POD内的容器之间的资源共享

概述

摘要:本文通过实践描述并验证了pod内容器如何实现网络、文件、PID、UTC、mount的共享。

pod实战之容器内资源共享与隔离

container容器之间的共享实战

从实际场景说起:有2个容器nginx与wordpress分别运行了紧密耦合且需要共享资源的应用程序。我们希望2两个容器共享网络命名空间,IPC 命名空间,PID 命名空间。

实现这个需求的可以使用2个解决方案:

解决方案一

  1. 先创建一个名为nginx的业务容器,根据docker的底层原理,linux内核中的namespaces组件会为nginx的容器创建独立与宿主的网络、IPC、PID、UTC命名空间。
  2. 再创建业务容器wordpress,同时将wordpress“加入”,属于nginx容器的命名空间。

在这里插入图片描述

该方案实现简单,但是存在一个问题就是,wordpress容器依赖nginx业务容器,一旦nginx容器fail,wordpress容器也将fail.

解决方案二

在这里插入图片描述

为了解决方案一存在的问题,我们可以利用pause容器来解决。pause容器不执行任何业务逻辑,仅仅是为了创建一个独立的命名空间而生,之后再将业务容器
“加入”到pause容器已经创建的命名空。具体步骤如下:

  1. 先创建一个容器:pause的容器,根据docker的底层原理,linux内核中的namespaces组件会为pause的容器创建独立于宿主的网络、IPC、PID、UTC命名空间。pause是一个特殊的容器,里面运行着一个非常简单的进程,它不执行任何功能,基本上是永远“睡觉”的。
  2. 创建业务容器nginx,同时将nginx”加入“,属于pause容器的命名空间。
  3. 再创建业务容器wordpress,同时将wordpress”加入“,属于pause容器的命名空间。

解决方案二的实践

root@ ubuntu1604:~# docker run -d --name pause   pause:3.1
3fd25a34f1b92e3799bbef61b13f88258ea9633b1ffef512e8e7d2f6b5fc199a

root@ ubuntu1604:~# docker  ps |grep pause
3fd25a34f1b9         pause:3.1   "/pause"                 26 seconds ago      Up 25 seconds                           pause
  • –name:指定 pause 容器的名字,pause
root@ ubuntu1604:~# docker run -d --name nginx --net=container:pause --ipc=container:pause --pid=container:pause --ipc=shareable   ubuntu1604
3d043d9a692cb8e3ed1e7f522c8222cc99d0e0c1a44b8b2ca0c4083c308f073f

root@ ubuntu1604:~# docker ps |grep nginx
3d043d9a692c         ubuntu1604   "/start.sh"              25 seconds ago      Up 24 seconds                           nginx
  • –net=container:pause:表示创建的容器与另一个容器共享网络命名空间。在这种情况下,容器 “nginx” 会与名为 “pause” 的容器共享网络命名空间,它们可以使用相同的网络配置和接口。
  • –ipc=container:pause:表示创建的容器与另一个容器共享 IPC 命名空间。IPC 命名空间允许容器之间进行进程间通信(Inter-Process Communication),在这里,容器 “nginx” 与名为 “pause” 的容器共享 IPC 命名空间。
  • –pid=container:pause:表示创建的容器与另一个容器共享 PID 命名空间。PID 命名空间允许容器查看和管理其他容器的进程。
  • –ipc=shareable:指示 IPC 命名空间是可共享的,以便其他容器也可以加入到这个共享命名空间中。
root@ ubuntu1604:~# docker run -d --name wordpress --net=container:pause --ipc=container:pause --pid=container:pause --ipc=shareable  ubuntu16.04
efaedd09438fdc2eb903cc2b57301088abf6cd6ee35fcc37f8d0b341802c28b5

  • 查看网络命名空间是否共享
root@ ubuntu1604:~# docker exec -it nginx  /bin/bash
root@3fd25a34f1b9:/work# 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
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:c0:a8:01:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.1.2/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever
root@3fd25a34f1b9:/work# ip route show
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.2


root@ ubuntu1604:~# docker exec -it wordpress  /bin/bash
root@3fd25a34f1b9:/work# 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
5: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:c0:a8:01:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.1.2/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever
root@3fd25a34f1b9:/work# ip route show
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.2

可以看到nginx与wordpress两个容器,IP地址和路由表是一样的,说明它们共用一个网络协议栈(网络命名空间)。

  • 查看PID命名空间是否共享
root@ ubuntu1604:~# docker exec -it nginx  ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0   1024     4 ?        Ss   17:26   0:00 /pause
root          6  0.0  0.0  19696  3160 ?        Ss   17:28   0:00 /bin/bash /sta
root         25  0.0  0.0  65512  3128 ?        Ss   17:28   0:00 /usr/sbin/sshd
root         34  0.0  0.0  27728  2748 ?        Ss   17:28   0:00 /usr/sbin/cron
root         39  0.0  0.0   6008   664 ?        S    17:28   0:00 sleep 600
root         40  0.0  0.0  19696  3368 ?        Ss   17:29   0:00 /bin/bash /sta
root         68  0.0  0.0  27728  2620 ?        Ss   17:29   0:00 /usr/sbin/cron
root         73  0.0  0.0   6008   668 ?        S    17:29   0:00 sleep 600
root        126  0.0  0.0  36084  3224 pts/0    Rs+  17:34   0:00 ps aux

root@ ubuntu1604:~# docker exec -it wordpress  ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0   1024     4 ?        Ss   17:26   0:00 /pause
root          6  0.0  0.0  19696  3160 ?        Ss   17:28   0:00 /bin/bash /sta
root         25  0.0  0.0  65512  3128 ?        Ss   17:28   0:00 /usr/sbin/sshd
root         34  0.0  0.0  27728  2748 ?        Ss   17:28   0:00 /usr/sbin/cron
root         39  0.0  0.0   6008   664 ?        S    17:28   0:00 sleep 600
root         40  0.0  0.0  19696  3368 ?        Ss   17:29   0:00 /bin/bash /sta
root         68  0.0  0.0  27728  2620 ?        Ss   17:29   0:00 /usr/sbin/cron
root         73  0.0  0.0   6008   668 ?        S    17:29   0:00 sleep 600
root        121  0.0  0.0  36084  3208 pts/0    Rs+  17:33   0:00 ps aux


可以看到nginx与wordpress两个容器,可以相互看到多方的进程pid。

  • 查看文件系统挂载是否共享
root@ ubuntu1604:~# docker exec -it nginx  df
Filesystem     1K-blocks     Used Available Use% Mounted on
overlay        309505024 38063364 258331752  13% /
tmpfs              65536        0     65536   0% /dev
tmpfs           16336452        0  16336452   0% /sys/fs/cgroup
/dev/vda1      309505024 38063364 258331752  13% /etc/hosts
shm                65536        0     65536   0% /dev/shm
tmpfs           16336452        0  16336452   0% /proc/acpi
tmpfs           16336452        0  16336452   0% /proc/scsi
tmpfs           16336452        0  16336452   0% /sys/firmware

root@ ubuntu1604:~# docker exec -it wordpress  df
Filesystem     1K-blocks     Used Available Use% Mounted on
overlay        309505024 38063460 258331656  13% /
tmpfs              65536        0     65536   0% /dev
tmpfs           16336452        0  16336452   0% /sys/fs/cgroup
/dev/vda1      309505024 38063460 258331656  13% /etc/hosts
shm                65536        0     65536   0% /dev/shm
tmpfs           16336452        0  16336452   0% /proc/acpi
tmpfs           16336452        0  16336452   0% /proc/scsi
tmpfs           16336452        0  16336452   0% /sys/firmware

可以看到nginx与wordpress两个容器,挂载的目录是一样的。

  • 查看UTC命名空间是否共享
root@ ubuntu1604:~# docker exec -it wordpress  hostname
3fd25a34f1b9
root@ ubuntu1604:~# docker exec -it nginx  hostname
3fd25a34f1b9

可以看到nginx与wordpress两个容器,挂载的主机名是一样的。

总结:

  • 方案二中,由于pause是不运行业务逻辑代码,永远处于”睡觉“状态。就可以"维护"一套独立的命名空间,再将业务容器加入pause的命名空间。

  • 细心的读者可能观察到,这套方案和pod就很类似,恩,没错。kubernetes就是利用pause容器+业务容器来实现一个POD的。

  • 其实pause除了实现 Pod 中多个容器的共享网络与资源隔离的功能之外,pause 容器也会负责管理容器之间的生命周期,保证在 Pod 删除与更新时,容器和资源可以被正确地释放。如果 Pod 中运行的所有其他容器都终止,则 pause 容器自动终止并删除。

    关于pause容器的具体描述后面再展开。

pod内容器之间的共享与隔离

我们知道kubernetes管理的最小单位是pod,而不是容器。一个pod中可以包括一个或多个容器。在实践中,通常一个pod中运行多个容器,将多个紧密耦合且需要共享资源的应用程序封装到一个pod.

实践中根据业务场景的不同,需要考虑pod中多个容器对共享与隔离的需求:

  1. pod内的多个容器,使用的网络是共享的,而且也是必须的。
  2. pod内的多个容器,对于文件系统是有共享的需求的,默认情况下容器之间对文件访问是隔离的。
  3. pod内的多个容器,对于pid也是有共享需求的,默认情况下容器的pid是隔离的,不能相关看到对方容器的pid。
  4. pod内的多个容器,对于hostname(UTC)也是有共享需求的,默认情况下容器的UTC是隔离的,容器有不同的hostname。
  5. pod需要和宿主共享PID,默认pod是无法看到宿主的PID,也是处于安全考虑,默认情况下pod无法与宿主共享PID命名空间。

pod内容器之间网络的共享

当Pod创建多个容器时,容器之间会通过namespace实现了隔离的,之间的网络是隔离的。Pod要解决内部容器之间网络通信的问题其实就要打破namespace的隔离。

那么Kubernetes是怎么解决两个容器之间通信的问题呢?

也即是容器之间看到的网络协议栈是一样的,在创建pod的时候会先创建infra container这个容器(也叫sandbox或pause容器),启动好之后然后再将实际创建的容器加入到infra container容器当中,这个infra容器实现的主要目的是维护了pod的网络,没有跑任何的业务逻辑,只是启动了一个容器罢了。其他容器的创建都让其连接至该容器的网络命名空间当中。这样一来其他容器看到的网络视图就是infra container的网络视图了。一个pod当中所有的容器看到的网络设备,网卡,ip,mac地址都看到的是同一个了,因为在一个网络命名空间。这样就解决了网络共享的问题。实际上pod的ip就是infra container的ip。(类似上面方案二的实践)

记住: 同一个pod内的所有容器共享一个协议栈。

pod内容器之间文件的共享

pod内的容器之间的文件系统,默认是相互隔离的。如果需要实现共享文件或目录,可以两个容器共享一个卷用于他们之间的通信。

root@ ubuntu1604:~# cat pod-blog.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: blog
  labels:
    app: blog
spec:
  restartPolicy: Always
  volumes:
  - name: shared-data
    emptyDir: {}
  containers:
  containers:
    - name: nginx
      volumeMounts:
      - name: shared-data
        mountPath: /sharedir
      image: ubuntu16.04
    - name: wordpress
      volumeMounts:
      - name: shared-data
        mountPath: /sharedir
      image: ubuntu16.04

在配置文件中,你可以看到 Pod 有一个共享卷,名为 shared-data

配置文件中的第一个容器运行了一个 nginx 服务器,第二个容器是运行 wordpress 服务器。他们共享卷的挂载路径是 /sharedir

先在第一个容器中共享的目录中创建一个文件/sharedir/blog.txt

root@ ubuntu1604:~# kubectl get pod -owide
NAME   READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
blog   2/2     Running   0          10s   192.168.26.100   10.234.12.77   <none>           <none>
root@ ubuntu1604:~# kubectl exec -it blog -c nginx -- bash
root@blog:/work# df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay         296G   84G  199G  30% /
tmpfs            64M     0   64M   0% /dev
tmpfs            16G     0   16G   0% /sys/fs/cgroup
/dev/vda1       296G   84G  199G  30% /sharedir
shm              64M     0   64M   0% /dev/shm
tmpfs            16G   12K   16G   1% /run/secrets/kubernetes.io/serviceaccount
root@blog:/work# echo "myblog" >>  /sharedir/blog.txt
root@blog:/work# cat /sharedir/blog.txt
myblog

第二个容器读取/sharedir/blog.txt的内容。

root@ ubuntu1604:~# kubectl exec -it blog -c wordpress -- cat /sharedir/blog.txt
myblog

pod内容器之间的PID的共享

POD内的容器之前,默认的PID是隔离的,无法相互看到或操控。但可以使用 Pod .spec 中的 shareProcessNamespace 字段可以启用进程命名空间共享。shareProcessNamespace的值默认为false,即容器之间不是共享进程命名空间的。调整shareProcessNamespace为true,可以实现容器之间共享进程命名空间

创建POD,指定shareProcessNamespace: true

root@ ubuntu1604:~# cat pod-blog.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: blog
  labels:
    app: blog
spec:
  ### 使用 pod.spec.shareProcessNamespace 控制Pod内容器之间的PID共享。shareProcessNamespace的值默认为false
  shareProcessNamespace: true
  restartPolicy: Always
  volumes:
  - name: shared-data
    emptyDir: {}
  containers:
  containers:
    - name: nginx
      volumeMounts:
      - name: shared-data
        mountPath: /sharedir
      image: ubuntu16.04
    - name: wordpress
      volumeMounts:
      - name: shared-data
        mountPath: /sharedir
      image: ubuntu16.04

观察2个业务容器观察到的PID是一样的。

root@ ubuntu1604:~# kubectl exec -it blog -c nginx --  ps  aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0   1024     4 ?        Ss   18:13   0:00 /pause
root          6  0.0  0.0  19708  3344 ?        Ss   18:13   0:00 /bin/bash /sta
root         25  0.0  0.0  65512  3080 ?        Ss   18:13   0:00 /usr/sbin/sshd
root         34  0.0  0.0  27728  2704 ?        Ss   18:13   0:00 /usr/sbin/cron
root         40  0.0  0.0  19708  3328 ?        Ss   18:13   0:00 /bin/bash /sta
root         68  0.0  0.0  27728  2700 ?        Ss   18:13   0:00 /usr/sbin/cron
root        102  0.0  0.0   6008   800 ?        S    18:23   0:00 sleep 600
root        103  0.0  0.0   6008   660 ?        S    18:23   0:00 sleep 600
root        119  0.0  0.0  36084  3216 pts/0    Rs+  18:28   0:00 ps aux
root@ ubuntu1604:~# kubectl exec -it blog -c wordpress  --  ps  aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0   1024     4 ?        Ss   18:13   0:00 /pause
root          6  0.0  0.0  19708  3344 ?        Ss   18:13   0:00 /bin/bash /sta
root         25  0.0  0.0  65512  3080 ?        Ss   18:13   0:00 /usr/sbin/sshd
root         34  0.0  0.0  27728  2704 ?        Ss   18:13   0:00 /usr/sbin/cron
root         40  0.0  0.0  19708  3328 ?        Ss   18:13   0:00 /bin/bash /sta
root         68  0.0  0.0  27728  2700 ?        Ss   18:13   0:00 /usr/sbin/cron
root        102  0.0  0.0   6008   800 ?        S    18:23   0:00 sleep 600
root        103  0.0  0.0   6008   660 ?        S    18:23   0:00 sleep 600
root        124  0.0  0.0  36084  3152 pts/0    Rs+  18:29   0:00 ps aux

注意:这里有一个隐含的信息,是pause, nginx,wordpress三个容器共享进程命名空间。PID 1是pause容器

pod内容器之间共享主机名

POD内的容器之前,默认的UTC是独立的,也就是容器的主机名都不通。但可以使用 Pod .spec 中的 hostname 实现UTC命名空间共享,也就是多个容器共用同样的主机名。

创建yaml文件pod-blog.yaml,添加spec.hostname: sharedhostname实现容器之间共用同样的主机名


---
apiVersion: v1
kind: Pod
metadata:
  name: blog
  labels:
    app: blog
spec:
  ### 使用 pod.spec.hostname 实现容器共用同一个主机名
  hostname: sharedhostname
  ### 使用 pod.spec.shareProcessNamespace 控制Pod内容器之间的PID共享。shareProcessNamespace的值默认为false
  shareProcessNamespace: true
  restartPolicy: Always
  volumes:
  - name: shared-data
    emptyDir: {}
  containers:
  containers:
    - name: nginx
      volumeMounts:
      - name: shared-data
        mountPath: /sharedir
      image:  ubuntu1604
    - name: wordpress
      volumeMounts:
      - name: shared-data
        mountPath: /sharedir
      image:  ubuntu1604
root@ ubuntu1604:~# kubectl exec -it blog -c nginx -- hostname
sharedhostname
root@ ubuntu1604:~# kubectl exec -it blog -c wordpress  -- hostname
sharedhostname

pod与宿主的共享网络命名空间

我们知道pod如果需要使用宿主的网络协议栈,可以使用hostNetwork: true来实现。 由于该场景非常有,所以本次实践略。

pod与宿主的进程命名空间

我们知道pod如果需要使用宿主的网络协议栈,可以使用hostNetwork: true来实现。 有时场景下一个管理性的Pod,也需要与宿主进程命名空间,即看到和控制宿主的进程。这时就可以使用hostPID: true来实现。

创建yaml文件指定hostPID: true

---
apiVersion: v1
kind: Pod
metadata:
  name: mgr
spec:
  restartPolicy: Always
  hostPID: true
  containers:
    - name: nginx
      image: ubuntu16.04

从容器中查看宿主的内核进程kworker

root@ ubuntu1604:~# kubectl exec -it mgr -- ps aux |grep worker |head
root          4  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/0:0H]
root         18  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/1:0H]
root         24  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/2:0H]
root         30  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/3:0H]
root         36  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/4:0H]
root         42  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/5:0H]
root         48  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/6:0H]
root         54  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/7:0H]
root         60  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/8:0H]
root         66  0.0  0.0      0     0 ?        I<   16:28   0:00 [kworker/9:0H]

参考文档

同 Pod 内的容器使用共享卷通信

在 Pod 中的容器之间共享进程命名空间

https://cloud.tencent.com/developer/article/2332162

https://blog.csdn.net/qq_34556414/article/details/110083541

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SRExianxian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值