在 Kubernetes
中Pod
是容器管理的最小单位, 有着各种各样的Pod
管理器. 那么一个Pod
从启动到释放, 在这期间经历了哪些过程呢?
Pod
自开始创建, 到正常运行, 再到释放, 其时间跨度及经历的阶段大致如下:
说一下各个阶段的作用以及是为了解决什么问题. 容器调度和下载镜像的过程就忽略了, 也没什么好说的.
init
在Pod
启动一个容器时, 可以有一组init
容器先行启动(当然也可以没有), 这些init
容器会依次执行, 且前一个成功之后, 后一个才会执行. 同时还会监控init
容器的退出状态, 若init
容器异常退出, 则会根据配置restartPolicy
的重启策略选择重新启动或退出(这里的退出, 说明Pod
启动失败了). 通过配置文件的pod.spec.initContainers
进行配置, 其配置项与containers
相同
init
容器可应用与如下场景:
- 可以将服务的创建和部署进行解耦. 以防止主容器过于臃肿
- 检测依赖. 比如服务 A 必须要等服务 B 启动成功之后才能运行, 那么就可以在服务 A 的 init 阶段进行循环检测等待, 直到服务 B 启动成功了, 才开始启动服务 A
- 具有访问
Secret
的权限.Secret
是用来存储一些敏感数据的, 会进行加密处理. 主容器是没有权限访问的, 这也很好理解, 如果一个容器被攻破了, 如果能够拿到Secret
的数据, 很可能会导致一串服务都被攻破. 而init
容器在Pod
提供服务之前就退出了, 可以提高数据的安全. - 等等
Pod
在init
容器启动完成之前, 是不会对外提供服务的, 其状态一直为Pending
start/stop
容器启动和释放时运行的钩子. 通过配置文件的pod.spec.containers.lifecycle.postStart
和pod.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
探测失败后, 会导致容器重启, 因此liveness
的initialDelaySeconds
配置就需要稍微花点心思了, 要延时一些时间, 等待服务启动成功后再开始. 否则可能导致readiness
还没有完成探测任务, 就被liveness
探测失败而重启了.
startup
上面说liveness
与readiness
是同时运行的, 通过配置liveness
的initialDelaySeconds
参数来等待. 但对于一些服务, 我们并不能确定其启动需要多久呀, 如果一味延长等待时间就太不划算了.
而startup
就是为了解决liveness
与readiness
执行顺序的问题, 将服务就绪探测和服务的存活探测彻底分开. 定义在配置文件的pod.spec.containers.startupProbe
位置, 探针项与readiness
相同.
startup
探针会在探测成功后, 再将探测任务交由后续的探测任务. 默认success
所以一般使用liveness
和startup
配合探测即可, readiness
貌似没有什么用武之地了.