一些关于pod的表述很专业,例如
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元
pod是kubernetes项目中的最小API对象
pod是kubernetes项目的原子调度单位
官方描述:https://kubernetes.io/zh/docs/concepts/workloads/pods/
2. 为什么需要pod对于这些对pod概念的总结大多殊路同归。
在理解概念前不妨先想一个问题:
明明有了容器,为什么还需要pod?
最质朴的回答往往是:
为了解决容器不足,或者说容器无法满足需求。
确实是这样,先分析一下容器的本质:
namespace做隔离
Cgroup做限制
rootfs做文件系统
三者相辅相成组成容器基本模型
但是,宏观的来说,容器的本质是系统中的一个进程。只不过这个进程启动时被附加了以上等等一下特殊的属性。
所谓容器只是一个恰当的说法。
就如系统中的大多数进程来说,不是单个进程独自工作,而是以“进程组”的方式“原则性”的组织在一起,互相协作,完成复杂任务。当然,它们之间也会共享一些资源,例如pid,namespace,存储等等。
在实际开发和运维中也是随处可见的这种问题,应用之间有深切的联系和依赖。
比如说,我要将一个应用容器化,这个应用由负责各个功能的5个进程组成,这时候,问题来了。
正是容器的局限性:单进程模型
单进程不是指容器中只能运行一个进程,而是容器无法去管理多个进程
例如,容器中有pid=1的进程,还有一个pid=5的进程,当这个pid=5的进程异常退出时,后续的垃圾回收等处理工作又由谁去做呢?
所以,这个应用的5个模块就必须分别制成5个容器,而且必须在同一个机器上运行。
随之而来的又是一个问题:
也就是容器调度问题,例如有两个容器调度节点node1和node2,可用内存分别为5G和4.5G,
每个容器分1G内存。由于5个容器必须在一台机器,正常全部调度到node1刚刚好,没有任何问题。
但是,因为是以容器为单位调度,有这样一些特殊情况。当前4个容器被调度到node2上时,空间只有0.5G,不足以运行最后一个容器,它有只能在node1运行,这就是以容器为调度单位的缺点。
当然也有解决方案:如Mesos中的资源囤积(resource hoarding),也就是所有调度任务都到达了才进行调度,也有谷歌Omega论文提出乐观调度,就是先不管冲突,而是在冲突之后通过一系列回滚机制解决冲突。
但这些都没有很完善的解决容器调度问题,但是在kubernetes中,这些问题都迎刃而解。
因为不在按照传统思维的将容器作为调度单位
kubernetes中的项目调度器是统一按照pod的资源需求做调度计算
也就是开始总结的那句话: pod是kubernetes项目的原子调度单位
3. pod结构如图所示,一个pod包含了两类容器:
- 用户容器
- Pause容器,也常常被称为“根容器”(貌似老版本叫做infra容器)
用户容器好理解,但是Pause容器,也就是根容器,他是做什么用的呢?
pause容器主要为每个用户容器提供以下功能:
① PID命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID。
② 网络命名空间:Pod中的多个容器能够访问同一个IP和端口范围。
③ IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信。
④ UTS命名空间:Pod中的多个容器共享一个主机名;Volumes(共享存储卷):
⑤ Pod中的各个容器可以访问在Pod级别定义的Volumes。
4. 容器设计模式考虑这样一个问题,容器见的关系是一成不变的吗?
举一些例子:
- 在pod中的一些容器的启动,必须依赖某一个正在运行的容器,也就是说这个容器必须比其他容器先启动
- 在pod中的容器必须同时协作,也就是说所有容器必须并行执行
- 一个pod需要给外部的其他pod提供接口
- 外部访问pod时,又怎样确保响应报文的一致性
- ..........
常见容器设计模式:
Init(初始化)容器
Sidecar(边车)容器
Adapter(适配器)容器
Ambassador(外交官)容器
关于容器设计模式可以参考论文:https://www.usenix.org/conference/hotcloud16/workshop-program/presentation/burns
5. pod实现原理一定要明白一点:pod只是一个逻辑上的概念
因为kubernetes真正处理的还是宿主机操作系统上容器的Namespace和Cgroup,也就是说没有所谓的pod边界或隔离环境。
所以说,pod就是一组共享了某些资源的容器
在一个pod中所有容器是共享一个Network Namespace
的,根据声明的不同来实现不同的资源共享
但是容器间的复杂关系在容器上难以解决,所以kubernetes项目里,pod的实现借用了一个中间容器,也就是常常说的根容器(也叫pause容器或infra容器,现在好像都统称pause容器,infra容器已经不再使用)。
在pod中,根容器永远是第一个创建的容器,用户后面定义的容器会加入进pod的Network Namespace
,从而在视图上容器都在pod里。
不妨在k8s中看看这个容器镜像:
[root@master ~]# docker images | grep pause
registry.aliyuncs.com/google_containers/pause 3.2 80d28bedfe5d 15 months ago 683kB
#当然,主机上有多少个pod就能docker ps 过滤看到多少pause容器
pause镜像大小只有683k,它是由汇编语言写的镜像
在一个pod中的容器,他们的Namespace文件,是一样的
也就意味着:
- pod内的容器可以使用localhost进行通信
- 根容器能看到的网络资源,其他容器都能看到,也就是pod的网络资源和pod内的容器共享
- 一个pod有一个ip地址,和pod对应的Network namespace的ip一致
- pod的生命周期只与根容器有关,与pod内的容器无关
- 从pod里的容器的视角来说,它们的流量进出可以看做是通过根容器完成的