Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

网上的资料对这块的讲解几乎都是纯文字性的,结果可能会导致在入门kubernetes的时候,就忽略了这个非常重要的知识点,先糊涂一阵,等实际操作了后,再回过头来,原来如此啊。本文在讲解特性的同时,配了几张图,希望对理解pod有帮助。

Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。

1.什么是 Pod

Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离 方面,即用来隔离 Docker 容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。

2.使用 Pod

Kubernetes 集群中的 Pod 主要有两种用法:

  • 运行单个容器的 Pod。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。

  • 运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的“边车”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。

你很少在 Kubernetes 中直接创建一个个的 Pod,甚至是单实例(Singleton)的 Pod。 而是使用工作负载资源(Deployment、StatefulSet、DaemonSet、Cronjob)等来创建和管理多个 Pod。 资源的控制器能够处理副本的管理、上线,并在 Pod 失效时提供自愈能力。 例如,如果一个节点失败,控制器注意到该节点上的 Pod 已经停止工作, 就可以创建替换性的 Pod。调度器会将替身 Pod 调度到一个健康的节点执行。

3.Pod 模版

工作负载资源(Deployment、StatefulSet、DaemonSet、Cornjob)的控制器通常使用 Pod 模板(Pod Template)来创建 Pod 并管理。

工作负载的控制器会使用负载对象中的 PodTemplate 来生成实际的 Pod。 下面的示例是一个简单的 Job 的清单,其中的 template 指示启动一个容器。 该 Pod 中的容器会打印一条消息之后暂停。未来每个被启动的pod母本描述都是来源于此。

apiVersion: batch/v1
kind: Job
metadata:
  name: hello
spec:
  template:
    # ================== 这里是 Pod 模版  ==================
    spec:
      containers:
      - name: hello
        image: busybox
        command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
      restartPolicy: OnFailure
    # ================== 以上为 Pod 模版 ==================

修改 Pod 模版或者切换到新的 Pod 模版都不会对已经存在的 Pod 起作用。 Pod 不会直接收到模版的更新。相反, 新的 Pod 会被创建出来,与更改后的 Pod 模版匹配。下面是从一个正常运行的pod导出的yaml文件,里面包含了很多pod自身特有的性质,接下来,我们将会逐一进行介绍。

apiVersion: v1 # 【必须】版本号
kind: Pod # 【必选】Pod
metadata: # 【必选-Object】元数据
  name: String # 【必选】 Pod的名称
  namespace: String # 【必选】 Pod所属的命名空间
  labels: # 【List】 自定义标签列表
   - name: String
  annotations: # 【List】 自定义注解列表
   - name: String
spec: # 【必选-Object】 Pod中容器的详细定义
  containers: # 【必选-List】 Pod中容器的详细定义
  - name: String # 【必选】 容器的名称
    image: String # 【必选】 容器的镜像名称
    imagePullPolicy: [Always | Never | IfNotPresent] # 【String】 镜像拉取策略
    command: [String] # 【List】 容器的启动命令列表,如果不指定,则使用镜像打包时使用的启动命令
    args: [String] # 【List】 容器的启动命令参数列表
    workingDir: String # 容器的工作目录
    volumeMounts: # 【List】 挂载到容器内部的存储卷配置
    - name: String # 引用Pod定义的共享存储卷的名称,需使用volumes[]部分定义的共享存储卷名称
      mountPath: Sting # 存储卷在容器内mount的绝对路径,应少于512个字符
      readOnly: Boolean # 是否为只读模式,默认为读写模式
    ports: # 【List】 容器需要暴露的端口号列表
    - name: String  # 端口的名称
      containerPort: Int # 容器需要监听的端口号
      hostPort: Int # 容器所在主机需要监听的端口号,默认与containerPort相同。设置hostPort时,同一台宿主机将无法启动该容器的第二份副本
      protocol: String # 端口协议,支持TCP和UDP,默认值为TCP
    env: # 【List】 容器运行前需设置的环境变量列表
    - name: String # 环境变量的名称
      value: String # 环境变量的值
    resources: # 【Object】 资源限制和资源请求的设置
      limits: # 【Object】 资源限制的设置
        cpu: String # CPU限制,单位为core数,将用于docker run --cpu-shares参数
        memory: String # 内存限制,单位可以为MB,GB等,将用于docker run --memory参数
      requests: # 【Object】 资源限制的设置
        cpu: String # cpu请求,单位为core数,容器启动的初始可用数量
        memory: String # 内存请求,单位可以为MB,GB等,容器启动的初始可用数量
    # 【Object】 对Pod内各容器健康检查的设置,当探测无响应几次之后,系统将自动重启该容器。
    # 可以设置的方法包括:exec、httpGet和tcpSocket。对一个容器只需要设置一种健康检查的方法
    livenessProbe:
      exec: # 【Object】 对Pod内各容器健康检查的设置,exec方式
        command: [String] # exec方式需要指定的命令或者脚本
      httpGet: # 【Object】 对Pod内各容器健康检查的设置,HTTGet方式。需要指定path、port
        path: String
        port: Number
        host: String
        scheme: String
        httpHeaders:
        - name: String
          value: String
      tcpSocket: # 【Object】 对Pod内各容器健康检查的设置,tcpSocket方式
        port: Number
      initialDelaySeconds: Number # 容器启动完成后首次探测的时间,单位为s
      timeoutSeconds: Number  # 对容器健康检查的探测等待响应的超时时间设置,单位为s,默认值为1s。
      periodSeconds: Number # 对容器健康检查的定期探测时间设置,单位为s,默认10s探测一次
      successThreshold: 0
      failureThreshold: 0
    securityContext:
      privileged: Boolean
  # Pod的重启策略 一旦终止运行,都将重启 | 终止后kubelet将报告给master,不会重启 
  # 只有Pod以非零退出码终止时,kubelet才会重启该容器。如果容器正常终止(退出码为0),则不会重启。
  restartPolicy: [Always | Never | OnFailure]
  nodeSelector: object # 设置Node的Label,以key:value格式指定,Pod将被调度到具有这些Label的Node上
  imagePullSecrets: # 【Object】 pull镜像时使用的Secret名称,以name:secretkey格式指定
  - name: String
  # 是否使用主机网络模式,默认值为false。设置为true表示容器使用宿主机网络,不再使用docker网桥,该Pod将无法在同一台宿主机上启动第二个副本
  hostNetwork: Boolean
  volumes: # 【List】 在该Pod上定义的共享存储卷列表
  - name: String # 共享存储卷的名称,volume的类型有很多emptyDir,hostPath,secret,nfs,glusterfs,cephfs,configMap
    emptyDir: {} # 【Object】 类型为emptyDir的存储卷,表示与Pod同生命周期的一个临时目录,其值为一个空对象:emptyDir: {}
    hostPath: # 【Object】 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
      path: String # Pod所在主机的目录,将被用于容器中mount的目录
    secret: # 【Object】类型为secret的存储卷,表示挂载集群预定义的secret对象到容器内部
      secretName: String
      items:
      - key: String
        path: String
    configMap: # 【Object】 类型为configMap的存储卷,表示挂载集群预定义的configMap对象到容器内部
      name: String
      items:
      - key: String
        path: String

4.Pod 的生命周期

Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者 被终止。

5.Pod 阶段

Pod 的 status 字段是一个 PodStatus 对象,其中包含一个 phase 字段。Pod 的阶段(Phase)是 Pod 在其生命周期中所处位置的简单宏观概述。

Pod 阶段的数量和含义是严格定义的。 下面是 phase 可能的值:

取值描述
PendingPod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
RunningPod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
SucceededPod 中的所有容器都已成功终止,并且不会再重启。
FailedPod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
Unknown因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的 phase 设置为 Failed。

6.容器状态

Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的阶段一样。一旦调度器将 Pod 分派给某个节点,kubelet 就通过 容器运行时 开始为 Pod 创建容器。 容器的状态有三种:Waiting(等待)、Running(运行中)和 Terminated(已终止)。要检查 Pod 中容器的状态,你可以使用 kubectl describe pod <pod 名称>。 其输出中包含 Pod 中每个容器的状态。每种状态都有特定的含义:

状态描述说明
Waiting等待处于 Waiting 状态的容器仍在运行它完成启动所需要的操作
Running运行中Running 状态表明容器正在执行状态并且没有问题发生
Terminated已终止处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败

下面是一个“Running”的pod状态截图。

7.容器重启策略

Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。例如:

restartPolicy 适用于 Pod 中的所有容器。restartPolicy 仅针对同一节点上 kubelet 的容器重启动作。当 Pod 中的容器退出时,kubelet 会按指数回退 方式计算重启的延迟(10s、20s、40s、...),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启回退计时器执行 重置操作。

8.Pod 状况

Pod 有一个 PodStatus 对象,其中包含一个 PodConditions 数组。Pod 可能通过也可能未通过其中的一些状况测试。

  • PodScheduled:Pod 已经被调度到某节点;

  • ContainersReady:Pod 中所有容器都已就绪;

  • Initialized:所有的 Init 容器 都已成功完成;

  • Ready:Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。

字段名称描述
typePod 状况的名称
status表明该状况是否适用,可能的取值有 "True", "False" 或 "Unknown"
lastProbeTime上次探测 Pod 状况时的时间戳
lastTransitionTimePod 上次从一种状态转换到另一种状态时的时间戳
reason机器可读的、驼峰编码(UpperCamelCase)的文字,表述上次状况变化的原因
message人类可读的消息,给出上次状态转换的详细信息

9.容器探针

9.1检查机制

使用探针来检查容器有四种不同的方法。 每个探针都必须准确定义为这四种机制中的一种:

序号机制说明
1exec在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
2grpc使用 gRPC 执行一个远程过程调用。 目标应该实现 gRPC健康检查。 如果响应的状态是 "SERVING",则认为诊断成功。
3httpGet对容器的 IP 地址上指定端口和路径执行 HTTP GET 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。
4tcpSocket对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。

9.2探测结果

每次探测都将获得以下三种结果之一

序号状态描述说明
1Success成功容器通过了诊断
2Failure失败容器未通过诊断
3Unknown未知诊断失败,因此不会采取任何行动

9.3探测类型

针对运行中的容器,kubelet 可以选择是否执行以下三种探针,以及如何针对探测结果作出反应:

序号探针类型
1livenessProbe指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success。
2readinessProbe指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。
3startupProbe指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器,而容器依其 重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success。

为了更直观的加深印象,专门找了一个正在运行的pod的探针信息截图。

10.Pod 的终止

默认情况下,所有的删除操作都会附有 30 秒钟的宽限期限。

10.1正常终止

kubectl delete pod  <pod名称> -n <命名空间>

10.2强制终止

kubectl delete 命令支持 --grace-period=<seconds> 选项,允许重载默认值, 设定希望的期限值,且同时额外设置 --force 参数才能发起强制删除请求。

11.失效 Pod 的垃圾收集

对于已失败的 Pod 而言,对应的 API 对象仍然会保留在集群的 API 服务器上,直到 用户或者控制器进程显式地 将其删除。

12.总结

pod是在 Kubernetes 中创建和管理的、最小的可部署的计算单元。基于pod的特性,扩展了很多高级操作。纵观互联网的材料,对pod的关联性阐述,应该加深一下,快速踏入kubernetes的门槛吧。

Logo

开源、云原生的融合云平台

更多推荐