配置Pod的liveness和readiness探针
Table of Contents
使用kubernetes的时候,有没有遇到过Pod在启动后一会就挂掉然后又重新启动这样的恶性循环? 有没有想过kubernetes是如何检测pod是否还存活? 虽然容器已经启动,但是kubernetes如何知道容器的进程是否准备好对外提供服务了呢?
Kubelet使用 liveness probe (存活探针)来确定何时 重启容器
例如,当应用程序处于运行状态但无法做进一步操作,liveness探针将捕获到deadlock,重启处于该状态下的容器,使应用程序在存在bug的情况下依然能够继续运行下去(谁的程序还没几个bug呢)
Kubelet使用 readiness probe (就绪探针)来确定容器是否已经就绪可以 接受流量 :
- 只有当Pod中的容器都处于就绪状态时kubelet才会认定该Pod处于就绪状态。该信号的作用是控制哪些Pod应该作为service的后端
- 如果Pod处于非就绪状态,那么它们将会被从service的load balancer中移除
定义 liveness命令
许多长时间运行的应用程序最终会转换到broken状态,除非重新启动,否则无法恢复。Kubernetes提供了liveness probe来检测和补救这种情况
在本次练习将基于 gcr.io/google_containers/busybox镜像创建运行一个容器的Pod
以下是Pod的配置文件exec-liveness.yaml:
apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-exec spec: containers: - name: liveness args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 image: gcr.io/google_containers/busybox livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5
该配置文件给Pod配置了一个容器 periodSeconds 规定kubelet要每隔5秒执行一次liveness probe initialDelaySeconds 告诉kubelet在第一次执行probe之前要的等待5秒钟 探针检测命令是在容器中执行 cat /tmp/healthy 命令 如果命令执行成功,将返回0,kubelet就会认为该容器是活着的并且很健康。如果返回非0值,kubelet就会杀掉这个容器并重启它
容器启动时,执行该命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
在容器生命的最初30秒内有一个 /tmp/healthy 文件,在这30秒内 cat /tmp/healthy命令会返回一个成功的返回码 30秒后, cat /tmp/healthy 将返回失败的返回码
创建Pod:
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/exec-liveness.yaml
在30秒内,查看Pod的event:
$ kubectl describe pod liveness-exec
结果显示没有失败的liveness probe:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 24s 24s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "gcr.io/google_containers/busybox" 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "gcr.io/google_containers/busybox" 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined] 23s 23s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e
启动35秒后,再次查看pod的event:
$ kubectl describe pod liveness-exec
在最下面有一条信息显示liveness probe失败,容器被删掉并重新创建:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 37s 37s 1 {default-scheduler } Normal Scheduled Successfully assigned liveness-exec to worker0 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulling pulling image "gcr.io/google_containers/busybox" 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Pulled Successfully pulled image "gcr.io/google_containers/busybox" 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Created Created container with docker id 86849c15382e; Security:[seccomp=unconfined] 36s 36s 1 {kubelet worker0} spec.containers{liveness} Normal Started Started container with docker id 86849c15382e 2s 2s 1 {kubelet worker0} spec.containers{liveness} Warning Unhealthy Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
再等30秒,确认容器已经重启:
$ kubectl get pod liveness-exec
从输出结果来RESTARTS值加1了:
NAME READY STATUS RESTARTS AGE liveness-exec 1/1 Running 1 1m
定义一个liveness HTTP请求
可以使用 HTTP GET请求 作为liveness probe。下面是一个基于gcr.io/google_containers/liveness镜像运行了一个容器的Pod的例子http-liveness.yaml
apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-http spec: containers: - name: liveness args: - /server image: gcr.io/google_containers/liveness livenessProbe: httpGet: path: /healthz port: 8080 httpHeaders: - name: X-Custom-Header value: Awesome initialDelaySeconds: 3 periodSeconds: 3
该配置文件只定义了一个容器,livenessProbe 指定kubelet需要每隔3秒执行一次liveness probe initialDelaySeconds 指定kubelet在该执行第一次探测之前需要等待3秒钟 该探针将向容器中的server的8080端口发送一个HTTP GET请求 如果server的/healthz路径的handler返回一个成功的返回码,kubelet就会认定该容器是活着的并且很健康 如果返回失败的返回码,kubelet将杀掉该容器并重启它。 任何大于200小于400的返回码都会认定是成功的返回码。其他返回码都会被认为是失败的返回码
最开始的10秒该容器是活着的, /healthz handler返回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将杀掉和重启容器
创建一个Pod来测试一下HTTP liveness检测:
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/http-liveness.yaml
10秒后,查看Pod的event,确认liveness probe失败并重启了容器:
$ kubectl describe pod liveness-http
定义TCP liveness探针
第三种liveness probe使用 TCP Socket 。 使用此配置,kubelet将尝试在指定端口上打开容器的套接字:
- 如果可以建立连接,容器被认为是健康的
- 如果不能就认为是失败的
apiVersion: v1 kind: Pod metadata: name: goproxy labels: app: goproxy spec: containers: - name: goproxy image: gcr.io/google_containers/goproxy:0.1 ports: - containerPort: 8080 readinessProbe: tcpSocket: port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 15 periodSeconds: 20
TCP检查的配置与HTTP检查非常相似。 此示例同时使用了readiness和liveness probe 容器启动后5秒钟,kubelet将发送第一个readiness probe。 这将尝试连接到端口8080上的goproxy容器 如果探测成功,则该pod将被标记为就绪。Kubelet将每隔10秒钟执行一次该检查 除了readiness probe之外,该配置还包括liveness probe,容器启动15秒后,kubelet将运行第一个liveness probe 就像readiness probe一样,这将尝试连接到goproxy容器上的8080端口。如果liveness probe失败,容器将重新启动
使用命名的端口
可以使用命名的ContainerPort作为HTTP或TCP liveness检查:
ports: - name: liveness-port containerPort: 8080 hostPort: 8080 livenessProbe: httpGet: path: /healthz port: liveness-port
定义readiness探针
有时,应用程序暂时无法对外部流量提供服务
例如,应用程序可能需要在启动期间加载大量数据或配置文件,在这种情况下,不能杀死应用程序,但也不能发送请求 Kubernetes提供了readiness probe来检测和减轻这些情况:Pod中的容器可以报告自己还没有准备,不能处理Kubernetes服务发送过来的流量。
Readiness probe的配置跟liveness probe很像。唯一的不同是使用 readinessProbe 而不是livenessProbe
readinessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5
Readiness probe的HTTP和TCP的探测器配置跟liveness probe一样
Readiness和livenss probe可以并行用于同一容器。 使用两者可以确保流量无法到达未准备好的容器,并且容器在失败时重新启动
配置Probe
Probe 中有很多精确和详细的配置,通过它们能准确的控制liveness和readiness检查:
- initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒
- periodSeconds:执行探测的频率
- 默认是10秒
- 最小1秒
- timeoutSeconds:探测超时时间
- 默认1秒
- 最小1秒
- successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功
- 默认是1
- 对于liveness必须是1
- 最小值是1
- failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败
- 默认是3
- 最小值是1
HTTP probe 中可以给 httpGet设置其他配置项:
host:连接的主机名,默认连接到pod的IP
可能想在http header中设置"Host"而不是使用IP
- scheme:连接使用的schema,默认HTTP
- path: 访问的HTTP server的path
- httpHeaders:自定义请求的header。HTTP运行重复的header
- port:访问的容器的端口名字或者端口号。端口号必须介于1和65535之间
对于HTTP探测器,kubelet向指定的路径和端口发送HTTP请求以执行检查 Kubelet将probe发送到容器的IP地址,除非地址被httpGet中的可选host字段覆盖,在大多数情况下,不想设置主机字段 有一种情况下可以设置它:假设容器在127.0.0.1上侦听,并且Pod的hostNetwork字段为true。 然后,在httpGet下的host应该设置为127.0.0.1 如果pod依赖于虚拟主机,这可能是更常见的情况,不应该是用host,而是应该在httpHeaders中设置Host头
Next: Service Account | Home:配置 |