k8s中 pause 容器作用

2023-07-21 16:41:13 浏览数 (1)

1 现象

在k8s中集群中每当我们创建一个pod,都会伴随着一个pause容器产生,因此我们在node节点上会有很多的pause容器。

例如:

代码语言:javascript复制
# master节点
[root@test-3-217 ~]# kubectl apply -f busybox.yaml
[root@test-3-217 ~]# kubectl get pod -o wide
NAME          READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
busybox-pod   1/1     Running   0          30m   10.244.2.45   test-3-219   <none>           <none>
# node节查看busybox容器
[root@test-3-219 ~]# docker ps -a
CONTAINER ID        IMAGE                                                                      COMMAND                  CREATED             STATUS                     PORTS               NAMES
0969c5802814        1c35c4412082                                                               "sleep 3600"             52 seconds ago      Up 50 seconds                                  k8s_busybox_busybox-pod_default_ec874d6b-9d08-4a16-8f48-e22fd8bfca0a_0
434df7bbc3fb        registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2              "/pause"                 53 seconds ago      Up 51 seconds                                  k8s_POD_busybox-p

由上可以看出,pause是一个容器,但不是pod,而且先于busybox容器产生,那么pause容器有什么作用呢?

在kubernetes中,pod是可以创建和管理的最小单元,由一个或多个相关联的容器组成。pod中的多个容器共享同一个network namespace,因此这些容器可以共享pod的IP和端口。

其中共享的network namespace就是通过pause容器实现的。

下面我们通过创建一个由nginx、ghost、busybox组成的pod来演示下。

2 pause功能演示 network namespace

2.1 创建 pod 资源

代码语言:javascript复制
# 配置文件
vim pause-test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pause-test
spec:
  containers:
  - name: busybox
    command:
      - sleep
      - "3600"
    image: busybox
    imagePullPolicy: IfNotPresent
  - name: ghost
    image: ghost:3.21
    imagePullPolicy: IfNotPresent
  - name: nginx
    image: nginx:1.9.1
    imagePullPolicy: IfNotPresent
  restartPolicy: Always
  
# 运行
kubectl apply -f pause-test.yaml
 
# 查看pod
[root@test-3-217 pause]# kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE     IP            NODE           NOMINATED NODE   READINESS GATES
pause-test   3/3     Running   3          3h11m   10.244.2.49   test-3-219   <none>           <none>

# 查看容器
[root@test-3-219 ~]# docker ps -a
CONTAINER ID        IMAGE                                                                      COMMAND                  CREATED             STATUS                      PORTS               NAMES
2d9d8566b53f        1c35c4412082                                                               "sleep 3600"             22 minutes ago      Up 22 minutes                                   k8s_busybox_pause-test_default_02e7dcb7-5aeb-477f-a50b-74ce1b0a7704_3
9d8ccf485b8f        94ec7e53edfc                                                               "nginx -g 'daemon of…"   3 hours ago         Up 3 hours                                      k8s_nginx_pause-test_default_02e7dcb7-5aeb-477f-a50b-74ce1b0a7704_0
faa2fb108ab3        db9598608d2e                                                               "docker-entrypoint.s…"   3 hours ago         Up 3 hours                                      k8s_ghost_pause-test_default_02e7dcb7-5aeb-477f-a50b-74ce1b0a7704_0
cbaab0586322        registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2              "/pause"                 3 hours ago         Up 3 hours                                      k8s_POD_pause-test_default_02e7dcb7-5aeb-477f-a50b-74ce1b0a7704_0

我们创建了一个名为pause-test的pod资源,由busybox、ghost、nginx三个容器组成,其中:

busybox作用是提供Linux基础命令,提供ps、netstat等基础调试命令;

ghost作用是一个博客系统,默认端口2368;

nginx作用是为博客提供反向代理,默认端口80; 以上可模拟构建一套基于共享网络的测试环境。

2.2 查看 pod 中容器网络

代码语言:javascript复制
[root@test-3-217 pause]# kubectl exec -it  pause-test -- /bin/sh
# 默认进入pod中第一个容器
Defaulting container name to busybox.
Use 'kubectl describe pod/pause-test -n default' to see all of the containers in this pod.
/ # netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:2368            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 3600
    6 root      0:00 /bin/sh
   12 root      0:00 ps aux

通过以上输出可以得出:

  • netstat命令我们可以看到nginx和ghost各自的启动端口,因此得出pod中network namespace是可以由不同容器共享的。
  • ps命令我们可以看出pid 为1 的进程是容器自身的ENTRYPOINT进程sleep 3600,而不是/pause。因此得出pod中pid namesapce 没有被容器所共享。

此时我们访问nginx的80端口:

代码语言:javascript复制
[root@uvmsvr-3-217 pause]# curl 10.244.2.49
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...省略....
</html>

由于默认的nginx镜像没有进行proxy配置,访问的默认页面。由于此时nginx和ghost能够通信,因此我们通过nginx进行代理。

2.3 nginx代理ghost

代码语言:javascript复制
# 进入nginx容器
[root@test-3-217 pause]# kubectl exec -it -c nginx pause-test -- /bin/sh
# cd /etc/nginx/conf.d
# 反向代理ghost
# cat > example.conf <<EOF
server {
    listen 80 default_server;
    server_name example.com www.example.com;
    location / {
        proxy_pass http://127.0.0.1:2368;
    }
}
EOF
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# nginx -s reload
2020/06/29 03:25:34 [notice] 15#15: signal process started

# 再次访问nginx
# 注意:由于没有设置service或ingress,只能使用内部ip调试
[root@test-3-217 pause]# curl 10.244.2.49
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />

    <title>Ghost</title>
    <meta name="HandheldFriendly" content="True" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
....省略....

此时访问nginx不是默认页,而是ghost的页面(由于使用内部ip,暂时无法在浏览器展示),即pod中多个容器是可以共享网络的。

如果上面的例子你已经明白,我们再来看看pause的定义吧。

3 pause容器定义

Pause容器 全称infrastucture container(又叫infra)基础容器,即它会在每个 Pod 里,额外起一个Infra container 小容器来共享整个 Pod 的 Network Namespace。

Infra container 是一个非常小的镜像,C语言写的、永远处于“暂停”状态的容器。基于Infra container 之后,其他所有容器都会通过 Join Namespace 的方式加入到 Infra container 的 Network Namespace 中。

而在网上的大部分文章则用以下解释

kubernetes中的pause容器主要为每个业务容器提供以下功能:

  • 在pod中担任Linux命名空间共享的基础;
  • 启用pid命名空间,开启init进程;

通过上文的实验pause提供了 network namespace 可以印证第一点“在pod中担任Linux命名空间共享的基础”,但是pid namespace并不是共享的,而是由各自容器ENTRYPOINT自行管理,这是为什么呢?

下面继续通过实例进行讲解。

4 pause功能演示pid namespace

4.1 新建 pod 资源

代码语言:javascript复制
apiVersion: v1
kind: Pod
metadata:
  name: pause-test2
spec:
  # 共享pid namespace
  shareProcessNamespace: true
  containers:
  - name: busybox
    command:
      - sleep
      - "3600"
    image: busybox
    imagePullPolicy: IfNotPresent
  - name: ghost
    image: ghost:3.21
    imagePullPolicy: IfNotPresent
  - name: nginx
    image: nginx:1.9.1
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

配置文件中我们新增了shareProcessNamespace: true 可以实现pid namespace在pod中容器共享。

4.2 进程查看

代码语言:javascript复制
# 进入新建的pod pause-test2
[root@test-3-217 pause]# kubectl exec -it pause-test2 -- /bin/sh
Defaulting container name to busybox.
Use 'kubectl describe pod/pause-test2 -n default' to see all of the containers in this pod.
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    6 root      0:00 sleep 3600
   12 1000      0:17 node current/index.js
   75 root      0:00 nginx: master process nginx -g daemon off;
   80 104       0:00 nginx: worker process
   86 root      0:00 /bin/sh
   91 root      0:00 ps aux

此时我们可以看到pid 为1的进程是/pause,nginx进程、ghost进程等都可以在busybox容器中看到,即pid namespace在pod中的容器间共享,其好处是便于进程间通信,类似linux操作系统,避免由于容器的异常终止导致僵尸进程。

但是在 Kubernetes 1.8 版本之前,默认是启用 PID namespace 共享的,除非使用 kubelet 标志 --docker-disable-shared-pid=true 禁用。然而在 Kubernetes 1.8 版本以后,情况刚好相反,默认情况下 kubelet 标志 --docker-disable-shared-pid=true,如果要开启,还要设置成 false。也可以给通过pod.spec.shareProcessNamespace 决定是否启用 PID namespace 共享。

至于为什么要关闭pid namespace共享?

因为当应用程序不会产生其他进程,而且僵尸进程带来的问题就可以忽略不计时,就用不到 PID namespace 的共享了。

5 pause生命周期

代码语言:javascript复制
# node节点停止pause容器
docker stop 9ebe5f09adfe
# 查看pod相关容器
[root@test-3-219 ~]# docker ps -a
CONTAINER ID        IMAGE                                                                      COMMAND                  CREATED             STATUS                        PORTS               NAMES
38be505f017a        94ec7e53edfc                                                               "nginx -g 'daemon of…"   23 seconds ago      Up 22 seconds                                     k8s_nginx_pause-test2_default_5c98d865-ab34-4ea2-a712-34ef5431864b_1
bdd98a7996de        db9598608d2e                                                               "docker-entrypoint.s…"   24 seconds ago      Up 23 seconds                                     k8s_ghost_pause-test2_default_5c98d865-ab34-4ea2-a712-34ef5431864b_1
b2ff89c04fee        1c35c4412082                                                               "sleep 3600"             24 seconds ago      Up 23 seconds                                     k8s_busybox_pause-test2_default_5c98d865-ab34-4ea2-a712-34ef5431864b_1
3d30657ff21e        registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2              "/pause"                 25 seconds ago      Up 24 seconds                                     k8s_POD_pause-test2_default_5c98d865-ab34-4ea2-a712-34ef5431864b_1
# pod生命周期,没有随pause的停止而停止
[root@test-3-217 pause]# kubectl get pod
NAME          READY   STATUS    RESTARTS   AGE
pause-test    3/3     Running   4          4h54m
pause-test2   3/3     Running   3          27m

由于pause容器作为基础容器,在pod内部第一个启动,并且提供namespace级别共享,因此pause生命周期决定了pod内部容器的生命周期。正如上面的实验,pause容器在node节点停止后,kubelet会重新拉起pause容器,此时pod内的容器都会重启,但pod的生命周期并没有随着pause容器的停止而重新计时。

文章参考:

https://www.bbsmax.com/A/VGzlQYmYJb/

https://www.ianlewis.org/en/almighty-pause-container

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

原创: 三页 木纳大叔爱运维

0 人点赞