在 Kubernetes 中,最小的管理元素不是一个个独立的容器,而是 Pod 是最小的,管理,创建,计划的最小单元。
什么是 Pod
一个 Pod(就像一群鲸鱼,或者一个豌豆夹)相当于一个共享 context 的配置组,在同一个 context 下,应用可能还会有独立的 cgroup 隔离机制,一个 Pod 是一个容器环境下的 “逻辑主机”,它可能包含一个或者多个紧密相连的应用,这些应用可能是在同一个物理主机或虚拟机上。
Pod 的 context 可以理解成多个 linux 命名空间的联合
- PID 命名空间(同一个 Pod 中应用可以看到其它进程)
- 网络 命名空间(同一个 Pod 的中的应用对相同的 IP 地址和端口有权限)
- IPC 命名空间(同一个 Pod 中的应用可以通过 VPC 或者 POSIX 进行通信)
- UTS 命名空间(同一个 Pod 中的应用共享一个主机名称)
同一个 Pod 中的应用可以共享磁盘,磁盘是 Pod 级的,应用可以通过文件系统调用,额外的,一个 Pod 可能会定义顶级的 cgroup 隔离,这样的话绑定到任何一个应用(好吧,这句是在没怎么看懂,就是说 Pod,应用,隔离)
由于 docker 的架构,一个 Pod 是由多个相关的并且共享磁盘的容器组成,Pid 的命名空间共享还没有应用到 Docker 中
与相互独立的容器一样,Pod 是一种相对短暂的存在,而不是持久存在的,正如我们在 Pod 的生命周期中提到的,Pod 被安排到结点上,并且保持在这个节点上直到被终止(根据重启的设定)或者被删除,当一个节点死掉之后,上面的所有 Pod 均会被删除。特殊的 Pod 永远不会被转移到的其他的节点,作为替代,他们必须被 replace.
Pod 的发展
资源的共享及通信
Pod 使 Pod 内的数据共享及通信变得容易
Pod 的中的应用均使用相同的网络命名空间及端口,并且可以通过 localhost 发现并沟通其他应用,每个 Pod 都有一个扁平化的网络命名空间下 IP 地址,它是 Pod 可以和其他的物理机及其他的容器进行无障碍通信,(The hostname is set to the pod’s Name for the application containers within the pod)主机名被设置为 Pod 的名称(这个没翻译出来…)
除了定义了在 Pod 中运行的应用之外,Pod 还定义了一系列的共享的磁盘,磁盘让这些数据在容器重启的时候不回丢失并且可以将这些数据在 Pod 中的应用进行共享
管理
Pod 通过提供一个高层次抽象而不是底层的接口简化了应用的部署及管理,Pod 作为最小的部署及管理单位,位置管理,拷贝复制,资源共享,依赖关系都是自动处理的。(fate sharing 估计就说什么时候该死了,什么时候该新增一个了…)
Pod 的使用
Pod 可以作为垂直应用整合的载体,但是它的主要特点是支持同地协作,同地管理程序,例如:
- 内容管理系统,文件和数据加载,本地缓存等等
- 日志和检查点备份,压缩,循环,快照等等
- 数据交换监控,日志追踪,日志记录和监控适配器,以及事件发布等等
- 代理,网桥,适配器
- 控制,管理,配置,更新
总体来说,独立的 Pod 不会去加载多个相同的应用实例
考虑过的其他方案
为什么不直接在一个容器上运行所有的应用?
- 透明,Pod 中的容器对基础设施可见使的基础设施可以给容器提供服务,例如线程管理和资源监控,这为用户提供很多便利
- 解耦软件依赖关系, 独立的容器可以独立的进行重建和重新发布,Kubernetes 甚至会在将来支持独立容器的实时更新
- 易用,用户不需要运行自己的线程管理器,也不需要关心程序的信号以及异常结束码等
- 高效,因为基础设施承载了更多的责任,所以容器可以更加高效
为什么不支持容器的协同调度?
容器的协同调度可以提供,但是它不具备 Pod 的大多数优点,比如资源共享,IPC,选择机制,简单管理等
Pod 的持久性
Pod 并不是被设计成一个持久化的资源,它不会在调度失败,节点崩溃,或者其他回收中(比如因为资源的缺乏,或者其他的维护中)幸存下来
总体来说,用户并应该直接的去创建 Pod,用户因该一直使用 controller(replication controller), 即使是一个节点的情况,这是因为 controller 提供了集群范围内的自我修复,以及复制还有展示管理
集群 API 的使用是用户的主要使用方式,这是相对普遍的在如下云管理平台中( Borg, Marathon, Aurora, and Tupperware.)
Pod 的直接暴露是如下操作变得更容器
- 调度和管理的易用性
- 在没有代理的情况下通过 API 可以对 Pod 进行操作
- Pod 的生命周期与管理器的生命周期的分离
- 解偶控制器和服务,后段管理器仅仅监控 Pod
- 划分清楚了 Kubelet 级别的功能与云平台级别的功能,kubelet 实际上是一个 Pod 管理器
- 高可用,当发生一些删除或者维护的过程时,Pod 会自动的在他们被终止之前创建新的替代
目前对于宠物的最佳实践是,创建一个副本等于 1 和有对应 service 的一个 replication 控制器。如果你觉得这太麻烦,请在这里留下你的意见。
容器的终止
因为 pod 代表着一个集群中节点上运行的进程,让这些进程不再被需要,优雅的退出是很重要的(与粗暴的用一个 KILL 信号去结束,让应用没有机会进行清理操作)。用户应该能请求删除,并且在室进程终止的情况下能知道,而且也能保证删除最终完成。当一个用户请求删除 pod,系统记录想要的优雅退出时间段,在这之前 Pod 不允许被强制的杀死,TERM 信号会发送给容器主要的进程。一旦优雅退出的期限过了,KILL 信号会送到这些进程,pod 会从 API 服务器其中被删除。如果在等待进程结束的时候,Kubelet 或者容器管理器重启了,结束的过程会带着完整的优雅退出时间段进行重试。
一个示例流程:
- 用户发送一个命令来删除 Pod,默认的优雅退出时间是 30 秒
- API 服务器中的 Pod 更新时间,超过该时间 Pod 被认为死亡
- 在客户端命令的的里面,Pod 显示为”Terminating(退出中)” 的状态
- (与第 3 同时)当 Kubelet 看到 Pod 标记为退出中的时候,因为第 2 步中时间已经设置了,它开始 pod 关闭的流程
- 如果该 Pod 定义了一个停止前的钩子,其会在 pod 内部被调用。如果钩子在优雅退出时间段超时仍然在运行,第二步会意一个很小的优雅时间断被调用
- 进程被发送 TERM 的信号
- (与第三步同时进行)Pod 从 service 的列表中被删除,不在被认为是运行着的 pod 的一部分。缓慢关闭的 pod 可以继续对外服务,当负载均衡器将他们轮流移除。
- 当优雅退出时间超时了,任何 pod 中正在运行的进程会被发送 SIGKILL 信号被杀死。
- Kubelet 会完成 pod 的删除,将优雅退出的时间设置为 0(表示立即删除)。pod 从 API 中删除,不在对客户端可见。
默认情况下,所有的删除操作的优雅退出时间都在30秒以内。kubectl delete命令支持–graceperiod=的选项,以运行用户来修改默认值。0表示删除立即执行,并且立即从API中删除pod这样一个新的pod会在同时被创建。在节点上,被设置了立即结束的的pod,仍然会给一个很短的优雅退出时间段,才会开始被强制杀死。