配置存活、就绪和启动探针

本页面展示了如何为容器配置存活、就绪和启动探针。

有关探针的更多信息,请参阅 存活、就绪和启动探针

开始之前

你需要有一个 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 只有一个 ContainerperiodSeconds 字段指定 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 套接字。使用此配置,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

定义 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 存活检查,请使用以下命令创建一个 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),而内置探针会在超时时失败。

使用命名端口

您可以为 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 接收流量。

说明

就绪探针在容器的整个生命周期内运行。

注意

就绪探针和存活探针的成功互不依赖。如果您想在执行就绪探针之前等待,请使用 initialDelaySecondsstartupProbe

就绪探针的配置方式与存活探针类似。唯一的区别是您使用 readinessProbe 字段代替 livenessProbe 字段。

readinessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5

HTTP 和 TCP 就绪探针的配置也与存活探针完全相同。

就绪探针和存活探针可以同时用于同一个容器。同时使用两者可以确保流量不会到达未准备好的容器,并且容器在失败时会重启。

接下来


最后修改时间 2026 年 4 月 6 日 23:14 PST:删除概念解释 (69c3a7e993)