深入Pod原理

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端口

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

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来进行测试

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 文件

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容器的日志可以看到正在动态查看我们指定的命令

#进入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在当前目录下进入后即可找到挂载的目录,如下图所示:







「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论