Kubernetes中Pod生命周期

KubernetesPod是容器管理的最小单位, 有着各种各样的Pod管理器. 那么一个Pod从启动到释放, 在这期间经历了哪些过程呢?

Pod自开始创建, 到正常运行, 再到释放, 其时间跨度及经历的阶段大致如下:

image-20211218110404250

说一下各个阶段的作用以及是为了解决什么问题. 容器调度和下载镜像的过程就忽略了, 也没什么好说的.

init

Pod启动一个容器时, 可以有一组init容器先行启动(当然也可以没有), 这些init容器会依次执行, 且前一个成功之后, 后一个才会执行. 同时还会监控init容器的退出状态, 若init容器异常退出, 则会根据配置restartPolicy的重启策略选择重新启动或退出(这里的退出, 说明Pod启动失败了). 通过配置文件的pod.spec.initContainers进行配置, 其配置项与containers相同

init容器可应用与如下场景:

  • 可以将服务的创建和部署进行解耦. 以防止主容器过于臃肿
  • 检测依赖. 比如服务 A 必须要等服务 B 启动成功之后才能运行, 那么就可以在服务 A 的 init 阶段进行循环检测等待, 直到服务 B 启动成功了, 才开始启动服务 A
  • 具有访问Secret的权限. Secret是用来存储一些敏感数据的, 会进行加密处理. 主容器是没有权限访问的, 这也很好理解, 如果一个容器被攻破了, 如果能够拿到Secret的数据, 很可能会导致一串服务都被攻破. 而init容器在Pod提供服务之前就退出了, 可以提高数据的安全.
  • 等等

Podinit容器启动完成之前, 是不会对外提供服务的, 其状态一直为Pending

start/stop

容器启动和释放时运行的钩子. 通过配置文件的pod.spec.containers.lifecycle.postStartpod.spec.containers.lifecycle.preStop进行配置. 配置相同, 这里用postStart举例了. 具体配置可通过kubectl explain pod.spec.containers.lifecycle.postStart查看, 官方文档很详细.

注意 preStop事件结束之后, 才会向容器中的主进程发送停止信号

# 执行一组命令
postStart: 
  command: ["/bin/sh", "-c", "sleep 1"]
---
# 调用 http 接口通知
postStart: 
  host: baidu.com
  path: /start
  port: 80

readiness

既就绪探针. 检测容器中的服务是否已经启动成功并可以对外提供访问了. 只有检测成功后, 才会将状态改为就绪状态(Running). 定义在配置文件的pod.spec.containers.readinessProbe位置. 默认success

注意, 在新版k8s中, readiness运行周期与liveness相同, 区别是探测失败时的处理方式不同. readiness探测失败时不在向该pod发送流量, liveness探测失败时会重启pod

readiness是为了解决服务的启动时间问题, 比如容器已经启动成功了, 但是提供服务的进程还没有启动完毕, 此时对外提供服务的话就会有问题. Kubernetes提供了如下三种探针:

  • ExecAction: 在容器中执行指定命令. 若命令返回0, 则成功
  • TCPSocketAction: 对指定端口进行 TCP 检查, 若端口开放, 则认为成功
  • HTTPGetAction: 对指定端口进行 HTTP Get 请求, 若响应码区间为[200, 400), 则认为成功

其配置文件大致如下:

# 命令探针
readinessProbe: 
  exec: 
    command: ["cat", "/tmp/file"]
  # 以下这些字段为通用字段, 下面不再重复

  # 探针失败的最大重试次数, 超过这个次数则认为本次探测失败, 容器启动失败. 默认3
  failureThreshold: 3
  # 探测的循环周期, n秒后进行下一次探测. 与 failureThreshold 配合确定启动时间. 默认10s
  periodSeconds: 1
  # 执行第一次探测前需要等待5s. 默认0s
  initialDelaySeconds: 5
  # 探测超时时间. 默认1s
  timeoutSeconds: 1
  # 当探测失败后, 需要连续探测成功3次才认为成功. 默认1
  successThreshold: 3
  # 当探测失败后, 优雅释放可等待的时间. 超过则会被强制释放
  terminationGracePeriodSeconds: 5
---
# tcp 探针
readinessProbe: 
  tcpSocket: 
    host: baidu.com
    port: 80
---
# http 探针
readinessProbe: 
  httpGet: 
    host: baidu.com
    path: /
    port: 80
    # 设置请求的 header, 是个对象数组
    httpHeaders: 
      - name: headerName
        value: headerValue
    # 请求方式. HTTP 或 HTTPS. 默认 HTTP
    scheme: HTTP

liveness

既存活探测, 在容器执行的这段时间, 探测容器是否存活, 若已经无法提供服务, 则需要重启容器. 定义在配置文件的pod.spec.containers.livenessProbe位置. 其配置项与readiness相同, 不再赘述. 默认success

在容器运行过程中, 可能容器还活着, 但里面提供服务的进程已经死了(例如死锁). 这时容器其实已经无法对外提供服务了. 需要这样一种机制来检测是否还能正常提供服务.

注意, liveness并不是在readiness探测完毕后才会启动.而是几乎同时启动, 而liveness探测失败后, 会导致容器重启, 因此livenessinitialDelaySeconds配置就需要稍微花点心思了, 要延时一些时间, 等待服务启动成功后再开始. 否则可能导致readiness还没有完成探测任务, 就被liveness探测失败而重启了.

startup

上面说livenessreadiness是同时运行的, 通过配置livenessinitialDelaySeconds参数来等待. 但对于一些服务, 我们并不能确定其启动需要多久呀, 如果一味延长等待时间就太不划算了.

startup就是为了解决livenessreadiness执行顺序的问题, 将服务就绪探测和服务的存活探测彻底分开. 定义在配置文件的pod.spec.containers.startupProbe位置, 探针项与readiness相同.

startup探针会在探测成功后, 再将探测任务交由后续的探测任务. 默认success

所以一般使用livenessstartup配合探测即可, readiness貌似没有什么用武之地了.

订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请发表评论。x