1. Pod 容器分类
pod容器主要分为3类:
-
pause 基础容器
-
init容器
-
应用容器
2. pause 基础容器
2.1 概述
pause容器又称为infra容器,全称infrastructure container,pause容器与pod是一一对应的,每个Pod里运行着一个特殊的被称之为Pause的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷,使其之间通信和数据交换更为高效,在设计时可以充分利用这一特性将一组密切相关的服务进程放入同一个Pod中。同一个Pod里的容器之间仅需通过localhost就能互相通信。pause容器主要为每个业务容器提供以下功能:
- PID命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID。
- 网络命名空间:Pod中的多个容器能够访问同一个IP和端口范围。
- IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信。
- UTS命名空间:Pod中的多个容器共享一个主机名;Volumes(共享存储卷):
- Pod中的各个容器可以访问在Pod级别定义的Volum
2.2 镜像部署
more /etc/kubernetes/kubelet······--pod-infra-container-image=hub.test.tech/library/pod-infrastructure:latest"······
2.2.1 部署案例
1)部署在节点上运行一个pause容器
docker run -d --name pause -p 8880:80 --ipc=host registry.cn-hangzhou.aliyuncs.com/google_containers/pause-amd64:3.1
2)运行一个nginx容器
docker run -d --name nginx --net=container:pause --pid=container:pause --ipc=container:pause nginx
3)运行一个ghost应用容器
docker run -d --name ghost --net=container:pause --ipc=container:pause --pid=container:pause ghost
pause容器将内部的80端口映射到宿主机的8880端口,pause容器在宿主机上设置好了网络namespace后,nginx容器加入到该网络namespace中,可以看到nginx容器启动的时候指定了--net=container:pause,ghost容器同样加入到了该网络namespace中,这样三个容器就共享了网络,互相之间就可以使用localhost直接通信,--ipc=contianer:pause --pid=container:pause就是三个容器处于同一个namespace中,init进程为pause,进入到ghost容器中查看进程情况。
root@weizhibiao:~# docker exec -it ghost bash
root@cfa367869c60:/var/lib/ghost# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 13:12 ? 00:00:00 /pause
root 756 0 0 13:37 ? 00:00:00 nginx: master process nginx -g daemon off;
101 785 756 0 13:37 ? 00:00:00 nginx: worker process
node 786 0 2 13:37 ? 00:00:08 node current/index.js
root 1181 0 0 13:41 pts/0 00:00:00 bash
root 1495 1181 0 13:42 pts/0 00:00:00 ps -ef
root@cfa367869c60:/var/lib/ghost#
在ghost容器中同时可以看到pause和nginx容器的进程,并且pause容器的PID是1。而在kubernetes中容器的PID=1的进程即为容器本身的业务进程。
3. init容器
3.1 概述
Init 容器 必须在 应用程序容器 启动之前运行完成,如果有多个 Init 容器,是串行启动。而应用程序容器是并行运行的,所以 Init容器 能够提供了一种简单的阻塞或延迟应用容器的启动的方法。
Init 容器与普通的容器非常像,除了以下两点:
- Init 容器总是运行到成功完成为止
- 每个Init 容器都必须在下一个 Init 容器启动之前成功完成
如果 Pod的 Init 容器失败,k8s 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod对应的重启策略(restartPolicy)为 Never,它不会重新启动。
init 容器和 pause 容器有相同点,也有不同点
相同点在于:它们都有固定用途,是专用的特殊容器
不同点在于: init容器是用户级的容器,它是由用户来定义的,而 pause 容器是系统级容器,它不是由用户定义的。
init 容器会在应用(业务)容器启动之前运行,用来包含一些应用镜像中不存在的实用工具或安装脚本。
3.2 特别说明
- 在Pod启动过程中,Init容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出。
- 如果由于运行时或失败退出,将导致容器启动失败,它会根据Podl的restartPolicy指定的策略进行重试。然而,如果Pod的restartPolicy设置为Always,Init容器失败时会使用RestartPolicy策略。
- 在所有的Init容器没有成功之前,Pod将不会变成Ready状态。Init容器的端口将不会在service中进行聚集。正在初始化中的Pod处于Pending状态,但应该会将Initializing状态设置为true。
- 如果Pod重启,所有Init容器必须重新执行。
- 对Init容器spec的修改被限制在容器image字段,修改其他字段都不会生效。更改Init容器的image字段,等价于重启该Pod。
- Init容器具有应用容器的所有字段。除了readinessProbe,因为Tnit容器无法定义不同于完成(completion)的就绪(readiness)之外的其他状态。这会在验证过程中强制执行。
- 在Pod中的每个app和Init容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误.
3.3 init 容器的运行机制
- init 容器必须先于 应用容器启动
- 仅当 init 容器完成后,才能运行应用容器
- 一个 Pod 允许有多个 init 容器,做不同的初始化任务
当一个 Pod 有多个 init 容器时,这些 init 容器是顺序运行的,一个 init 容器完成之后,才会运行一个 init 容器。
在执行kubectl get pod时加一个 -w
参数,就能看到 Pod 状态的变化过程。
在正常情况下(默认 Pod 的 restartPolicy 为 Never),只要有一个 init 容器运行失败,整个 Pod 便会不停地重启,直到 init 容器全部运行完成为止。
而只要一个 Pod 重启,不管init 容器之前有没有执行过,所有的 init 容器都要重新执行一遍。
3.4 init 容器与应用容器的不同
1)定义位置不同。
应用容器定义在 Pod.Spec.Containers,是必填字段,而 init 是定义在 Pod.Spec.initContainers 中,是可选字段。
2)部分配置不同。
init 容器没有 Lifecycle actions, Readiness probes, Liveness probes 和 Startup probes,而这些应用容器都有。
另外,虽然 init 容器与应用容器是两个类别的容器,但由于属于同一个 Pod ,因此容器的名字,是不能重复的。
3.5 init 容器的资源问题
当一个 Pod 只有应用容器时,那么在 kube-scheduler 调度该 Pod 时,会将所有的应用容器的 requests/limits 资源进行相加,得到一个requests/limits 的总量。然后用计算得出的总量和node 上的可用资源进行对比,若 node 上的资源充足,则允许调度过去,反之则不允许。
而当有了 init 容器后,情况会稍微复杂一点,由于 init 容器会先于应用容器运行,只有当 init 运行成功并且退出后,应用容器才会运行,因此为了保证所有的容器(不仅包括应用容器,还包括 init 容器)的运行,pod 的资源总量的计算公式如下
max(应用容器请求资源之和,max(所有的 init 容器请求资源))
3.6 init 容器的应用场景
为应用启动和运行提供基础环境。
4. 业务容器(Maincontainer)
业务运行容器,并行启动,其他与正常环境无异。
5. 总结
- Pod是 k8s 最小的运行单元,一个pod至少需要包含两个容器:1个基础容器(pause),应用容器(1个或者多个)。
- pod 里的容器会共享net , uts,ipc,namespace等网络资源。