如何排查我的 Amazon EKS 集群的存活和就绪探测问题?
我想解决与我的 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 官方已更新 9 个月前
- AWS 官方已更新 8 个月前
- AWS 官方已更新 2 年前