配置存活探针、就绪探针和启动探针
本页面展示如何为容器配置存活探针、就绪探针和启动探针。
有关探针的更多信息,请参阅存活探针、就绪探针和启动探针
存活探针的常见模式是使用与就绪探针相同的低成本 HTTP 端点,但设置更高的 `failureThreshold`。这可以确保 Pod 在被强制终止之前,有一段时间会被观察到处于 NotReady 状态。
kubelet 使用启动探针来确定容器应用程序何时已启动。如果配置了此类探针,则存活探针和就绪探针会延迟到启动探针成功后才会开始,从而确保这些探针不会干扰应用程序启动。这可用于对启动缓慢的容器采用存活检查,避免在它们启动并运行之前被 kubelet 杀死。
注意
存活探针是应用程序失败后一种强大的恢复方式,但应谨慎使用。必须仔细配置存活探针,以确保它们真正指示不可恢复的应用程序故障,例如死锁。说明
存活探针的错误实现可能导致级联故障。这会导致容器在高负载下重启;由于应用程序的可伸缩性降低而导致客户端请求失败;以及由于一些失败的 Pod 导致剩余 Pod 的工作负载增加。理解就绪探针和存活探针之间的区别以及何时将它们应用于你的应用程序。开始之前
定义一个存活命令
许多长时间运行的应用程序最终会进入损坏状态,除非重启否则无法恢复。Kubernetes 提供了存活探针来检测和修复这种情况。
在这个练习中,你将创建一个 Pod,它运行基于 registry.k8s.io/busybox:1.27.2
镜像的容器。以下是该 Pod 的配置文件
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: registry.k8s.io/busybox:1.27.2
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /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
。如果命令成功,返回 0,kubelet 会认为容器是存活且健康的。如果命令返回非零值,kubelet 会杀死容器并重新启动它。
当容器启动时,它会执行此命令
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"
在容器生命周期的前 30 秒内,存在一个 /tmp/healthy
文件。因此,在前 30 秒内,命令 cat /tmp/healthy
返回成功代码。30 秒后,cat /tmp/healthy
返回失败代码。
创建 Pod
kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml
在 30 秒内,查看 Pod 事件
kubectl describe pod liveness-exec
输出表明目前没有存活探针失败
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 11s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulling 9s kubelet, node01 Pulling image "registry.k8s.io/busybox:1.27.2"
Normal Pulled 7s kubelet, node01 Successfully pulled image "registry.k8s.io/busybox:1.27.2"
Normal Created 7s kubelet, node01 Created container liveness
Normal Started 7s kubelet, node01 Started container liveness
35 秒后,再次查看 Pod 事件
kubectl describe pod liveness-exec
在输出的底部,有消息表明存活探针已失败,并且失败的容器已被杀死并重新创建。
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 57s default-scheduler Successfully assigned default/liveness-exec to node01
Normal Pulling 55s kubelet, node01 Pulling image "registry.k8s.io/busybox:1.27.2"
Normal Pulled 53s kubelet, node01 Successfully pulled image "registry.k8s.io/busybox:1.27.2"
Normal Created 53s kubelet, node01 Created container liveness
Normal Started 53s kubelet, node01 Started container liveness
Warning Unhealthy 10s (x3 over 20s) kubelet, node01 Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing 10s kubelet, node01 Container liveness failed liveness probe, will be restarted
再等待 30 秒,然后验证容器已重新启动
kubectl get pod liveness-exec
输出显示 RESTARTS
已递增。请注意,一旦失败的容器恢复到运行状态,RESTARTS
计数器就会递增。
NAME READY STATUS RESTARTS AGE
liveness-exec 1/1 Running 1 1m
定义一个存活 HTTP 请求
另一种存活探针使用 HTTP GET 请求。以下是运行基于 registry.k8s.io/e2e-test-images/agnhost
镜像的容器的 Pod 配置文件。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: registry.k8s.io/e2e-test-images/agnhost:2.40
args:
- liveness
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
在配置文件中,你可以看到 Pod 包含一个容器。periodSeconds
字段指定 kubelet 每 3 秒执行一次存活探针。initialDelaySeconds
字段告诉 kubelet 在执行第一次探针之前应该等待 3 秒。要执行探针,kubelet 向容器中运行的、监听端口 8080 的服务器发送一个 HTTP GET 请求。如果服务器 `/healthz` 路径的处理程序返回成功代码,kubelet 认为容器是存活且健康的。如果处理程序返回失败代码,kubelet 会杀死容器并重新启动它。
任何大于等于 200 且小于 400 的代码表示成功。任何其他代码表示失败。
你可以在 server.go 中查看服务器的源代码。
在容器存活的前 10 秒内,`/healthz` 处理程序返回状态码 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"))
}
})
kubelet 在容器启动 3 秒后开始执行健康检查。因此,最初的几次健康检查会成功。但 10 秒后,健康检查将失败,kubelet 将杀死并重新启动容器。
要尝试 HTTP 存活检查,请创建一个 Pod
kubectl apply -f https://k8s.io/examples/pods/probe/http-liveness.yaml
10 秒后,查看 Pod 事件,验证存活探针是否已失败以及容器是否已重新启动
kubectl describe pod liveness-http
在 v1.13 及之后的版本中,本地 HTTP 代理环境变量设置不影响 HTTP 存活探针。
定义一个 TCP 存活探针
第三种存活探针使用 TCP socket。使用此配置,kubelet 将尝试在指定的端口上打开一个 socket 连接到你的容器。如果能够建立连接,则认为容器是健康的;如果不能,则认为是失败。
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: registry.k8s.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
如你所见,TCP 检查的配置与 HTTP 检查非常相似。此示例同时使用了就绪探针和存活探针。kubelet 将在容器启动 15 秒后运行第一次存活探针。这将尝试连接到端口 8080 上的 goproxy
容器。如果存活探针失败,容器将重新启动。kubelet 将每隔 10 秒继续运行此检查。
除了存活探针之外,此配置还包括就绪探针。kubelet 将在容器启动 15 秒后运行第一次就绪探针。与存活探针类似,它将尝试连接到端口 8080 上的 goproxy
容器。如果探针成功,则 Pod 将被标记为 Ready 并将从 Services 接收流量。如果就绪探针失败,则 Pod 将被标记为 NotReady 并且不会从任何 Services 接收流量。
要尝试 TCP 存活检查,请创建一个 Pod
kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml
15 秒后,查看 Pod 事件,验证存活探针
kubectl describe pod goproxy
定义一个 gRPC 存活探针
Kubernetes v1.27 [稳定]
如果你的应用程序实现了gRPC 健康检查协议,此示例显示了如何配置 Kubernetes 以将其用于应用程序存活检查。类似地,你也可以配置就绪探针和启动探针。
以下是一个示例清单文件
apiVersion: v1
kind: Pod
metadata:
name: etcd-with-grpc
spec:
containers:
- name: etcd
image: registry.k8s.io/etcd:3.5.1-0
command: [ "/usr/local/bin/etcd", "--data-dir", "/var/lib/etcd", "--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"]
ports:
- containerPort: 2379
livenessProbe:
grpc:
port: 2379
initialDelaySeconds: 10
要使用 gRPC 探针,必须配置 port
。如果你想区分不同类型的探针和不同功能的探针,可以使用 service
字段。你可以将 service
设置为 liveness
,并让你的 gRPC 健康检查端点对该请求的响应与将 service
设置为 readiness
时不同。这允许你使用同一个端点进行不同类型的容器健康检查,而不是监听两个不同的端口。如果你想指定自己的自定义服务名称并同时指定探针类型,Kubernetes 项目建议你使用一个将这些组合起来的名称。例如:myservice-liveness
(使用 -
作为分隔符)。
说明
与 HTTP 或 TCP 探针不同,你不能按名称指定健康检查端口,也不能配置自定义主机名。配置问题(例如:不正确的端口或 Service、未实现的健康检查协议)被视为探针失败,类似于 HTTP 和 TCP 探针。
要尝试 gRPC 存活检查,请使用以下命令创建一个 Pod。在下面的示例中,etcd Pod 被配置为使用 gRPC 存活探针。
kubectl apply -f https://k8s.io/examples/pods/probe/grpc-liveness.yaml
15 秒后,查看 Pod 事件,验证存活检查是否未失败
kubectl describe pod etcd-with-grpc
使用 gRPC 探针时,需要注意一些技术细节
- 探针是针对 Pod 的 IP 地址或其主机名运行的。请确保配置你的 gRPC 端点以监听 Pod 的 IP 地址。
- 探针不支持任何身份认证参数(如
-tls
)。 - 内置探针没有错误代码。所有错误都被视为探针失败。
- 如果
ExecProbeTimeout
特性门控设置为false
,grpc-health-probe
不会遵守timeoutSeconds
设置(默认值为 1s),而内置探针会在超时时失败。
使用命名端口
例如
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
使用启动探针保护启动缓慢的容器
有时候,你必须处理那些在第一次初始化时需要额外启动时间的应用程序。在这种情况下,设置存活探针参数可能会很棘手,因为既要快速响应死锁(这是引入这类探针的动机),又要避免在启动过程中误判。解决方案是设置一个启动探针,使用相同的命令、HTTP 或 TCP 检查,并设置一个足够长的 failureThreshold * periodSeconds
,以覆盖最坏情况下的启动时间。
因此,前面的例子将变为
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 1
periodSeconds: 10
startupProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 30
periodSeconds: 10
借助启动探针,应用程序最多有 5 分钟(30 * 10 = 300 秒)完成其启动。一旦启动探针成功一次,存活探针就会接管,以便对容器死锁做出快速响应。如果启动探针从未成功,则容器将在 300 秒后被杀死,并受 Pod 的 restartPolicy
约束。
定义就绪探针
有时候,应用程序暂时无法提供流量。例如,应用程序在启动期间可能需要加载大量数据或配置文件,或者在启动后依赖于外部服务。在这种情况下,你不想杀死应用程序,但也不想向其发送请求。Kubernetes 提供了就绪探针来检测和缓解这些情况。容器报告未就绪的 Pod 不会通过 Kubernetes Services 接收流量。
说明
就绪探针在容器的整个生命周期中运行。注意
就绪探针和存活探针的成功互不依赖。如果你想在执行就绪探针之前等待,应该使用initialDelaySeconds
或 startupProbe
。就绪探针的配置与存活探针类似。唯一的区别是使用 readinessProbe
字段而不是 livenessProbe
字段。
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
HTTP 和 TCP 就绪探针的配置也与存活探针相同。
就绪探针和存活探针可以并行用于同一个容器。同时使用这两种探针可以确保流量不会发送到尚未就绪的容器,并在容器失败时将其重新启动。
配置探针
timeoutSeconds
: 探针超时前等待的秒数。默认为 1 秒。最小值为 1。successThreshold
: 在失败后,探针被视为成功的最小连续成功次数。默认为 1。对于存活探针和启动探针,此值必须为 1。最小值为 1。
注意
就绪探针的错误实现可能会导致容器中进程数量不断增加,如果 unchecked,可能导致资源耗尽。HTTP 探针
host
: 要连接到的主机名,默认为 Pod IP。你可能更想在httpHeaders
中设置 "Host"。scheme
: 连接到主机的协议(HTTP 或 HTTPS)。默认为 "HTTP"。path
: 在 HTTP 服务器上访问的路径。默认为 "/"。httpHeaders
: 在请求中设置的自定义头部。HTTP 允许重复的头部。port
: 容器上要访问的端口名称或端口号。端口号必须在 1 到 65535 范围内。
对于 HTTP 探针,kubelet 会向指定的端口和路径发送 HTTP 请求以执行检查。除非 httpGet
中的可选 host
字段覆盖了地址,否则 kubelet 会将探针发送到 Pod 的 IP 地址。如果 scheme
字段设置为 HTTPS
,kubelet 会发送 HTTPS 请求并跳过证书验证。在大多数情况下,你不需要设置 host
字段。这里有一个你会设置它的场景。假设容器监听 127.0.0.1 并且 Pod 的 hostNetwork
字段为 true
。那么 httpGet
下的 host
应该设置为 127.0.0.1。如果你的 Pod 依赖于虚拟主机(这可能是更常见的情况),则不应使用 host
,而应在 httpHeaders
中设置 Host
头部。
对于 HTTP 探针,kubelet 除了强制性的 Host
头部外,还会发送两个请求头部
User-Agent
: 默认值为kube-probe/1.33
,其中1.33
是 kubelet 的版本。Accept
: 默认值为*/*
。
你可以通过为探针定义 httpHeaders
来覆盖默认头部。例如
livenessProbe:
httpGet:
httpHeaders:
- name: Accept
value: application/json
startupProbe:
httpGet:
httpHeaders:
- name: User-Agent
value: MyUserAgent
你也可以通过将这两个头部定义为空值来移除它们。
livenessProbe:
httpGet:
httpHeaders:
- name: Accept
value: ""
startupProbe:
httpGet:
httpHeaders:
- name: User-Agent
value: ""
说明
当 kubelet 使用 HTTP 探测 Pod 时,只有当重定向指向同一主机时,它才会遵循重定向。如果 kubelet 在探测期间收到 11 次或更多重定向,则认为探针成功并创建一个相关的 Event。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 29m default-scheduler Successfully assigned default/httpbin-7b8bc9cb85-bjzwn to daocloud
Normal Pulling 29m kubelet Pulling image "docker.io/kennethreitz/httpbin"
Normal Pulled 24m kubelet Successfully pulled image "docker.io/kennethreitz/httpbin" in 5m12.402735213s
Normal Created 24m kubelet Created container httpbin
Normal Started 24m kubelet Started container httpbin
Warning ProbeWarning 4m11s (x1197 over 24m) kubelet Readiness probe warning: Probe terminated redirects
如果 kubelet 收到的重定向的主机名与请求不同,则探测结果将被视为成功,并且 kubelet 会创建一个事件来报告重定向失败。
TCP 探针
对于 TCP 探针,kubelet 在节点上进行探测连接,而不是在 Pod 内部,这意味着你不能在 host
参数中使用 Service 名称,因为 kubelet 无法解析它。
探针级别的 terminationGracePeriodSeconds
Kubernetes v1.28 [稳定]
在 1.25 及更高版本中,用户可以在探针规范中指定探针级别的 terminationGracePeriodSeconds
。当 Pod 级别和探针级别的 terminationGracePeriodSeconds
都设置时,kubelet 将使用探针级别的值。
设置 terminationGracePeriodSeconds
时,请注意以下事项
如果 Pod 上存在探针级别的
terminationGracePeriodSeconds
字段,kubelet 总是会遵循该字段。如果你现有的 Pod 设置了
terminationGracePeriodSeconds
字段并且你不再希望使用基于探针的终止宽限期,则必须删除这些现有的 Pod。
例如
spec:
terminationGracePeriodSeconds: 3600 # pod-level
containers:
- name: test
image: ...
ports:
- name: liveness-port
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 1
periodSeconds: 60
# Override pod-level terminationGracePeriodSeconds #
terminationGracePeriodSeconds: 60
探针级别的 terminationGracePeriodSeconds
不能为就绪探针设置。它将被 API 服务器拒绝。
下一步
- 了解更多关于容器探针的信息。
你还可以阅读以下 API 参考文档