如何排查我的 Amazon EKS 集群的存活和就绪探测问题?

4 分钟阅读
0

我想解决与我的 Amazon Elastic Kubernetes Service (Amazon EKS) 集群中的存活和就绪探测相关的问题。

简短描述

在工作线程节点上运行的 kubelet 使用探测定期检查 Pod 状态。Kubernetes 目前在探测中支持三种状态:成功、失败和未知。在以下条件下,kubelet 将 Pod 视为成功或运行正常:

  • 在容器内运行的应用程序已准备就绪。
  • 应用程序接受流量并响应 Pod 清单上定义的探测。

当探测没有响应时,kubelet 会将应用程序 Pod 视为失败或运行状况不佳。然后 kubelet 将此 Pod 标记为运行状况不佳并将 SIGTERM 发送到该 Pod。以下任一情况都是根据部署中定义的生命周期策略和 restartPolicy 发生的:

  • Pod 立即终止。
  • Pod 在停止接受流量后正常关闭。

示例:

spec:
 containers:
 - name: "example-container"
  image: "example-image"
  lifecycle:
   preStop:
    exec:
     command: ["sh", "-c", "sleep 10"]

在此示例中,如果在 example-pod 内运行的 example-container 由于未响应探测而变得运行状况不佳,则 Pod 将在 10 秒钟后停止接受流量。然后,kubelet 从容地关闭 Pod。如果 Pod 在 30 秒后仍未终止,kubelet 会强行移除该 Pod。如果无法使用部署清单上定义的探测来确定 Pod 的状态,Kubelet 会将应用程序 Pod 视为未知。在这种情况下,kubelet 会执行额外的检查以确定 Pod 状态。

Kubernetes 提供有关存活探测、就绪探测和启动探测的探测检查。

  • kubelet 使用存活探测来了解在您的 Pod 中运行的应用程序状态。
  • Kubelet 使用就绪探测来了解您的应用程序何时准备好开始处理传入流量。
  • kubelet 使用启动探测来处理容器内缓慢启动的应用程序。配置启动探测时,活跃和就绪探测在认为启动成功之前不会检查 Pod。

如果这些探测均未在 Pod 清单中定义,kubelet 会无限期地将 Pod 标记为成功或运行正常。可以配置以下探测之一来检查 Pod 的运行状况:

  • HTTP 探测
  • 命令探测
  • TCP 套接字探测
  • gRPC 探测

解决方案

由于客户端超时而导致应用程序运行状况检查失败错误

当存活或就绪探测失败时,您会收到以下错误消息:

Liveness probe failed: Get "http://podIP:8080/health ": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

Readiness probe failed: Get "http://podIP:8080/health ": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

要进一步对这些错误进行故障排查,请执行以下操作:

检查您是否正确配置应用程序 Pod 的存活和就绪探测。

如果您使用的是 Amazon Virtual Private Cloud (Amazon VPC) CNI 版本 1.11.0 或更高版本,请务必在 aws-node DaemonSet 中将 POD_SECURITY_GROUP_ENFORCING_MODE 设置为标准。如果此设置不正确,请运行以下命令:

kubectl set env daemonset aws-node -n kube-system POD_SECURITY_GROUP_ENFORCING_MODE=standard

当以下条件成立时,对于 initcontainers 下的容器 amazon-k8s-cni-init,请务必将 DISABLE_TCP_EARLY_DEMUX 设置为 true

  • 您使用的 Amazon VPC CNI 版本早于 1.11.0 版。
  • 您的 Pod 已配置安全组。
  • ENABLE_POD_ENI 设置为 true。
kubectl patch daemonset aws-node -n kube-system \
-p '{"spec": {"template": {"spec": {"initContainers": [{"env":[{"name":"DISABLE_TCP_EARLY_DEMUX","value":"true"}],"name":"aws-vpc-cni-init"}]}}}}'

Amazon VPC CNI 故障错误

您的 aws-node DaemonSet 可能会因以下错误而失败:

Liveness probe failed: OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: read init-p: connection reset by peer: unknown
Warning  Unhealthy  11m (x3 over 12m)    kubelet            Liveness probe failed:
Normal   Killing    11m                  kubelet            Container aws-node failed liveness probe, will be restarted

Readiness probe failed: OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: process_linux.go:99: starting setns process caused: fork/exec /proc/self/exe: resource temporarily unavailable: unknown
Warning  Unhealthy  11m (x9 over 13m)    kubelet            Readiness probe failed:

可以通过在 aws-node DaemonSet 上将 timeoutSeconds 的值增加到 60 秒来解决这些错误。

要查看 VPC CNI 中字段的当前值,请运行以下命令:

$kubectl get daemonset aws-node -n kube-system -o yaml

输出与以下内容类似:

"livenessProbe":
          exec:
            command:
            - /app/grpc-health-probe
            -addr=:50051
            -connect-timeout=5s
            -rpc-timeout=5s
          failureThreshold: 3
          initialDelaySeconds: 60
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 60

应用程序连接错误

当你在自定义应用程序 Pod 上运行 describe 命令时,如果 Pod 未通过存活和就绪探测,则会出现以下错误:

2m 25s Warning  Unhealthy  Liveness probe failed: Get "http://podIP:8081/health ": dial tcp 192.168.187.28: 8081: connect: connection refused

2m 25s Warning  Unhealthy   Readiness probe failed: Get "http:// podIP:8081/health": dial tcp 192.168.187.28:8081: connect: connection refused

Warning  Unhealthy  39s (x4 over 2m19s)  kubelet            Liveness probe failed: HTTP probe failed with statuscode: 500

Warning  Unhealthy  29s (x5 over 2m19s)  kubelet            Readiness probe failed: HTTP probe failed with statuscode: 500

要排查此错误,请执行以下操作:

1.    从工作线程节点对在 Pod 清单上定义的运行状况检查路径执行 curl 命令。

[ec2-user@ip-10-0-0-11 ~]$ curl -ikv podIP:8081/health

2.    在未通过存活或就绪探测的应用程序容器中执行 Exec 命令。然后,对 Pod 清单上定义的运行状况检查路径执行 curl 命令:

local@bastion-host ~ % kubectl exec <pod-name> -- curl  -ikv "http://localhost:8081/_cluster/health?"

3.    检查 Pod 正在其中运行的工作线程节点的 kubelet 日志中是否存在任何错误:

[ec2-user@ip-10-0-0-11 ~]$ journalctl -u kubelet //optionally 'grep' with pod name

4.    在 Pod 上运行 describe pod 命令并检查 Pod 中正在运行的容器的当前状态。另外,请查看 Pod 日志:

$ kubectl describe pod <pod name> -n <namespace>

$ kubectl logs <pod name>

5.    如果仍然没有关于错误的信息,那么可以考虑增加在工作线程节点上运行的底层 kubelet 的详细程度:

$ sudo systemctl status kubelet
$ vi /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf 
   [Service]
   Environment='KUBELET_ARGS=--node-ip=192.168.31.211 --pod-infra-container-image=602401143452.dkr.ecr.us-east-2.amazonaws.com/eks/pause:3.5 --v=2'

在配置文件中,将 --v=2 更改为 --v=9,然后保存该文件。

重新启动 kubelet 以使更改生效:

$ sudo systemctl daemon-reload && sudo systemctl restart kubelet && sudo systemctl enable kubelet

运行以下命令来检查 kubelet 的详细程度:

$ systemctl status kubelet -l

输出必定类似于以下内容:

CGroup: /system.slice/kubelet.service 
       └─5909 /usr/bin/kubelet --cloud-provider aws --config /etc/kubernetes/kubelet/kubelet-config.json --kubeconfig /var/lib/kubelet/kubeconfig --container-runtime docker --network-plugin cni --node-ip=10.0.0.11 --pod-infra-container-image=602401143452.dkr.ecr.us-east-1.amazonaws.com/eks/pause:3.1-eksbuild.1 --v=9

重新启动存活或就绪检查失败的 Pod。然后,确保将此 Pod 部署在进行上述更改的 Amazon EKS 工作线程节点上。您可以通过运行以下命令来检查 kubelet 日志:

$ journalctl -u kubelet //optionally 'grep' with pod name

6.    在堡垒主机上运行相同的容器映像,并检查是否可以在清单中的探测定义的运行状况检查路径执行 curl 命令。另外,请查看容器日志。

7.    对于 HTTP 探测,请检查自定义 http 标头的配置是否正确。Kubelet 使用相当于 curl 命令的 golang 代码来测试您的 Pod。

示例:

"livenessProbe":
   httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3

8.    如果使用的是 exec 探测,请检查您的 Pod 配置是否正确。在以下示例中,Pod 通过测试 30 秒,然后失败:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/busybox
    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

AWS 官方
AWS 官方已更新 2 年前