在Kubernetes中,可以为Pod里的容器定义一个健康检查探针(Probe),这样Kubernetes会根据这个Probe的返回值决定这个容器的状态,而不是直接以容器是否允许(来自Docker返回的信息)作为依据。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: test-liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
这个Pod的容器在启动之后做的第一件事是在/tmp目录下创建一个healthy文件,以此作为自己已经正常运行的标识,而30s过后它会把这个文件删除掉。同时还定义了一个livenessProbe,类型是exec,它会在容器启动后执行指定的命令:“cat /tmp/healthy”,如果这个文件存在,这条命令返回值就是0,Pod就会认为这个容器不仅已经启动,而且是健康的,这个健康检查在启动5s后开始执行,每5s执行一次。
$ kubectl create -f test-liveness-exec.yaml
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
test-liveness-exec 1/1 Running 0 10s
####30s后
$ kubectl describe pod test-liveness-exec
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
2s 2s 1 {kubelet worker0} spec.containers{liveness} Warning Unhealthy Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
$ kubectl get pod test-liveness-exec
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
可以看到,健康检查报告容器不健康,但是Pod保存了running状态,这是为什么呢?
认真看可以发现。RESTARTS字段已经变成1了,即这个异常的容器已经被Kubernetes重启了,在这个过程中,Pod保存Running状态不变。Kubernetes没有Docker的Stop语义,所以虽然是重启,实际却是重新创建了容器,这个功能就是Kubernetes里的Pod恢复机制(restartPolicy),它是Pod的Spec部分的一个标准字段(pod.spec.restartPolicy),默认值为Always,作为用户可以设置Pod的恢复策略
- Always:任何情况下,只要容器不在运行状态,就自动重启容器(合理设置,如果只计算1+1=2,计算完成后退出,强制重启毫无意义)
- OnFailure:只在容器异常时才自动重启容器
- Never:从来不重启容器(如要关心容器退出后的日志、文件和目录,就需要设置为NEVER,否则可能丢失)
Pod的恢复过程,永远都是发送在当前节点上,而不会跑到别的节点上去,即如果这个宿主机宕机了,这个pod也不会主动迁移到其他节点上去。如果想让Pod出现在其他可用节点上,就必须用Deployment这样的控制器来管理Pod。
Kubernetes中restartPolicy和Pod里容器的状态以及Pod状态的对应关系的基本设计原理有两个:
- 只要Pod的restartPolicy指定的策略允许重启异常的容器(如Always),那么这个Pod就会保持running状态,并进行容器重启,否则Pod会进入Failed状态。
- 对于包含多个容器的Pod,只有它里面所有的容器都进入异常状态后,Pod才会进入Failed状态,在此之前,Pod都是running状态,此时Pod的REDY字段会显示正常容器的个数。
所以假如一个Pod里只有一个容器,然后这个容器异常退出了,那么只有当restartPolicy=Never时,这个Pod才会进入Failed状态,而其他情况下,由于kubernetes都可以重启这个容器,所以Pod状态保持running不变。如果这个Pod有多个容器,仅有一个容器异常退出,它始终保持Running状态,哪怕即使restartPolicy=Never,也只有当容器也异常退出之后,这个Pod才会进入Failed状态。
除了在容器中执行命令外,livenessProbe也可以定义为发起HTTP或者TCP请求的方式,定义格式如下:
...
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
...
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20