【图解】Kubernetes Deployment 故障排查指南
来源:K8sMeetup社区
太长不看版:下面这张图可以帮助你调试 Kubernetes 中的 Deployment。 

Deployment:创建 Pod 副本的方法; Service:内部负载均衡器,将流量路由到 Pod; Ingress:描述流量如何从外部集群流向 Service; 
Kubernetes 中应用程序通过内部和外部两层负载均衡器暴露
内部负载均衡器叫 Service,外部负载均衡器叫 Ingress

假设你希望部署一个简单的 Hello World 应用程序,这个应用程序的 YAML 应该类似于如下内容:

何时应使用端口 80,何时应使用端口 8080? 是否应该为每个服务创建一个新端口,以免冲突? 标签(label)名称重要吗?应该保持标签名称一致吗? 
令人惊讶的是,Deployment 和 Service 之间根本没有连接。相反,Service 直接指向 Pod,完全跳过了 Deployment。因此,你应该关注的是 Pod 和 Service 之间是如何相互关联的。
请记住以下三件事:
Service selector 应至少匹配 Pod 的一个标签;
Service 的
targetPort应该与 Pod 的containerPort匹配;Service 端口可以是任何数字。多个 Service 可以使用同一个端口,因为每个 Service 分配到的 IP 地址不同;
下图总结了如何连接端口:

在创建 Pod 时,需要为 Pod 中的每个容器定义端口 containerPort
创建 Service 时,可以定义 port 和 targetPort。但是哪一个应该和容器连接呢

targetPort 和 conatinerPort 需始终匹配

targetPort 应该也是 3000port/targetPort 应该是匹配的。
track:canary 标签呢?也要匹配上吗?matchLables selector 呢?它必须始终与 Pod 的标签匹配,Deployment 用它来跟踪 Pod。

any-name=my-app是any-name:my-app标签。port-forward 命令来连接到 Service 并测试该连接。
service/<service name>是 service 的名称(在当前的 YAML 文件中是 "my service")。3000 是你想在计算机上开启的端口。 80 是由 Service 在 port字段中暴露的端口。
Ingress 的 service.port必须匹配 Service 的port。Ingress 的 service.name必须匹配 Service 的name。
你已经知道了 Service 会暴露一个 port
Ingress 有一个字段叫做 ServicePort
Service 的 port 和 Ingress 的 ServicePort 必须始终匹配
如果你要把端口 80 分配给一个 Service,必须把 ServicePort 也改成 80

kubectl port-forward,但是要注意是连接到 Ingress controller 而不是 Service。


Service selector 应该和 Pod 的标签匹配; Service 的 targetPort应该和 Pod 里面容器的containerPort匹配;Service 端口可以是任意数字。多个 Service 可以使用同一个端口,因为不同的 Service 分配的 IP 地址不同; Ingress 的 service.port应该和 Service 的port匹配;Service 的名称应该和 Ingress 中 service.name字段匹配;
确保 Pod 正在运行; 着重关注让 Service 将流量路由到 Pod; 检查 Ingress 的配置是否正确。 
应该从最底层开始为 Deployment 做故障排查。首先,检查 Pod 是否已就绪并在运行中
如果 Pod 已就绪,应该检查 Service 是否能将流量路由到 Pod
最后,检查 Service 和 Ingress 之间的连接
排查 Pod 故障

kubectl logs <pod name>有助于检索 Pod 中容器的日志;kubectl describe pod <pod name>对检索与 Pod 相关的事件列表很有用;kubectl get pod <pod name>可提取 Kubernetes 中存储的 Pod 的 YAML 定义;kubectl exec -ti <pod name> bash可在 Pod 中的一个容器运行一个交互式命令。
常见的 Pod 报错
ImagePullBackoff ImageInspectError ErrImagePull ErrImageNeverPull RegistryUnavailable InvalidImageName 
CrashLoopBackOff RunContainerError KillContainerError VerifyNonRootError RunInitContainerError CreatePodSandboxError ConfigPodSandboxError KillPodSandboxError SetupNetworkError TeardownNetworkError 
ImagePullBackOff
镜像名称无效——比如,你拼错了镜像名称,或者镜像不存在。 为镜像指定了一个不存在的标签。 正在检索的镜像属于私有 registry,Kubernetes 没有访问的凭证。 
CrashLoopBackOff
应用程序中存在错误,阻止了容器的启动; 容器配置有误:StackOverFlow 上这个问题就是如此 https://stackoverflow.com/questions/41604499/my-kubernetes-pods-keep-crashing-with-crashloopbackoff-but-i-cant-find-any-lo Liveness 探针失败多次。 

RunContainerError
挂载不存在的卷,如 ConfigMap 或 Secret; 将只读卷挂载为读写卷。 
kubectl describe pod <pod-name> 命令检查和分析这个错误。Pod 处于 Pending 的状态
集群没有足够的资源(例如 CPU 和内存)来运行 Pod。 当前的命名空间具有 ResourceQuota 对象,创建 Pod 将使命名空间超过配额。 该 Pod 绑定了一个处于 Pending 状态的 PersistentVolumeClaim。 
kubectl describe 命令中检查事件。

Pod 处于未就绪状态
kubectl describe 中的“事件”以验证错误。排查 Service 故障

<ip address:port> ,当 Service 定位到一个 Pod 后,至少应该有一个 Endpoint。正在运行的 Pod 没有正确的标签(应该检查一下是否在正确的命名空间中); Service 的 selector标签拼写有误。
targetPort 可能出问题了。如何测试 Service 呢?无论什么类型的 Service,都可以用 kubectl port-forward 来连接:
<service-name>是 Service 的名称;3000是你想在计算机上打开的端口;80是 Service 暴露的端口。
Pod 在运行中且是就绪状态; Service 可以分发流量分配到 Pod。 
service.name 和 service.port 连接到 Service。应该检查一下这些配置是否正确。
将 Ingress 暴露到公网的方式; 将集群暴露到公网的方式; 


最后,连接到 Pod:

如果解决了,那么就是基础设施问题。你要看一下流量是如何路由到集群的。 如果没有解决,那么是 Ingress controller 的问题,你应该调试 controller。 
调试 Ingress Nginx
kubectl ingress-nginx 来进行如下操作:检查日志、Backend、证书等; 连接到 Ingress; 检查当前配置。 
kubectl ingress-nginx lint:用于检查nginx.conf;kubectl ingress-nginx backend:用于检查 Backend(类似kubectl describe ingress <ingress-name>);kubectl ingress-nginx logs:用于检查日志。
请注意,你可能需要使用 --namespace
为 Ingress controller 指定正确的命名空间。 
出现故障的 Job 和 CronJob; StatefulSet 和 DaemonSet。 
- END -
公众号后台回复「加群」加入一线高级工程师技术交流群,一起交流进步。
推荐阅读 让运维简单高效,轻松搞定运维管理平台 备份和迁移 Kubernetes 利器:Velero 搭建一套完整的企业级 K8s 集群(v1.20,二进制方式) 记一次 Kubernetes 机器内核问题排查 Shell 脚本进阶,经典用法及其案例 Kubernetes 集群网络从懵圈到熟悉 记一次 Linux服务器被入侵后的排查思路 5个面试的关键技巧,助你拿到想要的offer! 
点亮,服务器三年不宕机


