Kubernetes-4.Pods

  • docker version:19.03.14
  • kubernetes version:1.19.4

** 已了解Kubernetes的组成、安装、以及kubectl基本命令使用

本文概述Kubernetes中workloads资源控制器基本信息以及Pods资源的介绍。

目录

workloads

工作负载(workloads)是在Kubernetes上运行的应用程序。无论负载是单一组件还是有多个一同工作的组件构成,在Kubernetes中均可以在一组Pods中运行它。

在Kubernetes中,Pod代表的是集群上处于运行状态的一组容器。

Pods有确定的生命周期,使用中通常并不需要直接管理每个Pod。可以使用负载资源来管理一组Pods。这些资源配置控制器(controllers)来确保合适类型的、处于运行状态的Pod个数是正确的且与指定状态是相一致的。

资源控制器

Kubernetes常用资源、对象:

  • Pods
  • workloads资源
  • 服务发现及均衡
  • 配置与存储
  • 集群级资源
  • 元数据型资源

基础介绍

workload主要包含以下资源:

  1. Deployment和ReplicaSet(替换ReplicationController)。Deployment很适合用来管理集群上的无状态应用。
  2. StatefulSet。运行有状态应用控制器。
  3. DaemonSet。定义提供节点本地支撑设施的Pods。
  4. Job和Cronjob。定义一些一直运行到结束并停止的任务。Job为一次性任务,Cronjob为重复性任务。

服务发现及均衡资源:

  1. Service
  2. Ingress

存储与配置资源:

  1. Volume
  2. CSI(容器存储接口)
  3. ConfigMap、Secret
  4. DownwardAPI

集群级资源:

  1. Namespace
  2. Node
  3. Role,ClusterRole
  4. RoleBinding,ClusterRoleBinding

元数据型资源:

  1. HPA
  2. PodTamplate
  3. LimitRange

Pods

Pods是在kubernetes中最小可部署的计算单元。

Pod是一组(一个或多个)容器。这些容器共享存储、网络、以及容器运行声明。

Pod类似于共享名称空间和文件系统卷的一组Docker容器。

每个Pod都运行给定应用程序的单个实例,希望横向扩展应用程序,则应该使用多个Pod,每个实例使用一个Pod,其被称为副本(Replication)。通常使用一种workload资源控制器来创建和管理一组Pod副本。

通过命令行使用的Pod操作基础

# 创建一个名称为nginx的pod,镜像为nginx:latest,默认存在于default名称空间
kubectl run nginx --image=nginx

# 查看;使用-O wide可查看详细信息;pod可简写为po
kubectl get po -o wide

# 为其创建一个服务(暴露端口);--type可指为ClusterIP、NodePort,默认ClusterIP;--port即服务端口;--target-port即后端端口,--protocol即协议、默认TCP;--name即为此service指定名称,可选
kubectl expose po webapp --type=ClusterIP --port=30080 --target-port=80 --protocol=TCP --name=websvc

# 查看service可以看到刚才expose的服务端口;service可简写为svc;集群内任意主机可以通过ClusterIP:Port进行访问
kubectl get svc

# 删除此pod
kubectl delete po 

清单文件

通常使用时很少通过命令行进行创建,一般使用清单文件创建。

清单文件格式

通常使用yaml格式

  • 在文件中字典可使用花括号,或换行缩进
  • 在文件中列表数据可使用中括号或中划线
  • 在一个文件中有多个yaml配置段使用三个中划线对其分隔

示例:

---
json:
- rigid
- better for data interchange
yaml:
- slim and flexible
- better for configuration
object:
  key: value
  array:
  - null_value: 
  - boolean: true
  - integer: 1
paragraph: |
  Blank lines denote
  paragraph breaks
content: |-
  Or we
  can auto
  convert line breaks
  to save space

通过清单文件创建Pod

示例:

apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
  namespace: default
spec:
  containers:
  - name: webapp
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: web-port
      containerPort: 80
  restartPolicy: Never

创建此文件保存至demo-pod.yaml文件,通过命令行创建:

# 当第一次创建此资源可以使用create,当已有该名称的资源存在则不能使用create
kubectl create -f demo-pod.yaml

# 使用apply则资源不存在则创建,资源已存在则更新资源状态为文件中的配置
kubectl apply -f demo-pod.yaml

大部分清单文件的的字段:
apiVersion:使用Kubernetes的哪个API资源
kind:资源类别
metadata:元数据
spec:期望状态
status:当前状态;该字段由集群维护

以上示例解释:
apiVersion:指定API资源;Pod控制器使用的api为v1
kind:指定资源类别;Pod资源属于Pod类别
metadata.name:指定此Pod的名称
metadata.namespace:指定此Pod所属的名称空间
spec.containers.name:为容器指定名称
spec.containers.image:指定容器的镜像
spec.containers.imagePullPolicy:指定容器的镜像拉取策略;可使用值为Always、Never、IfNotPresent;
如果镜像的tag是latest则默认值是Always,非latest标签则默认为IfNotPresent;指定Always表示已存在镜像且标签且为latest则总是拉取最新的latest,指定为Never表示永不拉取镜像,指定为IfNotPresent表示不存在则拉取镜像
spec.containers.ports:声明容器要公开的端口列表
spec.containers.ports.name:声明容器要公开的端口的名称
spec.containers.ports.name.containerPort:容器要暴露的端口
spec.restartPolicy:重启策略;Always(默认)、OnFailure、Never

explain

列出支持的资源的字段,此命令描述每个支持的API资源的字段。

通过此命令可以查看清单文件定义时可以使用的资源、字段等详细内容。

kubectl explain RESOURCE [options]

# 列出pod资源spec字段下的子字段
kubectl explain pods.spec

# 列出secret资源支持的字段
kubectl explain secret

# 列出pod资源spec字段中containers下livenessProbe字段支持的字段
kubectl explain pod.spec.containers.livenessProbe

Pod的生命周期

Pod中创建一个容器可能会包含一些初始化容器(辅助容器),初始化容器完成工作后退出,而后主要容器启动,启动容器后可能会需要postStart等操作,结束过程前可能会需要preStop等操作;其生命周期中可能需要持续保持着livenessProbe及readinessProbe操作。

Kubernetes-4.Pods

Pod阶段

Pod的status字段是一个PodStatus对象,其中包含一个phase字段。

Pod的阶段(Phase)是Pod在其生命周期中所处位置的简单宏观概述。

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

容器状态

Kubernetes会跟踪Pod中每个容器的状态,就像它跟踪Pod总体上的阶段(Phase)一样。

一旦调度器将Pod分配给某个节点,kubelet就通过容器运行时开始为Pod创建容器。容器的状态有三种:Waiting、Running、Terminated。

检查Pod中容器的状态,可使用kubectl describe pod <pod-name>

容器重启策略

Pod的spec字段中restartPolicy字段控制容器重启策略;其值为Always、OnFailure、Never,默认是Always。restartPolicy适用于Pod中的所有容器。

Pod状况

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

PodScheduled:Pod已经被调度到某节点;
ContainersReady:Pod中所有容器都已就绪;
Initialized:所有的Init容器都已成功启动;
Ready:Pod可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。

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

Pod的终止

终止Pod的过程:

  1. 发送删除Pod请求,Pod的优雅终止期限默认值30秒。

  2. 更新API服务器中的Pod对象,记录涵盖优雅终止限期在内Pod的最终死期。超出所计算时间则认为Pod已死(dead)。在Pod运行的节点上,kubelet一旦检测到Pod被标记为正在终止(Terminating ),则开始关闭在本节点上此Pod的进程。

    1 如果Pod中的任一容器定义了preStop回调,则开始运行此回调逻辑。如果超出了优雅终止限期,preStop仍在运行,则会给予该Pod一次性的宽限期(2秒)。如果preStop回调需要较长的时间,可以通过更改terminationGracePeriodSeconds属性值使其正常工作。
    2 kubelet发送TERM信号给每个容器中pid为1的进程

  3. 从对应的端点列表、工作负载资源中移除该Pod,ReplicaSets不再将其视为能够提供服务的副本。

  4. 超出终止宽限期限时,kubelet会触发强制关闭过程。容器运行时会向Pod中所有容器内仍在运行的进程发送SIGKILL信号。 kubelet也会清理隐藏的pause容器(如果有)。

  5. kubelet触发强制从API服务器上删除Pod对象的逻辑,并将优雅终止期限设置为0(意味着马上删除)。

  6. API服务器删除Pod的API对象。

强制终止Pod

默认情况下,所有的删除操作都会附有30秒钟的宽限期限。 kubectl delete命令支持--grace-period=<seconds>选项,允许重载默认值,设定自己希望的期限值。

将宽限期限强制设置为0意味着立即从API服务器删除Pod。

必须在设置--grace-period=0的同时额外设置--force参数才能发起强制删除请求。

执行强制删除操作时,API服务器不再等待来自kubelet的、关于Pod已经在原来运行的节点上终止执行的确认消息。API服务器直接删除Pod对象,这样新的与之同名的Pod即可以被创建。在节点侧,被设置为立即终止的Pod仍然会在被强行杀死之前获得一点点的宽限时间。

失效Pod的垃圾收集

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

控制面组件会在Pod个数超出所配置的阈值(根据kube-controller-manager的 terminated-pod-gc-threshold设置)时删除已终止的Pod(阶段值为Succeeded或Failed)。这一行为会避免随着时间演进不断创建和终止Pod而引起的资源泄露问题。

容器探针

Probe是由kubelet对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的Handler(处理程序)。有三种类型的处理程序:

ExecAction:在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
TCPSocketAction:对容器的IP地址上的指定端口执行TCP检查。如果端口打开,则诊断被认为是成功的。
HTTPGetAction:对容器的IP地址上指定端口和路径执行HTTP Get请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的。

每次探测都将获得以下三种结果之一:
Success:容器通过了诊断。
Failure:容器未通过诊断。
Unknown:诊断失败,因此不会采取任何行动。

针对运行中的容器,kubelet可以选择是否执行一下三种探针,以及如何针对探测结果作出反应:
livenessProbe:存活状态探测;指示容器是否正在运行。如果探测失败,则kubelet会杀死容器,并且容器将根据其重启策略决定未来。如果不指定存活状态探针,则默认状态为Success
readinessProbe:就绪状态探测;指示容器是否准备好为请求提供服务。如果探测失败,端点控制器将从与Pod匹配的所有服务的端点列表中删除该Pod的IP地址(即未准备就绪不会将其加入到service的后端)。初始延迟之前的就绪状态值默认为Failure。如果容器不提供就绪状态探针,则默认状态为Success
startupProbe:启动状态探测;指示容器中的应用是否已经启动。如果提供了启动探针,则所有其它探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet将杀死容器,以其重启策略重启。如果容器没有提供启动探测探针,则默认状态为Success

存活状态探针

如果容器因为进程遇到问题的情况下自行崩溃,则不一定需要存活状态探针。
如果希望的是容器在探测失败时被杀死并重启,这种情况下就应当使用存活状态探针,并且指定容器重启策略。

常用参数
pod.spec.containers.livenessProbe:启用livenessProbe
pod.spec.containers.livenessProbe.exec:使用命令方式探测,见#容器探针#ExecAction内容
pod.spec.containers.livenessProbe.httpGet:使用http get方式探测,见#容器探针#HTTPGetAction内容
pod.spec.containers.livenessProbe.tcpSocket:使用TCP Socket方式探测,见#容器探针#TCPSocketAction内容
pod.spec.containers.livenessProbe.initialDelaySeconds:延迟探测时间
pod.spec.containers.livenessProbe.periodSeconds:探测时间间隔,默认10s
pod.spec.containers.livenessProbe.successThreshold:成功N次则将状态装换为成功,默认1,最小1
pod.spec.containers.livenessProbe.failureThreshold:失败N次则将状态装换为失败,默认1,最小1
pod.spec.containers.livenessProbe.timeoutSeconds:探测超时时间(秒),默认1,最小1

示例:
使用存活探针探测某个文件是否存在,不存在则视为故障,使其重启且生成此文件。

根据清单文件创建此pod,观察其信息(kubectl describe po liveness-exec pod)中的Events,经过一定次数的探测后,其会提示Liveness probe failed,而后重启此Pod中的容器。

apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec-pod
  namespace: default
spec:
  containers:
  - name: liveness-exec-container
    image: busybox:latest
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh", "-c", "touch /tmp/healthy; sleep 60; rm -f /tmp/healthy; sleep 3600"]
    livenessProbe:
      exec:
        command: ["test", "-e", "/tmp/healthy"]
      initialDelaySeconds: 3
      periodSeconds: 5
  restartPolicy: OnFailure

就绪状态探针

就绪状态探针的存在意味着Pod将在启动阶段不接收任何数据,并且只有在就绪状态探针探测成功后才开始接收数据。

假如容器需要在启动时加载大量数据、配置文件或应用初始化等操作,则应当使用就绪状态探针。

常用参数
pod.spec.containers.readinessProbe:启用readinessProbe
其它参数同livenessProbe

示例:
使用就绪状态探针探测Web服务是否准备就绪,就绪后才开始接受请求。

创建此Pod,观察其READY状态(kubelet get po readiness-httpget-pod),在指定的就绪状态检测次数总和判定为成功之前和之后,其状态变化,则是readinessProbe探针状态的变化。

apiVersion: v1
kind: Pod
metadata:
  name: readiness-httpget-pod
  namespace: default
spec:
  containers:
  - name: readiness-httpget-container
    image: nginx
    imagePullPolicy: IfNotPresent
    readinessProbe:
      httpGet:
        port: 80
      initialDelaySeconds: 3
      periodSeconds: 5
  restartPolicy: Never

启动状态探针

对于所包含的容器需要较长时间才能启动就绪的Pod而言,则应当使用启动探针。如果容器启动时间通常超出initialDelaySeconds + failureThreshold × periodSeconds总值,则应该设置一个启动探测。

periodSeconds的默认值是10秒。应该将其failureThreshold设置得足够高,以便容器有充足的时间完成启动,并且避免更改存活态探针所使用的默认值。这一设置有助于减少死锁状况的发生。

常用参数
pod.spec.containers.startupProbe: 启用startupProbe
其它参数同livenessProbe

lifecycle

在Pod的生命周期中,还存在postStart和preStop两个处理函数。
postStart:当一个容器启动后,立即执行postStart事件
preStop:在容器被终结之前,执行preStop事件

postStart

注意:spec.containers.command执行顺序优先于postStart中的exec.command

常用参数
pod.spec.containers.lifecycle.postStart:启用postStart
pod.spec.containers.lifecycle.postStart.exec:使用命令行执行事件
pod.spec.containers.lifecycle.postStart.httGet:使用http get方法执行事件
pod.spec.containers.lifecycle.postStart.tcpSocket:使用TCP Socket方法执行事件

示例:
创建一个postStart事件,在容器启动后做一些操作

创建此Pod,而后访问其/hello.html文件,则证实postStart处理的事件

apiVersion: v1
kind: Pod
metadata:
  name: poststart-pod
  namespace: default
spec:
  containers:
  - name: poststart-pod
    image: nginx
    imagePullPolicy: IfNotPresent
    readinessProbe:
      httpGet:
        port: 80
        path: /hello.html
      initialDelaySeconds: 3
      periodSeconds: 5
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo HelloWebServer >>/usr/share/nginx/html/hello.html"]
  restartPolicy: Never

preStop

pod.spec.containers.lifecycle.preStop:启用preStop
其它同postStart

上一篇:Kubernetes --(k8s)Job、CronJob


下一篇:Angular jasmine单元测试框架spec的运行时数据结构