k8s和docker有些不同,docker是以容器为单位,而k8s是以pod为单位进行调度。下面一个图说明问题:
从外观上看,一个pod里面可能包含一组容器,它们组成一个整体的pod。
pod的特性
资料上是这么说:如果在 Pod 中运行多个容器,那么多个容器间是共享相同的 Pod 环境的。
共享环境中包括了 IPC 命名空间,共享的内存,共享的磁盘、网络以及其他资源等。举一个具体的例子,运行在相同 Pod 中的所有容器都有相同的 IP 地址(Pod 的 IP 地址)。
这个听起来很神奇,pod内部的容器竟然IP地址相同,下面我们准备用实验来验证。
实验准备的镜像:busybox
busybox是一个工具镜像,它里面包含各种命令行工具,你可以把它想像成是一个带有各种工具的mini linux系统。我们想实现的是下面的拓扑结构:
小人表示我们,我们通过sh进到busybox内部,然后执行ip命令,就可以查看容器的网络。需要说下,在研究k8s的时候,我们应该先熟悉docker的相关操作,如果不熟悉可以尽快看书熟悉。
给k8s server发命令
拓扑结构清楚之后,我们接下来就给k8s发命令,也就是给它发送配置文件,如下:
apiVersion: v1
kind: Pod
metadata:
name: simple-busybox-pod
spec:
containers:
# 第一个busybox容器,启动后休眠
- name: busybox-1
image: busybox:1.35
command: ["sleep", "infinity"] # 保持容器运行不退出
# 第二个busybox容器,启动后休眠
- name: busybox-2
image: busybox:1.35
command: ["sleep", "infinity"] # 保持容器运行不退出
文件命名为:pod-busybox-test.yml,名字可以任意。
然后,我们通过kubectl发送命令:
kubectl apply -f pod-busybox-test.yml
kubectl apply的意思就是应用、部署等的意思,那么连起来就是:把pod-busybox-test.yml这个文件发给api server,然后让它执行。
为什么要让容器休眠?
容器有个特性,就是如果当前没有任何运行的进程,这个容器就自己退出。在实验中,我们不能让容器退出,因此让它休眠。
进入pod
再看下我们的网络拓扑结构:
master节点收到命令,也就是第一节课称为”纸“的东西之后,它马上就执行了,然后创建一个pod,但是我们看到集群有两个node节点,因此它就随机的在某个机器上创建。
查看pod
pod生成之后,我们想查看一下集群里面有多少个pod,就好比你是一家水果店老板,想盘点下店里还有多少个苹果。因此,查询是k8s里面非常频繁的动作,命令如下:
kubectl get pods
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
simple-busybox-pod 2/2 Running 0 28s
--------------------------------
我们看到创建的pod,它的NAME和配置文件中的name一样。这个名字很重要,我们需要它来引用这个pod进行各种操作。
进入pod的某个容器
命令:
kubectl exec -it \
simple-busybox-pod -c busybox-1 \
-- sh
这个命令我们分段解释一下:
kubectl exec:它和docker exec很相似,表示在容器内部执行命令。
-it:表示打开输入和分配一个伪终端。这个地方在后面详细解释。
simply-busybox-pod:表示pod名。
-c busybox-1:表示进入哪个容器。
-- sh:表示要执行的命令。
全部连起来就是:进入simple-busybox-pod内的busybox-1容器内,然后执行sh命令。
-it的解释
-it是一个比较绕的命令,我写下我的理解:
在C语言编程中,书本是这么说的,当一个进程打开后默认会打开三个文件描述符,输入,输出和错误输出。但是在容器中有点不同,当打开进程时,默认输入不是打开的,我在图中用键盘表示输入,也就是说一开始那根线是断的,为什么这样呢?一种说法是为了安全。
sh进程运行之后一看发现输入都没了,那我还傻等啥呢,命令都输不进来了,我也关闭算了。所以如果不打开输入,sh一会就关闭了,这就是-i的作用。
第二,为了让sh更好的完整的工作,我们专门还给它配一个伪终端。那么有的同学会问,我不分配又咋样?也没有问题,这样就是共享一个终端。打个比方说,你和同桌本来是一人一个桌子的,现在两个人共用一张桌子,那么同桌的动作可能就会干扰你的动作,在终端上的表现就是输出的东西混在一起。所以为了相互不打扰,就一人独占一个桌子,这就是分配一个伪终端的作用。
总结一下:sleep将容器休眠,然后再启动一个sh进程,让它输入畅通,再给它分配一个终端,这样准备工作就完成了。
执行ip命令
进入终端后,输入命令:
[root@k8s-master ~]# kubectl exec -it simple-busybox-pod -c busybox-1 -- sh
/ # ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1480 qdisc noqueue
link/ether 9e:84:35:cc:28:ea brd ff:ff:ff:ff:ff:ff
#IP地址
inet 10.244.169.140/32 brd 10.244.169.140 scope global eth0
valid_lft forever preferred_lft forever
输入exit退出,接着按着同样的方法,我们进入busybox-2容器,执行结果如下:
[root@k8s-master ~]# kubectl exec -it simple-busybox-pod -c busybox-2 -- sh
/ # ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1480 qdisc noqueue
link/ether 9e:84:35:cc:28:ea brd ff:ff:ff:ff:ff:ff
#IP地址
inet 10.244.169.140/32 brd 10.244.169.140 scope global eth0
valid_lft forever preferred_lft forever
可以看到,两个容器的IP地址确实相同。
总结
这篇内容比较长,主要说明了下面的问题
- 部署一个pod,且该pod内部有两个容器。
- 验证pod的一个结论:pod内部的容器共享pod环境,比如具有相同的IP地址。