在Kubernetes
集群当中,我们可以通过配置liveness probe
(存活探针)和readiness probe
(可读性探针)来影响容器的生存周期。
探针分类
其是kubelet对容器周期性执行的健康状态诊断,诊断操作由容器的处理器(handler)进行定义。kubernetes 支持三种处理器用于Pod探测
ExecAction :在容器中执行一个命令,并根据其返回的状态码进行针对的操作成为exec探测,状态码为0表示成功,否则为不健康状态
TCPsocketAction:通过与容器的某TCP端口尝试建立连接进行诊断,端口能够成功打开及为正常,否则为不健康状态
httpGetAction:通过向容器IP地址的某指定端口的指定path 发HTTP GET 请求进行诊断,响应码为2xx或3xx即为成功,否则为失败。
任何一种探测都有三种结果: success (成功)、failure (失败)或 unknown (未知),只有第一种为正常
存活性探测:判定是否处于运行状态,一旦此类检测为通过,则kubelet 将杀死容器并根据其restartPlicy 决定是否将其重启,未定义存活性检测到的容器默认状态为”sucess”。
就绪性探测:用于判断容器是否准备就绪并可对外提供服务,未通过检测的容器意味着尚未准备就绪,端点控制器会将其IP从所有匹配到此Pod对象的service对象的端点列表中移除,检测通过后,会再次将其IP添加到端点列表中。
容器的重启策略
容器程序发生崩溃或者容器申请超出限制的资源等原因都会导致POD 对象的终止,此时是否应该重建该POD对象取决于其重启策略
1 always:但凡Pod对象终止就将其重启,此为默认设定
2 onfailure:仅在容器出现错误时将其重启
3 Never :从不重启
Startup Probe
k8s1.16版本后新加的探测方式,用于判断容器内应用程序是否启动,如果设置了startupProbe 就会先禁止其他的探测,直到它成功为止,成功后就不在进行探测
liveness probe
kubelet 通过使用 liveness probe 来确定你的应用程序是否正在运行,通俗点将就是是否还活着。一般来说,如果你的程序一旦崩溃了, Kubernetes 就会立刻知道这个程序已经终止了,然后就会重启这个程序。而我们的 liveness probe 的目的就是来捕获到当前应用程序还没有终止,还没有崩溃,如果出现了这些情况,那么就重启处于该状态下的容器,使应用程序在存在 bug 的情况下依然能够继续运行下去。
kubelet使用活跃度探头知道什么时候重新启动的容器。例如,liveness probe可以捕获死锁,应用程序正在运行,但无法取得进展。在这种状态下重新启动容器可以继续存活。
readiness probe
kubelet 使用 readiness probe 来确定容器是否已经就绪可以接收流量过来了。这个探针通俗点讲就是说是否健康了,现在可以开始工作了。只有当 Pod 中的容器都处于就绪状态的时候 kubelet 才会认定该 Pod 处于就绪状态,因为一个 Pod 下面可能会有多个容器。当然 Pod 如果处于非就绪状态,那么我们就会将他从我们的工作队列(实际上就是我们后面需要重点学习的 Service)中移除出来,这样我们的流量就不会被路由到这个 Pod 里面来了。
使用readiness probe来了解容器何时准备开始接受流量。当所有容器准备就绪时,Pod被认为已准备就绪。此信号的一个用途是控制哪些Pod用作服务的后端。当Pod未就绪时,它将从服务负载平衡器中删除。例如当一个应用服务有大文件加载时,这种情况下不允许接受用户访问,readiness probe就不会对这类型的程序启动服务。
Pod健康检查
有不少应用程序长时间持续运行后会逐渐转为不可用状态,并且仅能通过重启回复,kubernetes 的容器存活性机制可发现此类问题,并依据探测结果结合重启策略触发过后需的行为,存活型探测是容器级别的配置,kubelet可基于他判断何时需要重启一个容器。
查询命令 kubectl explain pods.spec.containers.livenessProbe
存活性探测
查询命令: kubectl explain pods.spec.containers.livenessProbe
failureThreshold : 处于成功状态时,探测操作至少连续多少次的失败才被认为是检测不通过,默认是3次,最少是1次 initialDelaySeconds:存活性探测延迟时长,及容器启动多久后再开始第一次探测操作,显示为delay,默认为0秒,及容器启动后立刻便开始进行探测 periodSeconds:存活性探测的频度,显示为period,默认是10s,最小值也是1s。 successThreshold:处于失败状态时,探测操作至少连续多少次的成功才被认为是通过检测,显示为#success属性,默认值为1,最小是1. timeoutSeconds:存活性探测的超时时长,显示为timeout属性,默认为1s,最小为1s。
就绪性探测
因避免POD 对象启动后立即让其处理客户端请求,而是等待容器初始化工作执行完成并转为”就绪”状态再进行处理,便出现了就绪性探测 与存活性探测机制类似,就绪性探测是用来判断容器就绪与否的周期性操作,它用于探测容器是否已经初始化完成并可服务与客户端请求,探测操作返回success状态,即为传递容器已经”就绪”的信号。 与存活性探测机制相同,就绪性探测也支持EXEC、HTTPGET 和 TCP socket 三种探测方式,且各自定义机制相同,但与存活性探测不同的是,就绪性探测不会杀死或重启重启以保证其健康性,而是通知其尚未就绪,并触发以来与其就绪状态的操作,以确保不会有客户端请求接入此POD对象,不过,即便在运行过程中,Pod就绪性探测依然有存在的价值。
实例:
apiVersion: v1
kind: Pod
metadata:
name: test5
spec:
containers:
- name: test5
image: busybox
args: ["/bin/sh","-c","while true; do rm -rf /tmp/aaa; sleep 30 ;touch /tmp/aaa;sleep 40; done"]
readinessProbe:
exec:
command: ["test","-e","/tmp/aaa"]
initialDelaySeconds: 5
periodSeconds: 5
探测方法
许多运行很长时间的应用程序最终会转换到损坏状态,除非重新启动,否则无法恢复。Kubernetes提供活体探测器来检测和纠正这种情况。
ExecAction
通过busybox来练习一下liveness probe
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: 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具有单个Container。该periodSeconds
字段指定kubelet应每5秒执行一次活跃度探测。该initialDelaySeconds
字段告诉kubelet它应该在执行第一次探测之前等待5秒。要执行探测,kubelet将cat /tmp/healthy
在Container中执行命令。如果命令成功,则返回0,并且kubelet认为Container是活动且健康的。如果该命令返回非零值,则kubelet会终止Container并重新启动它。
当Container启动时,它会执行以下命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
在Container的生命的前30秒,有一个/tmp/healthy
文件。因此,在前30秒内,该命令cat /tmp/healthy
返回成功代码。30秒后,cat /tmp/healthy
返回失败代码。
创建Pod:
kubectl apply -f liveness-exec.yaml
在30秒内,查看Pod事件:
kubectl describe pod liveness-exec
HTTPGetAction
相关配置字段
host
port
httpHeaders<[]Object>: 自定义的请求报文首部
path
scheme: 建立连接使用的协议,仅可以是HTTP或HTTPS,默认是HTTP
另一种活动探测器使用HTTP GET请求
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: baxiang/liveness:1.0
livenessProbe:
httpGet:
path: /healthz
port: 8090
initialDelaySeconds: 3
periodSeconds: 3
在配置文件中,您可以看到Pod具有单个Container。该periodSeconds
字段指定kubelet应每3秒执行一次活跃度探测。该initialDelaySeconds
字段告诉kubelet它应该在执行第一次探测之前等待3秒。为了执行探测,kubelet向在Container中运行的服务器发送HTTP GET请求并侦听端口8080.如果服务器/healthz
路径的处理程序返回成功代码,则kubelet认为Container是活动且健康的。如果处理程序返回失败代码,则kubelet会终止Container并重新启动它。
任何大于或等于200且小于400的代码表示成功。任何其他代码表示失败。
您可以在server.go中查看服务器的源代码 。
对于Container /healthz
处于活动状态的前10秒,处理程序返回状态200.之后,处理程序返回状态500。
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
duration := time.Now().Sub(started)
if duration.Seconds() > 10 {
w.WriteHeader(500)
w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
} else {
w.WriteHeader(200)
w.Write([]byte("ok"))
}
})
在容器启动3秒后,kubelet开始执行运行状况检查。因此,前几次健康检查将成功。但是10秒后,运行状况检查将失败,并且kubelet将终止并重新启动Container。
要尝试HTTP活跃度检查,请创建一个Pod:
kubectl apply -f liveness-http.yaml
10秒后,查看Pod事件以验证活动探测失败并且Container已重新启动:
kubectl describe pod liveness-http
在v1.13之前的版本(包括v1.13)中,如果在运行pod的节点上设置了环境变量http_proxy(或HTTP_PROXY
),则HTTP活动探针将使用该代理。在v1.13之后的版本中,本地HTTP代理环境变量设置不会影响HTTP活动探测。
$ kubectl describe pod/liveness-http
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3d10h default-scheduler Successfully assigned default/liveness-http to k8s-node1
Normal Pulled 3d10h (x3 over 3d10h) kubelet Container image "baxiang/liveness:1.0" already present on machine
Normal Created 3d10h (x3 over 3d10h) kubelet Created container liveness
Normal Started 3d10h (x3 over 3d10h) kubelet Started container liveness
Normal Killing 3d10h (x2 over 3d10h) kubelet Container liveness failed liveness probe, will be restarted
Warning Unhealthy 3d10h (x7 over 3d10h) kubelet Liveness probe failed: HTTP probe failed with statuscode: 500
$ kubectl get pod -l test=liveness
NAME READY STATUS RESTARTS AGE
liveness-http 1/1 Running 5 2m9s
TCPSocketAction
第三种类型的活动探测器使用TCP套接字。使用此配置,kubelet将尝试在指定端口上打开容器的套接字。如果它可以建立连接,则容器被认为是健康的,如果它不能被认为是失败的话。
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: cnych/goproxy
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
我们可以看到,TCP 检查的配置与 HTTP 检查非常相似,只是将httpGet
替换成了tcpSocket
。 而且我们同时使用了readiness probe
和liveness probe
两种探针。 容器启动后5秒后,kubelet
将发送第一个readiness probe
(可读性探针)。 该探针会去连接容器的8080端,如果连接成功,则该 Pod 将被标记为就绪状态。然后Kubelet
将每隔10秒钟执行一次该检查。
除了readiness probe
之外,该配置还包括liveness probe
。 容器启动15秒后,kubelet
将运行第一个 liveness probe
。 就像readiness probe
一样,这将尝试去连接到容器的8080端口。如果liveness probe
失败,容器将重新启动。
有的时候,应用程序可能暂时无法对外提供服务,例如,应用程序可能需要在启动期间加载大量数据或配置文件。 在这种情况下,您不想杀死应用程序,也不想对外提供服务。 那么这个时候我们就可以使用readiness probe
来检测和减轻这些情况。 Pod中的容器可以报告自己还没有准备,不能处理Kubernetes服务发送过来的流量。
从上面的YAML
文件我们可以看出readiness probe
的配置跟liveness probe
很像,基本上一致的。唯一的不同是使用readinessProbe
而不是livenessProbe
。两者如果同时使用的话就可以确保流量不会到达还未准备好的容器,准备好过后,如果应用程序出现了错误,则会重新启动容器。
检测参数
initialDelaySeconds 初始化时间
periodSeconds 检测间隔
另外除了上面的initialDelaySeconds
和periodSeconds
属性外,探针还可以配置如下几个参数:
- timeoutSeconds:探测超时的秒数。默认为1秒。最小值为1。
- initialDelaySeconds:启动活动或准备就绪探测之前容器启动后的秒数。
- periodSeconds:执行探测的频率(以秒为单位)。默认为10秒。最小值为1。
- failureThreshold:当Pod启动并且探测失败时,Kubernetes会failureThreshold在放弃之前尝试一次。在活动探测的情况下放弃意味着重新启动Pod。如果准备好探测,Pod将被标记为未准备好。默认为3.最小值为1。
- successThreshold:失败后探测成功的最小连续成功次数。默认为1.活跃度必须为1。最小值为1。
[HTTP探针] 具有可以设置的其他字段httpGet
:
host
:要连接的主机名,默认为pod IP。您可能希望在httpHeaders中设置“主机”。scheme
:用于连接主机的方案(HTTP或HTTPS)。默认为HTTP。path
:HTTP服务器上的访问路径。httpHeaders
:要在请求中设置的自定义标头。HTTP允许重复标头。port
:容器上要访问的端口的名称或编号。数字必须在1到65535的范围内。
对于HTTP探测,kubelet将HTTP请求发送到指定的路径和端口以执行检查。kubelet将探测器发送到pod的IP地址,除非地址被可选host
字段覆盖httpGet
。如果 scheme
字段设置为HTTPS
,则kubelet会发送跳过证书验证的HTTPS请求。在大多数情况下,您不希望设置该host
字段。这是您设置它的一个场景。假设Container侦听127.0.0.1并且Pod的hostNetwork
字段为true。然后host
,在httpGet
,应设置为127.0.0.1。如果您的pod依赖虚拟主机,这可能是更常见的情况,您不应该使用host
,而是设置Host
标头httpHeaders
。
对于探测器,kubelet在节点处而不是在pod中进行探测连接,这意味着您无法在host
参数中使用服务名称,因为kubelet无法解析它。
POD 健康检查方法
1 execAction
exec 类型的探针通过在目标容器中执行由用户自定义的命令来判定容器的建康状态,若命令返回为0则表示其成功,其只有一个可用的command 命令,用于指定要执行的命令。
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
上述实例中启用了一个创建文件的操作和删除文件后探测的操作,
$kubectl describe pod test-liveness-exec
查看其中的Events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 90s default-scheduler Successfully assigned default/test-liveness-exec to docker-desktop
Warning Unhealthy 43s (x3 over 53s) kubelet, docker-desktop Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing 43s kubelet, docker-desktop Container liveness failed liveness probe, will be restarted
Normal Pulling 13s (x2 over 89s) kubelet, docker-desktop Pulling image "busybox"
Normal Pulled 9s (x2 over 86s) kubelet, docker-desktop Successfully pulled image "busybox"
Normal Created 9s (x2 over 86s) kubelet, docker-desktop Created container liveness
Normal Started 9s (x2 over 86s) kubelet, docker-desktop Started container liveness
查看重启次数
$kubectl get pod
NAME READY STATUS RESTARTS AGE
test-liveness-exec 1/1 Running 2 3m3s
在此处被kill了,其原因是由于存活探测无法成功导致的kill掉,而后重新拉去后创建,又进行探针探测
2 设置HTTP探针
其目的是向目标服务器发送一个HTTP请求,若返回为2XX和3XX则表示检测通过,否则为检测不通过,相关字段如下所示 : kubectl explain pods.spec.containers.livenessProbe.httpGet 相关配置字段 host
: 请求的主机地址,默认是PodIP地址, port :请求的端口,必选字段 httpHeaders<[]Object>: 自定义的请求报文首部 path : 请求的HTTP资源路径,及URL path scheme: 建立连接使用的协议,仅可以是HTTP或HTTPS,默认是HTTP
apiVersion: v1
kind: Pod
metadata:
name: nginx-liveness
labels:
name: nginx-liveness
spec:
containers:
- name: nginx-liveness
image: nginx:1.14
lifecycle:
postStart:
exec:
command: ["/bin/sh","-c","echo OK > /usr/share/nginx/html/health"]
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
livenessProbe:
httpGet:
port: 80
path: /health
查看结果
Liveness: http-get http://:80/health delay=0s timeout=1s period=10s #success=1
删除对应文件
kubectl exec nginx-liveness rm /usr/share/nginx/html/health
kubectl describe pod/nginx-liveness
结果
---- ------ ---- ---- -------
Normal Scheduled 3d10h default-scheduler Successfully assigned default/nginx-liveness to k8s-node1
Normal Pulled 3d10h kubelet Container image "nginx:1.14" already present on machine
Normal Created 3d10h kubelet Created container nginx-liveness
Normal Started 3d10h kubelet Started container nginx-liveness
Warning Unhealthy 3d10h kubelet Liveness probe failed: HTTP probe failed with statuscode: 404
一般的HTTP类型的探测操作应当针对专用URL路径进行处理,其仅能检测应用程序工作正常与否,但重启操作却无法解决其后端服务导致的故障(如数据库和缓存服务),此时,容器可能会被一次次重启,直到后端服务恢复正常为止,其余两种检测方式也存在类似问题。
3 设置TCP探针
基于TCP 的存活性检测用于向容器的特定端口发起TCP请求并尝试建立连接进行结果判定,连接建立成功即为通过检测,其更高效,但其精准度略低,建立连接成功并不意味着可用
kubectl explain pods.spec.containers.livenessProbe.tcpSocket
相关关键字 1 host :请求连接的目标IP地址,默认是POD ip 2 post: 请求连接的目标端口,必选字段
apiVersion: v1
kind: Pod
metadata:
name: test2
spec:
containers:
- name: test2
image: nginx:1.12-alpine
livenessProbe:
tcpSocket:
port: 80
查看结果
参考
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/