Pod介绍
Kubernetes并不直接运行容器,而是使用一个抽象的资源对象来封装一个或多个容器,这个抽象就被称为 Pod,它也是 Kubernetes 的最小调度单元,在Kubernetes中,容器不称为我们之前在Docker中所谓的容器,而是被称为 Pod。同一个 Pod 中可以有多个容器并且同一个Pod中的多个容器共享网络名称和存储资源,这些容器可通过本地回环接口 lo 直接通信,但彼此之间又在 Mount、User、PID等名称空间上保持了隔离。尽管 Pod 中可以包含多个容器,但是作为最小调度单元,它应该尽可能的保持 “小”,所以通常一个Pod中只有一个主容器和其它辅助容器,辅助容器指的是(Filebeats、zabbix_agent客户端等)。
Pod存在的意义
Pod主要为亲密性的应用而存在,例如像Nginx+PHP架构,应用+辅助容器,Nginx+Filebeats等类型的容器。
亲密性应用场景:
-
两个应用之间发生文件交互,例如filebeats要读取nginx日志文件进行收集
-
两个应用需要通过127.0.0.1或者socket通信,例如nginx+php需要通过lo接口或者socket通信
-
两个应用需要发生频繁的调用
Pod的实现机制与设计模式
众所周知,容器之间是通过Namespace隔离的,Pod要想解决上述应用场景,那么就要让Pod里的容器之间高效共享,那么Pod之内的容器是如何进行网络共享的呢?
1.Pod之内的多个容器是怎么进行网络共享的呢?
kubernetes的解法是这样的:会在每个Pod里先启动一个infra container
小容器,然后让其他的容器连接进来这个网络命名空间,然后其他容器看到的网络试图就完全一样了,即网络设备、IP地址、Mac地址等,这就是解决网络共享问题。在Pod的IP地址就是infra container的IP地址。
-
1.k8s会在创建真正的业务容器钱在Pod中创建一个基础容器(
infra container
)的容器。 -
2.然后让后创建的业务容器连接到基础容器中,一个Pod中的其它所有业务容器共享基础容器的网络、IP地址、Mac地址等。
-
3.基础容器的IP地址就是Pod的IP地址。
-
4.Pod启动的时候,无论Pod中有几个容器,都会创建一个基础容器(
infra container
),这个基础容器使用的是pause
镜像,容器名称也被叫做pause
,这个容器非常小,主要取决于它的镜像docker image
只有几百kb, pause镜像使用汇编语言编写。
测试网络
我们在一个Pod中启动nginx和centos容器,然后在centos中通过lo接口访问nginx的80端口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
cat nginx_network_pod.yaml apiVersion: v1 kind: Pod metadata: name: nginx-network-pod spec: containers: - name: nginx-network image: nginx:latest imagePullPolicy: IfNotPresent - name: centos-network image: centos:latest imagePullPolicy: IfNotPresent command: [ "/bin/bash", "-ce", "tail -f /dev/null" ] #创建pod资源对象 kubectl apply -f manifests/pod/nginx_network_pod.yaml #查看pod被调度到了哪台Node k8sops@k8s-master01:~$ kubectl get pods -o wide | grep nginx-network-pod nginx-network-pod 2/2 Running 0 53s 10.244.3.34 k8s-node01 <none> <none> |
pod被调度到了node1上,我们去node上可以查看由k8s启动的容器,有nginx-network和centos-network容器之外,还有基础容器infra container
1 2 3 4 5 6 7 |
root@k8s-node01:/# docker ps | grep nginx-network d3fea735ef5a 470671670cac "/bin/bash -ce 'tail…" 2 minutes ago Up 2 minutes k8s_centos-network_nginx-network-pod_default_c3acfee7-b262-4908-b083-67c5a4e50479_0 71f0554b5b6a 602e111c06b6 "nginx -g 'daemon of…" 2 minutes ago Up 2 minutes k8s_nginx-network_nginx-network-pod_default_c3acfee7-b262-4908-b083-67c5a4e50479_0 fb80158ec9ea registry.aliyuncs.com/google_containers/pause:3.2 "/pause" 2 minutes ago Up 2 minutes k8s_POD_nginx-network-pod_default_c3acfee7-b262-4908-b083-67c5a4e50479_0 #基础容器基于pause镜像启动,pause镜像只有683k root@k8s-node01:/# docker images | grep pause registry.aliyuncs.com/google_containers/pause 3.2 80d28bedfe5d 2 months ago 683kB |
在master节点上进入centos容器,然后通过lo接口访问nginx来进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
kubectl exec -it pods/nginx-network-pod -c centos-network -- /bin/bash #通过命令可以看到是监听着nginx的网络端口 [root@nginx-network-pod /]# ss -anplt State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 0.0.0.0:80 0.0.0.0:* #但是他们容器之前又隔离PID,所以我们pa aux看到的父进程是我们在yaml语法中定义的命令 [root@nginx-network-pod /]# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 23028 1396 ? Ss 05:34 0:00 /usr/bin/coreutils --coreutils-prog-shebang=tail /usr/bin/tail -f /dev/null root 8 0.1 0.0 12028 3264 pts/0 Ss 05:37 0:00 /bin/bash root 24 0.0 0.0 43960 3400 pts/0 R+ 05:37 0:00 ps aux #在此容器中通过lo接口访问nginx的服务 [root@nginx-network-pod /]# curl http://127.0.0.1 -I HTTP/1.1 200 OK Server: nginx/1.17.10 Date: Wed, 13 May 2020 05:37:28 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT Connection: keep-alive ETag: "5e95c66e-264" Accept-Ranges: bytes #查看本容器系统版本,确认此容器是centos容器而不是nginx容器 [root@nginx-network-pod /]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) #确认IP,查看IP是否与Pod中的pause容器进行共享网络 [root@nginx-network-pod /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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 3: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default link/ether e2:3f:d5:97:57:7d brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.244.3.34/24 scope global eth0 valid_lft forever preferred_lft forever #退出容器通过Pod IP访问Nginx服务 [root@nginx-network-pod /]# exit exit k8sops@k8s-master01:~$ curl http://10.244.3.34 -I HTTP/1.1 200 OK Server: nginx/1.17.10 Date: Wed, 13 May 2020 05:40:47 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT Connection: keep-alive ETag: "5e95c66e-264" Accept-Ranges: bytes |
2.容器之间共享存储
一个Pod中有两个容器,一个是nginx,另一个是centos容器,那么centos容器就需要读取nginx的日志文件,这个时候就需要让logstash容器读取到nginx容器的日志文件。k8s通过volume将nginx日志文件挂载出来,在本地宿主机生成一个目录,然后centos容器再将挂载出来的日志目录挂载到它自己的容器中,这样就实现了两个容器共享一个文件。
通过一个yaml配置清单实现一个pod中多容器
写一个yaml配置清单并观察这两个容器的网络和存储是否像上面描述的一样。
下面清单中启动了两个容器,分别是nginx和centos容器,nginx容器循环每个一秒往/data/hello文件中写入1-100个数字,写到100个数字即停止,然后由Pod默认的重启策略将Nginx容器重启,重启后再次从1写入到100,以此循环,并且nginx容器挂载了名称为data的卷,挂载到/data目录。
centos容器也挂载了名称为data的卷,并且挂载到了/data下,同时指定命令动态查看 /data/hello 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
apiVersion: v1 kind: Pod metadata: name: nginx-volume-pod spec: containers: - name: nginx-volume image: nginx:latest imagePullPolicy: IfNotPresent command: [ "/bin/bash", "-ce", "for i in {1..100};do echo $i >> /data/hello;sleep 1;done" ] volumeMounts: - name: data mountPath: /data - name: centos-volume image: centos:latest imagePullPolicy: IfNotPresent command: [ "/bin/bash", "-ce", "tail -f /data/hello" ] volumeMounts: - name: data mountPath: /data volumes: - name: data emptyDir: {} #name:data:指定了共享卷名称 #emptyDir: {}:在本地宿主机的路径,如果写为这样,则在相应的node节点上的/var/lib/kubectl/pods下创建相对应的挂载目录 #创建Pod资源 kubectl apply -f nginx-volume-pod.yaml #查看创建的pod被调度到哪台节点 kubectl get pods -n default -o wide | grep nginx-volume-pod nginx-volume-pod 2/2 Running 0 98s 10.244.3.36 k8s-node01 <none> <none> |
查看centos-volume容器的日志可以看到正在动态查看我们指定的命令
1 2 3 4 5 6 7 8 9 |
#进入nginx-volume容器查看 /data/ 目录是否挂载 k8sops@k8s-master01:~$ kubectl exec -it pods/nginx-volume-pod -c nginx-volume -- /bin/bash root@nginx-volume-pod:/# ls -lrth /data/hello -rw-r--r-- 1 root root 761 May 13 05:52 /data/hello #进入centos-volume容器查看 /data/ 目录是否挂载 k8sops@k8s-master01:~$ kubectl exec -it pods/nginx-volume-pod -c centos-volume -- /bin/bash [root@nginx-volume-pod /]# ls /data/hello -lrth -rw-r--r-- 1 root root 818 May 13 05:53 /data/hello |
我们在宿主机上可以找到容器中挂载的目录及在挂载目录中写入的文件
在Pod运行的Node主机上,进入 /var/lib/kubectl/pods/目录下,然后使用docker ps 命令查看容器生成的ID,通过ID在当前目录下进入后即可找到挂载的目录,如下图所示: