本页面展示了如何为容器配置存活、就绪和启动探针。
有关探针的更多信息,请参阅 存活、就绪和启动探针。
你需要有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具以与你的集群通信。建议在至少有两个节点的集群上运行本教程,且这些节点不能作为控制平面主机。如果你还没有集群,可以通过 minikube 创建一个,或者使用以下 Kubernetes 演练场之一。
许多长时间运行的应用程序最终会进入故障状态,除了重启外无法恢复。Kubernetes 提供了存活探针来检测并纠正这种情况。
在本练习中,您将创建一个运行 registry.k8s.io/busybox:1.27.2 镜像容器的 Pod。以下是该 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 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 套接字。使用此配置,kubelet 将尝试在指定的端口打开一个连接到您容器的套接字。如果可以建立连接,则认为容器健康;如果不能,则认为失败。
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 将被标记为就绪,并将接收来自服务的流量。如果就绪探针失败,Pod 将被标记为未就绪,且不会接收来自任何服务的流量。
要尝试 TCP 存活检查,请创建一个 Pod
kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml
15 秒后,查看 Pod 事件以验证存活探针
kubectl describe pod goproxy
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 存活检查,请使用以下命令创建一个 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 探针时,需要注意一些技术细节
-tls)。ExecProbeTimeout 特性门控设置为 false,grpc-health-probe 将不遵循 timeoutSeconds 设置(默认为 1s),而内置探针会在超时时失败。您可以为 HTTP 和 TCP 探针使用命名 端口。gRPC 探针不支持命名端口。
例如
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 = 300s)的时间完成启动。一旦启动探针成功一次,存活探针就会接管,以对容器死锁提供快速响应。如果启动探针从未成功,容器将在 300 秒后被终止,并受 Pod 的 restartPolicy 约束。
有时,应用程序会暂时无法提供流量。例如,应用程序在启动期间可能需要加载大量数据或配置文件,或者在启动后依赖外部服务。在这种情况下,您不希望终止应用程序,但也不希望向其发送请求。Kubernetes 提供了就绪探针来检测和缓解这些情况。如果 Pod 的容器报告未就绪,则不会通过 Kubernetes Service 接收流量。
initialDelaySeconds 或 startupProbe。就绪探针的配置方式与存活探针类似。唯一的区别是您使用 readinessProbe 字段代替 livenessProbe 字段。
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
HTTP 和 TCP 就绪探针的配置也与存活探针完全相同。
就绪探针和存活探针可以同时用于同一个容器。同时使用两者可以确保流量不会到达未准备好的容器,并且容器在失败时会重启。