个人K8s还在学习中,相关博客还没有写,准备学第二遍再开始学,发现这篇文章挺好,先转载一下。

原创: 白明的赞赏账户

下面是一个示意图,可帮助你调试Kubernetes Deployment(你可以在此处下载它的PDF版本 https://tonybai.com/wp-content/uploads/k8s-deployment-troubleshooting/troubleshooting-kubernetes.pdf)。

当你希望在Kubernetes中部署应用程序时,你通常会定义三个组件:

•一个Deployment - 这是一份用于创建你的应用程序的Pod副本的"食谱";

•一个Service - 一个内部负载均衡器,用于将流量路由到内部的Pod上;

•一个Ingress - 描述如何流量应该如何从集群外部流入到集群内部的你的服务上。

下面让我们用示意图快速总结一下要点。

在Kubernetes中,你的应用程序通过两层负载均衡器暴露服务:内部的和外部的

内部的负载均衡器称为Service,而外部的负载均衡器称为Ingress

Pod不会直接部署。Deployment会负责创建Pod并管理它们

假设你要部署一个简单的"HelloWorld"应用,该应用的YAML文件的内容应该类似下面这样:

  1. // hello-world.yaml
  2.  
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: my-deployment
  7. labels:
  8. track: canary
  9. spec:
  10. selector:
  11. matchLabels:
  12. any-name: my-app
  13. template:
  14. metadata:
  15. labels:
  16. any-name: my-app
  17. spec:
  18. containers:
  19. - name: cont1
  20. image: learnk8s/app:1.0.0
  21. ports:
  22. - containerPort: 8080
  23. ---
  24. apiVersion: v1
  25. kind: Service
  26. metadata:
  27. name: my-service
  28. spec:
  29. ports:
  30. - port: 80
  31. targetPort: 8080
  32. selector:
  33. name: app
  34. ---
  35. apiVersion: networking.k8s.io/v1beta1
  36. kind: Ingress
  37. metadata:
  38. name: my-ingress
  39. spec:
  40. rules:
  41. - http:
  42. paths:
  43. - backend:
  44. serviceName: app
  45. servicePort: 80
  46. path: /
  1. 这个定义很长,组件之间的相互关系并不容易看出来。

例如:

•什么时候应使用端口80,又是何时应使用端口8080?

•你是否应该为每个服务创建一个新端口以免它们相互冲突?

•标签(label)名重要吗?它们是否在每一处都应该是一样的?

在进行调试之前,让我们回顾一下这三个组件是如何相互关联的。

让我们从Deployment和Service开始。

一. 连接Deployment和Service

令人惊讶的消息是,Service和Deployment之间根本没有连接。

事实是:Service直接指向Pod,并完全跳过了Deployment。

因此,你应该注意的是Pod和Service之间的相互关系。

你应该记住三件事:

•Service selector应至少与Pod的一个标签匹配;

•Service的targetPort应与Pod中容器的containerPort匹配;

•Service的port可以是任何数字。多个Service可以使用同一端口号,因为它们被分配了不同的IP地址。

下面的图总结了如何连接端口:

考虑上面被一个服务暴露的Pod

创建Pod时,应为Pod中的每个容器定义containerPort端口

当创建一个Service时,你可以定义port和targetPort,但是哪个用来连接容器呢?

targetPort和containerPort应该始终保持匹配

如果容器暴露3000端口(containerPort),那么targetPort应该匹配这一个端口号

再来看看YAML,标签和ports/targetPort应该匹配:

  1. // hello-world.yaml
  2.  
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: my-deployment
  7. labels:
  8. track: canary
  9. spec:
  10. selector:
  11. matchLabels:
  12. any-name: my-app
  13. template:
  14. metadata:
  15. labels:
  16. any-name: my-app
  17. spec:
  18. containers:
  19. - name: cont1
  20. image: learnk8s/app:1.0.0
  21. ports:
  22. - containerPort: 8080
  23. ---
  24. apiVersion: v1
  25. kind: Service
  26. metadata:
  27. name: my-service
  28. spec:
  29. ports:
  30. - port: 80
  31. targetPort: 8080
  32. selector:
  33. any-name: my-app
  1. deployment顶部的track: canary标签呢?

它也应该匹配吗?

该标签属于deployment,service的选择器未使用它来路由流量。

换句话说,你可以安全地删除它或为其分配其他值。

matchLabels选择器呢?

它必须始终与Pod的标签匹配,并且被Deployment用来跟踪Pod。

假设你已经进行了所有正确的设置,该如何测试它呢?

你可以使用以下命令检查Pod是否具有正确的标签:

  1. $ kubectl get pods --show-labels

或者,如果你拥有属于多个应用程序的Pod:

  1. $ kubectl get pods --selector any-name=my-app --show-labels

any-name=my-app就是标签:any-name: my-app

还有问题吗?

你也可以连接到Pod!

你可以使用kubectl中的port-forward命令连接到service并测试连接。

  1. $ kubectl port-forward service/<service name> 3000:80

•service/ 是服务的名称- 在上面的YAML中是“my-service”

•3000是你希望在计算机上打开的端口

•80是service通过port字段暴露的端口

如果可以连接,则说明设置正确。

如果不行,则很可能是你填写了错误的标签或端口不匹配。

二. 连接Service和Ingress

接下来是配置Ingress以将你的应用暴露到集群外部。

Ingress必须知道如何检索服务,然后检索Pod并将流量路由给它们。

Ingress按名字和暴露的端口检索正确的服务。

在Ingress和Service中应该匹配两件事:

•Ingress的servicePort应该匹配service的port

•Ingress的serviceName应该匹配服务的name

下面的图总结了如何连接端口:

你已经知道servive暴露一个port

Ingress有一个字段叫servicePort

service的port和Ingress的service应该始终保持匹配

如果你为service指定的port是80,那么你也应该将ingress的servicePort改为80

实践中,你应该查看以下几行(下面代码中的my-service和80):

  1. // hello-world.yaml
  2.  
  3. apiVersion: v1
  4. kind: Service
  5. metadata:
  6. name: my-service --- 需关注
  7. spec:
  8. ports:
  9. - port: 80 --- 需关注
  10. targetPort: 8080
  11. selector:
  12. any-name: my-app
  13. ---
  14. apiVersion: networking.k8s.io/v1beta1
  15. kind: Ingress
  16. metadata:
  17. name: my-ingress
  18. spec:
  19. rules:
  20. - http:
  21. paths:
  22. - backend:
  23. serviceName: my-service --- 需关注
  24. servicePort: 80 --- 需关注
  25. path: /
  1. 你如何测试Ingress是否正常工作呢?

你可以使用与以前相同的策略kubectl port-forward,但是这次你应该连接到Ingress控制器,而不是连接到Service。

首先,使用以下命令检索Ingress控制器的Pod名称:

  1. $ kubectl get pods --all-namespaces
  2. NAMESPACE NAME READY STATUS
  3. kube-system coredns-5644d7b6d9-jn7cq 1/1 Running
  4. kube-system etcd-minikube 1/1 Running
  5. kube-system kube-apiserver-minikube 1/1 Running
  6. kube-system kube-controller-manager-minikube 1/1 Running
  7. kube-system kube-proxy-zvf2h 1/1 Running
  8. kube-system kube-scheduler-minikube 1/1 Running
  9. kube-system nginx-ingress-controller-6fc5bcc 1/1 Running
  1. 标识Ingress Pod(可能在其他命名空间中)并描述它以检索端口:
  1. $ kubectl describe pod nginx-ingress-controller-6fc5bcc \
  2. --namespace kube-system \
  3. | grep Ports
  4. Ports: 80/TCP, 443/TCP, 18080/TCP

最后,连接到Pod:

  1. $ kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

此时,每次你访问计算机上的端口3000时,请求都会转发到Ingress控制器Pod上的端口80。

如果访问http://localhost:3000,则应找到提供网页服务的应用程序。

回顾Port

快速回顾一下哪些端口和标签应该匹配:

• service selector应与Pod的标签匹配

• service的targetPort应与Pod中容器的containerPort匹配

• service的端口可以是任何数字。多个服务可以使用同一端口,因为它们分配了不同的IP地址。

• ingress的servicePort应该匹配service的port

• serivce的名称应与ingress中的serviceName字段匹配

知道如何构造YAML定义只是故事的一部分。

出了问题后该怎么办?

Pod可能无法启动,或者正在崩溃。

三. kubernetes deployment故障排除的3个步骤

在深入研究失败的deployment之前,我们必须对Kubernetes的工作原理有一个明确定义的思维模型。

由于每个deployment中都有三个组件,因此你应该自下而上依次调试所有组件。

•你应该先确保Pods正在运行•然后,专注于让service将流量路由到到正确的Pod•然后,检查是否正确配置了Ingress

你应该从底部开始对deployment进行故障排除。首先,检查Pod是否已就绪并正在运行。

如果Pod已就绪,则应调查service是否可以将流量分配给Pod。

最后,你应该检查service与ingress之间的连接。

1. Pod故障排除

在大多数情况下,问题出在Pod本身。

你应该确保Pod正在运行并准备就绪。

该如何检查呢?

  1. $ kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. app1 0/1 ImagePullBackOff 0 47h
  4. app2 0/1 Error 0 47h
  5. app3-76f9fcd46b-xbv4k 1/1 Running 1 47h 

在上述会话中,最后一个Pod处于就绪并正常运行的状态;但是,前两个Pod既不处于Running也不是Ready。

你如何调查出了什么问题?

有四个有用的命令可以对Pod进行故障排除:

• kubectl logs 有助于检索Pod容器的日志

• kubectl describe pod 检索与Pod相关的事件列表很有用

• kubectl get pod 用于提取存储在Kubernetes中的Pod的YAML定义

• kubectl exec -ti bash 在Pod的一个容器中运行交互式命令很有用

应该使用哪一个呢?

没有一种万能的。

相反,我们应该结合着使用它们。

常见Pod错误

Pod可能会出现启动和运行时错误。

启动错误包括:

• ImagePullBackoff

• ImageInspectError

• ErrImagePull

• ErrImageNeverPull

• RegistryUnavailable

• InvalidImageName

运行时错误包括:

• CrashLoopBackOff

• RunContainerError

• KillContainerError

• VerifyNonRootError

• RunInitContainerError

• CreatePodSandboxError

• ConfigPodSandboxError

• KillPodSandboxError

• SetupNetworkError

• TeardownNetworkError

有些错误比其他错误更常见。

以下是最常见的错误列表以及如何修复它们的方法。

ImagePullBackOff

当Kubernetes无法获取到Pod中某个容器的镜像时,将出现此错误。

共有三个可能的原因:

•镜像名称无效-例如,你拼错了名称,或者image不存在

•你为image指定了不存在的标签

•你尝试检索的image属于一个私有registry,而Kubernetes没有凭据可以访问它

前两种情况可以通过更正image名称和标记来解决。

针对第三种情况,你应该将私有registry的访问凭证通过Secret添加到k8s中并在Pod中引用它。

官方文档中有一个有关如何实现此目标的示例。

CrashLoopBackOff

如果容器无法启动,则Kubernetes将显示错误状态为:CrashLoopBackOff。

通常,在以下情况下容器无法启动:

•应用程序中存在错误,导致无法启动•你未正确配置容器

•Liveness探针失败太多次

你应该尝试从该容器中检索日志以调查其失败的原因。

如果由于容器重新启动太快而看不到日志,则可以使用以下命令:

  1. $ kubectl logs <pod-name> --previous

这个命令打印前一个容器的错误消息。

RunContainerError

当容器无法启动时,出现此错误。

甚至在容器内的应用程序启动之前。

该问题通常是由于配置错误,例如:

•挂载不存在的卷,例如ConfigMap或Secrets

•将只读卷安装为可读写

你应该使用kubectl describe pod 命令收集和分析错误。

处于Pending状态的Pod

当创建Pod时,该Pod保持Pending状态。

为什么?

假设你的调度程序组件运行良好,可能的原因如下:

•集群没有足够的资源(例如CPU和内存)来运行Pod

•当前的命名空间具有ResourceQuota对象,创建Pod将使命名空间超过配额

•该Pod绑定到一个处于pending状态的 PersistentVolumeClaim

最好的选择是检查kubectl describe命令输出的“事件”部分内容:

  1. $ kubectl describe pod <pod name>

对于因ResourceQuotas而导致的错误,可以使用以下方法检查集群的日志:

  1. $ kubectl get events --sort-by=.metadata.creationTimestamp

处于未就绪状态的Pod

如果Pod正在运行但未就绪(not ready),则表示readiness就绪探针失败。

当“就绪”探针失败时,Pod未连接到服务,并且没有流量转发到该实例。

就绪探针失败是应用程序的特定错误,因此你应检查kubectl describe中的“ 事件”部分以识别错误。

2. 服务的故障排除

如果你的Pod正在运行并处于就绪状态,但仍无法收到应用程序的响应,则应检查服务的配置是否正确。

service旨在根据流量的标签将流量路由到Pod。

因此,你应该检查的第一件事是服务关联了多少个Pod。

你可以通过检查服务中的端点(endpoint)来做到这一点:

  1. $ kubectl describe service <service-name> | grep Endpoints

端点是一对,并且在服务(至少)以Pod为目标时,应该至少有一个端点。

如果“端点”部分为空,则有两种解释:

•你没有运行带有正确标签的Pod(提示:你应检查自己是否在正确的命名空间中)

•service的selector标签上有错字

如果你看到端点列表,但仍然无法访问你的应用程序,则targetPort可能是你服务中的罪魁祸首。

你如何测试服务?

无论服务类型如何,你都可以使用kubectl port-forward来连接它:

  1. $kubectl port-forward service/<service-name> 3000:80

这里:

• 是服务的名称•3000 是你希望在计算机上打开的端口

•80 是服务公开的端口

3.Ingress的故障排除

如果你已到达本节,则:

•Pod正在运行并准备就绪

•服务会将流量分配到Pod

但是你仍然看不到应用程序的响应。

这意味着最有可能是Ingress配置错误。

由于正在使用的Ingress控制器是集群中的第三方组件,因此有不同的调试技术,具体取决于Ingress控制器的类型。

但是在深入研究Ingress专用工具之前,你可以用一些简单的方法进行检查。

Ingress使用serviceName和servicePort连接到服务。

你应该检查这些配置是否正确。

你可以通过下面命令检查Ingress配置是否正确:

  1. $kubectl describe ingress <ingress-name>

如果backend一列为空,则配置中必然有一个错误。

如果你可以在“backend”列中看到端点,但是仍然无法访问该应用程序,则可能是以下问题:

•你如何将Ingress暴露于公共互联网

•你如何将集群暴露于公共互联网

你可以通过直接连接到Ingress Pod来将基础结构问题与Ingress隔离开。

首先,获取你的Ingress控制器Pod(可以位于其他名称空间中):

  1. $ kubectl get pods --all-namespaces
  2. NAMESPACE NAME READY STATUS
  3. kube-system coredns-5644d7b6d9-jn7cq 1/1 Running
  4. kube-system etcd-minikube 1/1 Running
  5. kube-system kube-apiserver-minikube 1/1 Running
  6. kube-system kube-controller-manager-minikube 1/1 Running
  7. kube-system kube-proxy-zvf2h 1/1 Running
  8. kube-system kube-scheduler-minikube 1/1 Running
  9. kube-system nginx-ingress-controller-6fc5bcc 1/1 Running
  1. 描述它以检索端口:
  1. # kubectl describe pod nginx-ingress-controller-6fc5bcc --namespace kube-system \ | grep Ports

最后,连接到Pod:

  1. $ kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

此时,每次你访问计算机上的端口3000时,请求都会转发到Pod上的端口80。

现在可以用吗?

•如果可行,则问题出在基础架构中。你应该调查流量如何路由到你的集群。

•如果不起作用,则问题出在Ingress控制器中。你应该调试Ingress。

如果仍然无法使Ingress控制器正常工作,则应开始对其进行调试。

目前有许多不同版本的Ingress控制器。

热门选项包括Nginx,HAProxy,Traefik等。

你应该查阅Ingress控制器的文档以查找故障排除指南。

由于Ingress Nginx是最受欢迎的Ingress控制器,因此在下一部分中我们将介绍一些有关调试ingress-nginx的技巧。

调试Ingress Nginx

Ingress-nginx项目有一个Kubectl的官方插件。

你可以用kubectl ingress-nginx来:

•检查日志,后端,证书等。

•连接到ingress

•检查当前配置

你应该尝试的三个命令是:

•kubectl ingress-nginx lint,它会检查 nginx.conf

•kubectl ingress-nginx backend,以检查后端(类似于kubectl describe ingress )

•kubectl ingress-nginx logs,查看日志

请注意,你可能需要为Ingress控制器指定正确的名称空间--namespace 。

四. 总结

如果你不知道从哪里开始,那么在Kubernetes中进行故障排除可能是一项艰巨的任务。

你应该始终牢记从下至上解决问题:从Pod开始,然后通过Service和Ingress向上移动堆栈。

你在本文中了解到的调试技术也可以应用于其他对象,例如:

•failing Job和CronJob

•StatefulSets和DaemonSets

本文翻译自learnk8s上的文章A visual guide on troubleshooting Kubernetes deployments。

微博:https://weibo.com/bigwhite20xx 微信公众号:iamtonybai 博客:tonybai.com github: https://github.com/bigwhite

Kubernetes Deployment故障排除图解指南的更多相关文章

  1. Deployment故障排除图解

    PDF文件下载地址:https://files.cnblogs.com/files/sanduzxcvbnm/troubleshooting-kubernetes.pdf

  2. 分步骤讲解Deployment故障排除

    背景假设 当你希望在Kubernetes中部署应用程序时,你通常会定义三个组件: 一个Deployment - 这是一份用于创建你的应用程序的Pod副本的"食谱": 一个Servi ...

  3. Kubernetes中Deployment部署故障排除

    Kubernetes中Deployment部署故障排除 字符型思维导图 排查pod状态(带标签):kubectl get pods,是否有等待处理的pod? 是?kubectl describe po ...

  4. kubernetes 故障排除、处理、预防

    kubernetes 故障排除.处理.预防 故障排除顺序和思路 第一步: 我们可以通过查看节点是否正常,一是保证 K8S API Server 是正常的,二是可以查看节点集群网络中是否存在节点异常.如 ...

  5. Longhorn 云原生容器分布式存储 - 故障排除指南

    内容来源于官方 Longhorn 1.1.2 英文技术手册. 系列 Longhorn 是什么? Longhorn 云原生容器分布式存储 - 设计架构和概念 Longhorn 云原生容器分布式存储 - ...

  6. 主说明:自动Undo管理的故障排除指南(Doc ID 1579081.1)

    Master Note: Troubleshooting guide for Automatic Undo Management (Doc ID 1579081.1) APPLIES TO: Orac ...

  7. 解决Kubernetes Pod故障的5个简单技巧

    在很多情况下,你可能会发现Kubernetes中的应用程序没有正确地部署,或者没有正常地工作.今天这篇文章就提供了如何去快速解决这类故障以及一些技巧. 在阅读了这篇文章之后,你还将深入了解Kubern ...

  8. Sentry 监控 - 私有 Docker Compose 部署与故障排除详解

    内容整理自官方开发文档 系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Map ...

  9. 三小时学会Kubernetes:容器编排详细指南

    三小时学会Kubernetes:容器编排详细指南 如果谁都可以在三个小时内学会Kubernetes,银行为何要为这么简单的东西付一大笔钱? 如果你心存疑虑,我建议你不妨跟着我试一试!在完成本文的学习后 ...

随机推荐

  1. CentOS下firewalld添加开放端口

    添加 firewall-cmd --zone=public --add-port=/tcp --permanent (--permanent永久生效,没有此参数重启后失效) 重新载入 firewall ...

  2. 【Android Apk重新签名报错re-sign.jar之解决方法】

    故障现象:

  3. c语言l博客作业04

    这作业属于那个课程 c语言程序设计ll 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-4/homework/9772 我在这个课程的目标 ...

  4. C++对象在继承情况下的内存布局

    1,C++ 中继承是非常重要的一个特性,本节课研究在继承的情形下,C++ 的对象模 型又有什么不同: 2,继承对象模型(最简单的情况下): 1,在 C++ 编译器的内部类可以理解为结构体: 2,子类是 ...

  5. 中值滤波器(平滑空间滤波器)基本原理及Python实现

    1. 基本原理 一种典型的非线性滤波器就是中值滤波器,它使用像素的一个领域内的灰度的中值来代替该像素的值.中值滤波器通常是处理椒盐噪声的一种有效的手段. 2. 测试结果 图源自skimage 3. 代 ...

  6. 深入理解let和var的区别

    首先我们应该知道js引擎在读取js代码时会进行两个步骤: 第一个步骤是解释. 第二个步骤是执行. 所谓解释就是会先通篇扫描所有的Js代码,然后把所有声明提升到顶端,第二步是执行,执行就是操作一类的. ...

  7. ArcGIS 在VS2010中 ESRI.ArcGIS.SOESupport.dll 无法正常加载的处理

    转自  http://blog.csdn.net/tnt123688/article/details/23186973 问题描述: 打开ArcGIS的SOE模板后,提示  错误 命名空间“ESRI.A ...

  8. window对象open方法详解

    window.open详解 window.open("sUrl","sName","sFeature","bReplace&quo ...

  9. HTTPS到底是什么

    Http存在的问题   上过网的朋友都知道,网络是非常不安全的.尤其是公共场所很多免费的wifi,或许只是攻击者的一个诱饵.还有大家平时喜欢用的万能钥匙,等等.那我们平时上网可能会存在哪些风险呢?   ...

  10. Celery多队列配置

    Celery多队列配置 Celery官方文档 项目结构 /proj -__init__ -app.py #实例化celery对象 -celeryconfig.py #celery的配置文件 -task ...