3. Pod详解

Pod的功能

首先我们知道,要想在Kubernetes中部署一个容器,我们必须将其封装到Pod中再进行部署。为什么Kubernetes不直接使用容器,非要引入Pod这样一个概念来对容器进行封装呢?原因看上去好像一句废话一下:容器满足不了Kubernetes的需求。其实Pod在容器之上做了一系列的功能,来满足Kubernetes的需求,主要有增强容器的功能,辅助调度和共享资源三个方面。

增强容器

Pod通过以下一些配置增强了容器的功能:

  • Labels and annotations:通过标签Pod可以很方便的与Kubernetes中的其他资源对象进行协作。通过annotations可以引进新特性或与第三方组件进行集成。
  • Restart policies:可以指定Pod 及容器的重启策略。
  • Probes:通过探测(启动探测、就绪探测、活动探测等)可以获取Pod中容器或应用的状态,进而实现Pod的自动扩容缩容、滚动更新,self-healing等高级调度功能。
  • Affinity and anti-affinity rules:通过亲和性和反亲和性规则可以影响Kubernetes在调度中的决策,从而影响Pod部署到哪个节点。
  • Termination control:通过Termination control,可以实现Pod中容器和应用的优雅关闭。
  • Security policies:通过安全策略能够实现一些安全功能。
  • Resource requests and limits:通过资源需求和限制相关的配置,能够分配和限制Pod能够使用的资源,如CPU/Memory等。

下图表明一个Pod可以封装一个或多个容器,并提供了更多的功能:

辅助调度

Pod是调度的基本单元。Kubernetes能够确保Pod中的容器和应用调度到同一个worker node上,这也就保证了Pod中的所有应用都在同一个机房的同一个Region和Zone。

上文提到的Labels,Affinity and anti-affinity rules和Resource requests and limits也能够让用户很细的粒度控制Kubernetes的调度。

资源共享

Pod能够为在它内部的所有容器提供统一的共享的运行时环境,包括:

  • 共享的文件系统
  • 共享的网络
  • 共享的内存和存储

这意味着,Pod中的所有容器和应用共享一个IP地址,可以通过共享存储来同步文件或共享数据。

 

Pod的生命周期

当我们定义好一个Pod的YAML文件并提交给API Server后,API Server会先把这些配置信息存储到 Cluster store(etcd)中,这些信息可以称之为 Pod的 desired state. 配置信息保存好之后,API Server 通过 Scheduler 将Pod调度到一个worker node 上。一旦Pod被调度到worker node 上,Pod的状态就变为 pending状态。worker node 上的kubelet开始拉取镜像,启动Pod中的容器(这期间一直是pending状态),直到所有容器都启动成功,Pod则进入 running状态。一旦Pod中的所有容器都正常执行完毕,正常退出,Pod就进入success状态。如果Pod中的容器执行过程中发生了意外退出或者启动没有成功,Pod则进入failed状态。Pod的状态流转如下图所示:

Pod的部署

Pod可以通过kubelet客户端直接部署,也可以通过controller间接部署。

通过kubelet直接部署的Pod我们称之为static Pod.这类Pod不具备self-healing、自动扩容缩容及滚动更新等高级调度功能,因为这些功能是由controller提供的。static Pod是由kubelet客户端进行管理的,它只能够监控Pod, 如果Pod down掉,它只能在当前节点上对Pod进行简单的重启,不能向controller一样,将Pod调度到其他worker node上启动。

通过controller间接部署的Pod具有self-healing、自动扩容缩容及滚动更新等高级调度功能。当一个Pod节点挂掉后,controller检测到以后,会立即在其他的worker node上启动一个同样的Pod。理解这一点非常重要,这也是我们需要将 应用程序的状态信息保存到Pod外部的重要原因。

Shorted-lived and long-lived Pods
应用程序有很多种,有的是web服务,需要一直保持运行,如果Pod中有这种容器镜像,我们称之为long-lived Pods。有的是任务型,任务执行完成就退出了,这种我们称之为shorted-lived Pods. 如果一个long-lived Pods意外退出了,kubelet可能会重启它。为什么说可能?因为这取决于我们配置的restart Policy.restart Policy有三种:Always, OnFailure, and Never。绝大多数long-lived Pods 都会配置为Always,因为服务意外退出需要就需要重启恢复。大多数shorted-lived Pods会配置为OnFailure或Never.

Controller的类型

kubernetes提供了多种controller。Deployments, StatefulSets 和 DaemonSets 适合long-lived Pods. Jobs and CronJobs适合short-lived Pods.

Multi-container Pod

Pod中可以有一个或者多个容器。当多个容器在同一个Pod中时,这些容器是以Pod为基本单元,作为一个整体进行管理的。特别是在横向扩展时,Pod中的容器会一起扩容。不过,一般情况下,我们不会将多个容器放到同一个Pod中,除非这些容器是紧密联系在一起的。当我们在设计微服务时,通常会使用单一职责原则或者关注点分离原则,应用这些原则使得我们的微服务功能简单、体积小、易于重用并且能过快速迭代。但有些服务或功能之间联系非常紧密,我们又希望他们能够部署在一个Pod中。将多个容器放到同一个Pod中,使得容器能够保持单一职责原则,并能够将多个联系紧密的容器放到一起管理。Kubernetes为我们预定义了一些多容器部署的模式:

  • Sidecar Pattern 边车模式
  • Adaptor Pattern  适配器模式
  • Ambassador Pattern  外交官模式或代理模式
  • Init Pattern  初始化模式

Pod原理

从原理上讲,Pod其实是一个逻辑概念,对应于Linux系统的Namespace和Cgroups. 每个Pod的内部都有一个infra容器,它使用特殊的镜像:k8s.gcr.io/pause,这是使用汇编写的永远处于'暂停'状态的容器。 从这个角度看,可以认为Pod是容器的容器.Pod中的容器共享Pod的系统资源,这些系统资源其实就是操作系统内核的namespace.这些namespace包括:

  • net namespace: 包括 IP 地址,端口范围,路由表
  • pid namespace: 隔离的进程树
  • mnt namespace:文件系统及存储
  • UTS namespace:主机名
  • IPC namespace:Unix domain socket 和 共享内存

另一个方面,Pod使用操作系统的Control Groups 来管理CPU、内存及IOPS等资源。Pod可以指定自己的cgroups limits,每个容器也可以指定自己的cgroups limits,从而限制Pod和容器对资源的访问。

Pod与网络

 每一个Pod都有一个独立的network namespace. 这意味着每一个Pod都有独立的IP地址,端口号范围以及自己的路由表。如果Pod中有多个容器,这些容器共享这个Pod的IP地址,款口号范围及路由表。Pod内部的各个容器通过localhost即可互相访问,两个独立的Pod的相互访问则是通过Pod的IP地址实现。如下图:Main Container和Supporting Container之间可以通过localhost进行访问,右侧的Pod对左侧Pod中的容器的访问,则是通过左侧Pod的IP地址和其内部的容器的端口号进行访问。

 

 

kubernetes集群中有个虚拟网络,叫Pod network, 所有Pod的IP地址在Pod network中都是可达的。如下图所示,Pod network构建于物理网络之上:

 

 

 各个物理网络(A、B、C)之间通过路由器相连,可以互相访问,Pod 网络是构建在这几个物理网络之上的虚拟网络。

 

posted @ 2023-03-16 22:41  小张同学哈  阅读(153)  评论(0编辑  收藏  举报