Bootstrap

一、Pod的生命周期

Pod的生命周期

在这里插入图片描述

一、Init Container(初始化容器)

每个 Pod 中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。init container与应用容器在本质上是一样的,但它们是仅运行一次就结束的任务,并且必须在成功运行完成后,系统才能继续执行下一个init容器。
如果 Pod 的 Init 容器失败而 设 置RestartPolicy=Always时,Pod将会被系统自动重启,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的 restartPolicy 值为 “Never”,并且 Pod 的 Init 容器失败, 则 Kubernetes 会将整个 Pod 状态设置为失败。

apiVersion: v1
kind: Pod
metadata:
  name: pod-init
spec:
  restartPolicy: Never
  initContainers:
  - name: init-myservice
    image: busxx  #故意将镜像名称写错
    command: ['sh', '-c','echo The app is running!']
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']

在这里插入图片描述
在这里插入图片描述
下面以Nginx应用为例,在启动Nginx之前,通过初始化容器busybox为Nginx创建一个index.html主页文件。这里为init container和Nginx设置了一个共享的Volume,以供Nginx访问init container设置的index.html文件:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nginx
spec:
  initContainers:
  - image: busybox
    name: install_html
    command:
    - wget
    - www.baidu.com
    - -O
    - /tmp/index.html
    volumeMounts:
    - name: index
      mountPath: /tmp
  containers:
  - image: nginx
    name: show
    ports:
    - containerPort: 80
    volumeMounts:
    - name: index
      mountPath: /usr/share/nginx/html
  volumes:
  - name: index
    emptyDir: {}

创建这个Pod:

[root@node4 k8s-test]# kubectl apply -f init-test.yaml 
pod/pod-nginx created

在运行init container的过程中查看Pod的状态:
在这里插入图片描述
启动成功后,登录进Nginx容器,可以看到/usr/share/nginx/html目录下的index.html文件为init container所生成,其内容如下:

在这里插入图片描述
init container与应用容器的区别如下:

  • init container的运行方式与应用容器不同,它们必须先于应用容器执行完成,当设置了多个init container时,将按顺序逐个运行,并 且 只 有 前 一 个 init container 运 行 成 功 后 才 能 运 行 后 一 个 initcontainer。在所有init container都成功运行后,Kubernetes才会初始化Pod的各种信息,并开始创建和运行应用容器。

  • 在init container的定义中也可以设置资源限制、Volume的使用和安全策略,等等。但资源限制的设置与应用容器略有不同。

    • 如果多个init container都定义了资源请求/资源限制,则取最大的值作为所有init container的资源请求值/资源限制值。
    • Pod的有效(effective)资源请求值/资源限制值取以下二者中的较大值:①所有应用容器的资源请求值/资源限制值之和;②init container的有效资源请求值/资源限制值。
    • 调度算法将基于Pod的有效资源请求值/资源限制值进行计算,也就是说init container可以为初始化操作预留系统资源,即使后续应用容器无须使用这些资源。
    • Pod的有效QoS等级适用于init container和应用容器。
  • init container不能设置readinessProbe探针,因为必须在它们成功运行后才能继续运行在Pod中定义的普通容器。
    在Pod重新启动时,init container将会重新运行,常见的Pod重启场景如下:

  • init container的镜像被更新时,init container将会重新运行,导致Pod重启。仅更新应用容器的镜像只会使得应用容器被重启。

  • Pod的infrastructure容器更新时,Pod将会重启。

  • 若 Pod 中 的 所 有 应 用 容 器 都 终 止 了 , 并 且RestartPolicy=Always,则Pod会重启。

二、探针

2.1、LivenessProbe探针

LivenessProbe探针: 用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将“杀掉”该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。
kubelet 使用存活探针来确定什么时候要重启容器。
在下面的例子中,通过运行cat/tmp/health命令来判断一个容器运行是否正常。在该Pod运行后,将在创建/tmp/health文件20s后删除该文
件,而LivenessProbe健康检查的初始探测时间(initialDelaySeconds)为5s,如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness
spec:
  containers:
  - name: linevess
    image: busybox
    imagePullPolicy: IfNotPresent
    command:
    - /bin/sh
    - -c
    - echo 'ok'> /tmp/health;sleep 20; rm -rf /tmp/health;sleep 600
    livenessProbe:
      initialDelaySeconds: 5
      timeoutSeconds: 1
      periodSeconds: 1
      failureThreshold: 5
      exec:
        command:
        - cat
        - /tmp/health

请注意,一旦失败的容器恢复为运行状态,RESTARTS 计数器就会增加 1:
在这里插入图片描述

2.2、ReadinessProbe探针

kubelet 使用就绪探针可以知道容器何时准备好接受请求流量,当一个 Pod 内的所有容器都就绪时,才能认为该 Pod 就绪。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 若 Pod 尚未就绪,会被从 Service 的负载均衡器中剔除。
**ReadinessProbe探针:**用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的Pod,Service与Pod Endpoint的关联关系也将基于Pod是否Ready进行设置。如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod实例上。需要注意的是ReadinessProbe也是定期触发执行的,存在于Pod的整个生命周期中。
就绪探针的配置和存活探针的配置相似。 唯一区别就是要使用 readinessProbe 字段,而不是 livenessProbe 字段。

readinessProbe:
      initialDelaySeconds: 5
      timeoutSeconds: 1
      periodSeconds: 1
      failureThreshold: 5
      exec:
        command:
        - cat
        - /tmp/health
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness
spec:
  containers:
  - name: linevess
    image: nginx
    ports:
    - containerPort: 80
    imagePullPolicy: IfNotPresent
    readinessProbe:
      initialDelaySeconds: 5
      timeoutSeconds: 1
      periodSeconds: 1
      failureThreshold: 5
      tcpSocket:
        port: 81

在这里插入图片描述
不会造成重启!

2.3、StartupProbe探针

StartupProbe探针: 用于判断容器内进程(应用程序)是否已经启动。如果配置了startupProbe,就会先禁用其他的探测,直到它成功为止,成功后将不在进行探测(只执行一次)。某些应用会遇到启动比较慢的情况,例如应用程序启动时需要与远程服务器建立网络连接,或者遇到网络访问较慢等情况时,会造成容器启动缓慢,此时ReadinessProbe就不适用了,因为这属于“有且仅有一次”的超长延时,可以通过StartupProbe探针解决该问题。

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness
spec:
  containers:
 1. name: linevess
    image: nginx
    ports:
    - containerPort: 80
    imagePullPolicy: IfNotPresent
    startupProbe:
      initialDelaySeconds: 5
      timeoutSeconds: 1
      periodSeconds: 1
      failureThreshold: 5
      tcpSocket:
        port: 80

在这里插入图片描述

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness
spec:
  containers:
 2. name: linevess
    image: nginx
    ports:
    - containerPort: 80
    imagePullPolicy: IfNotPresent
    startupProbe:
      initialDelaySeconds: 5
      timeoutSeconds: 1
      periodSeconds: 1
      failureThreshold: 5
      tcpSocket:
        port: 81

在这里插入图片描述

2.4、探测方式

  1. ExecAction: 在容器内部运行一个命令,如果该命令的返回码为0,则表明容器健康。
    在这里插入图片描述

  2. TCPSocketAction: 通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。
    在这里插入图片描述

  3. HTTPGetAction: 通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康。
    在这里插入图片描述

    • host: 连接使用的主机名,默认是 Pod 的 IP。也可以在 HTTP 头中设置 “Host” 来代替。
    • scheme: 用于设置连接主机的方式(HTTP 还是 HTTPS)。默认是 “HTTP”。
    • path: 访问 HTTP 服务的路径。默认值为 “/”。
    • httpHeaders: 请求中自定义的 HTTP 头。HTTP 头字段允许重复。
    • port: 访问容器的端口号或者端口名。如果数字必须在 1~65535 之间。

2.5、配置探针

  • initialDelaySeconds: 容器启动后要等待多少秒后才启动启动、存活和就绪探针。 如果定义了启动探针,则存活探针和就绪探针的延迟将在启动探针已成功之后才开始计算。 默认是 0 秒,最小值是 0。
  • periodSeconds: 执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。
  • timeoutSeconds: 探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。
  • successThreshold: 探针在失败后,被视为成功的最小连续成功数。默认值是 1。 存活和启动探测的这个值必须是 1。最小值是 1。
  • failureThreshold: 探针连续失败了 failureThreshold 次之后, Kubernetes 认为总体上检查已失败:容器状态未就绪、不健康、不活跃。 对于启动探针或存活探针而言,如果至少有 failureThreshold 个探针已失败, Kubernetes 会将容器视为不健康并为这个特定的容器触发重启操作。

三、Pod的生命周期

3.1、Pod 阶段

Pod 的 status 字段是一个 PodStatus 对象,其中包含一个 phase 字段。Pod 的阶段(Phase)是 Pod 在其生命周期中所处位置的简单宏观概述。 该阶段并不是对容器或 Pod 状态的综合汇总,也不是为了成为完整的状态机。

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

在这里插入图片描述

apiVersion: v1
kind: Pod
metadata:
  name: pod-init
spec:
  restartPolicy: Never
  initContainers:
  - name: init-1
    image: busybox
    command: ['sh', '-c','echo The app1 is running!&& sleep 5']
  - name: init-2
    image: busybox
    command: ['sh', '-c','echo The app2 is running!&& sleep 5']
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running!&&sleep 3']

在这里插入图片描述

apiVersion: v1
kind: Pod
metadata:
  name: pod-nginx
spec:
  initContainers:
  - image: busybox
    name: install
    command:
    - wget
    - www.baidu.com
    - -O 
    - /tmp/index.html
    volumeMounts:
    - name: index
      mountPath: /tmp
  containers:
  - image: nginx
    name: show
    ports: 
    - containerPort: 80
    volumeMounts:
    - name: index
      mountPath: /usr/share/nginx/html
  volumes:
  - name: index
    emptyDir: {}

在这里插入图片描述
从 Kubernetes 1.27 开始,除了静态 Pod 和没有 Finalizer 的强制终止 Pod 之外,kubelet 会将已删除的 Pod 转换到终止阶段 (Failed 或 Succeeded 具体取决于 Pod 容器的退出状态),然后再从 API 服务器中删除。
如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的 phase 设置为 Failed。

3.2、容器状态

Kubernetes 会跟踪 Pod 中每个容器的状态,就像它跟踪 Pod 总体上的阶段一样。 你可以使用容器生命周期回调 来在容器生命周期中的特定时间点触发事件。
一旦调度器将 Pod 分派给某个节点,kubelet 就通过容器运行时开始为 Pod 创建容器。容器的状态有三种:Waiting(等待)、Running(运行中)和 Terminated(已终止)。

  • Waiting (等待)
    如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如, 从某个容器镜像仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。
    在这里插入图片描述
  • Running(运行中)
    Running 状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart 回调,那么该回调已经执行且已完成。 如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时, 你也会看到关于容器进入 Running 状态的信息。
    在这里插入图片描述
  • Terminated(已终止)
    处于 Terminated 状态的容器已经开始执行或者正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时, 你会看到容器进入此状态的原因、退出代码以及容器执行期间的起止时间。如果容器配置了 preStop 回调,则该回调会在容器进入 Terminated 状态之前执行。
    在这里插入图片描述

3.3、Pod 状况

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

  • PodScheduled: Pod 已经被调度到某节点;
  • PodHasNetwork: Pod 沙箱被成功创建并且配置了网络(Alpha 特性,必须被显式启用);
  • ContainersReady: Pod 中所有容器都已就绪;
  • Initialized: 所有的 Init 容器都已成功完成;
  • Ready: Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。
    在这里插入图片描述

四、容器生命周期回调

  • PostStart
    这个回调在容器被创建之后立即被执行。 但是,不能保证回调会在容器入口点(ENTRYPOINT)之前执行。 没有参数传递给处理程序。

  • PreStop
    在容器因 API 请求或者管理事件(诸如存活态探针、启动探针失败、资源抢占、资源竞争等) 而被终止之前,此回调会被调用。 如果容器已经处于已终止或者已完成状态,则对 preStop 回调的调用将失败在用来停止容器的 TERM 信号被发出之前,回调必须执行结束。 Pod 的终止宽限周期在 PreStop 回调被执行之前即开始计数, 所以无论回调函数的执行结果如何,容器最终都会在 Pod 的终止宽限期内被终止。 没有参数会被传递给处理程序。

4.1、回调处理程序的实现

容器可以通过实现和注册该回调的处理程序来访问该回调。 针对容器,有两种类型的回调处理程序可供实现:

  • Exec - 在容器的 cgroups 和名字空间中执行特定的命令(例如 pre-stop.sh)。 命令所消耗的资源计入容器的资源消耗。
  • HTTP - 对容器上的特定端点执行 HTTP 请求。

4.2、回调处理程序执行

当调用容器生命周期管理回调时,Kubernetes 管理系统根据回调动作执行其处理程序, httpGet 和 tcpSocket 在 kubelet 进程执行,而 exec 则由容器内执行。
回调处理程序调用在包含容器的 Pod 上下文中是同步的。 这意味着对于 PostStart 回调,容器入口点和回调异步触发。 但是,如果回调运行或挂起的时间太长,则容器无法达到 running 状态。
PreStop 回调并不会与停止容器的信号处理程序异步执行;回调必须在可以发送信号之前完成执行。 如果 PreStop 回调在执行期间停滞不前,Pod 的阶段会变成 Terminating并且一直处于该状态, 直到其terminationGracePeriodSeconds 耗尽为止,这时 Pod 会被杀死。 这一宽限期是针对 PreStop 回调的执行时间及容器正常停止时间的总和而言的。 例如,如果 terminationGracePeriodSeconds 是 60,回调函数花了 55 秒钟完成执行, 而容器在收到信号之后花了 10 秒钟来正常结束,那么容器会在其能够正常结束之前即被杀死, 因为 terminationGracePeriodSeconds 的值小于后面两件事情所花费的总时间(55+10)。如果 PostStart 或 PreStop 回调失败,它会杀死容器。

;