Kubernetes的视觉故障排除指南

注意事项 佩雷夫 :本文是learnk8s项目免费提供的材料的一部分,该项目教公司和个人管理员如何使用Kubernetes。 在其中,项目经理Daniele Polencic明确说明了在K8s集群中运行的应用程序遇到一般问题时应采取的步骤。



TL; DR:这是一个可以帮助您调试Kubernetes中的部署的图表:



查找和修复集群中错误的流程图。 原文(英文)以PDF图像形式提供

将应用程序部署到Kubernetes时,通常需要定义三个组件:

  • 部署是创建称为Pod的应用程序副本的秘诀。
  • 服务 -内部负载平衡器,用于在Pod之间分配流量;
  • 入口 -描述流量如何从外界流向服务。

这是一个简短的图形摘要:

1)在Kubernetes中,应用程序通过两层负载均衡器从内部世界接收流量:内部和外部。



2)内部平衡器称为Service,外部平衡器称为Ingress。



3)部署会创建吊舱并对其进行监视(它们不是手动创建的)。



假设您要在Hello World中部署一个简单的应用程序。 它的YAML配置如下所示:

apiVersion: apps/v1 kind: Deployment # <<< metadata: name: my-deployment labels: track: canary spec: selector: matchLabels: any-name: my-app template: metadata: labels: any-name: my-app spec: containers: - name: cont1 image: learnk8s/app:1.0.0 ports: - containerPort: 8080 --- apiVersion: v1 kind: Service # <<< metadata: name: my-service spec: ports: - port: 80 targetPort: 8080 selector: name: app --- apiVersion: networking.k8s.io/v1beta1 kind: Ingress # <<< metadata: name: my-ingress spec: rules: - http: paths: - backend: serviceName: app servicePort: 80 path: / 

定义很长,很容易混淆组件之间的关系。

例如:

  • 什么时候使用端口80,什么时候使用8080?
  • 是否应该为每个服务创建一个新端口,以免它们冲突?
  • 标签名称重要吗? 他们到处都应该一样吗?

在专注于调试之前,让我们回顾一下这三个组件如何相互关联。 让我们从部署和服务开始。

连接部署'a和服务'a


您会感到惊讶,但是部署和服务没有以任何方式连接。 而是,服务直接指向Pod,绕过部署。

因此,我们对Pod和服务如何相互关联感兴趣。 要记住的三件事:

  1. 服务selector必须至少匹配一个Pod标签。
  2. targetPort必须与Pod内的containerPort targetPort相匹配。
  3. port服务可以是任何东西。 不同的服务可以使用同一端口,因为它们具有不同的IP地址。

下图以图形形式表示以上所有内容:

1)想象一下,该服务将流量定向到某个吊舱:



2)创建容器时,必须为容器中的每个容器指定containerPort



3)创建服务时,必须指定porttargetPort但是,哪一个是通过容器连接的呢?



4)通过targetPort 。 它应该与containerPort匹配。



5)假设容器中的端口3000已打开,则targetPort值应相同。



在YAML文件中,标签和ports / targetPort必须匹配:

 apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment labels: track: canary spec: selector: matchLabels: any-name: my-app template: metadata: labels: # <<< any-name: my-app # <<< spec: containers: - name: cont1 image: learnk8s/app:1.0.0 ports: - containerPort: 8080 # <<< --- apiVersion: v1 kind: Service metadata: name: my-service spec: ports: - port: 80 targetPort: 8080 # <<< selector: # <<< any-name: my-app # <<< 

track: canary “部署”部分顶部的“ track: canary 应该匹配吗?

该标签指的是部署,服务不使用它来路由流量。 换句话说,可以将其删除或分配其他值。

那么matchLabels选择器呢?

它应始终与Pod的标签匹配 ,因为Deployment会使用它来跟踪Pod。

假设您进行了正确的编辑。 如何检查?

您可以使用以下命令检查容器标签:

 kubectl get pods --show-labels 

或者,如果Pod属于多个应用程序:

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

其中any-name=my-appany-name: my-app标签。

有什么困难吗?

您可以连接到吊舱! 为此,请在kubectl中使用port-forward命令。 它允许您连接到服务并检查连接。

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

在这里:

  • service/<service name> -服务名称; 就我们而言,这是my-service
  • 3000-您要在计算机上打开的端口;
  • 80-服务的port字段中指定的port

如果能够建立连接,则说明设置正确。

如果无法建立连接,则说明标签有问题或端口不匹配。

服务与入口的连接


提供对应用程序访问权限的下一步与配置Ingress有关。 入口应该知道如何找到服务,然后找到豆荚并将流量引向它们。 Ingress通过名称和开放端口找到所需的服务。

在Ingress和Service的描述中,两个参数必须匹配:

  1. Ingress中的servicePort必须与Service中的port参数匹配;
  2. Ingress中的serviceName必须与Service中的name字段匹配。

下图总结了端口的连接:

1)如您所知,Service在特定port上侦听:



2)Ingress有一个名为servicePort的参数:



3)此参数( servicePort )应始终与服务定义中的port匹配:



4)如果在服务中指定了端口80,则servicePort也必须为80:



实际上,您需要注意以下几行:

 apiVersion: v1 kind: Service metadata: name: my-service # <<< spec: ports: - port: 80 # <<< targetPort: 8080 selector: any-name: my-app --- apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: my-ingress spec: rules: - http: paths: - backend: serviceName: my-service # <<< servicePort: 80 # <<< path: / 

如何检查Ingress是否正常工作?

您可以将该方法与kubectl port-forward ,但需要连接到Ingress控制器而不是服务。

首先,您需要使用Ingress控制器找出Pod的名称:

 kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS kube-system coredns-5644d7b6d9-jn7cq 1/1 Running kube-system etcd-minikube 1/1 Running kube-system kube-apiserver-minikube 1/1 Running kube-system kube-controller-manager-minikube 1/1 Running kube-system kube-proxy-zvf2h 1/1 Running kube-system kube-scheduler-minikube 1/1 Running kube-system nginx-ingress-controller-6fc5bcc 1/1 Running 

找到Ingress窗格(它可能引用其他名称空间),然后运行describe命令找出端口号:

 kubectl describe pod nginx-ingress-controller-6fc5bcc \ --namespace kube-system \ | grep Ports Ports: 80/TCP, 443/TCP, 18080/TCP 

最后,连接到吊舱:

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

现在,每次您将请求发送到计算机上的端口3000时,它将使用Ingress控制器重定向到Pod的端口80。 通过转到http:// localhost:3000 ,您应该看到该应用程序创建的页面。

端口摘要


让我们再次记住哪些端口和标签应该匹配:

  1. 服务定义中的选择器必须与pod标签匹配;
  2. 服务定义中targetPort必须与pod内的containerPort containerPort相匹配;
  3. 服务定义中的port可以是任何东西。 不同的服务可以使用同一端口,因为它们具有不同的IP地址。
  4. servicePort入口必须与服务定义中的port匹配;
  5. 服务名称必须与Ingress中的serviceName字段匹配。

las,仅仅知道如何正确构造YAML配置还不够。

出问题了怎么办?

吊舱可能无法启动或崩溃。

解决Kubernetes中应用程序故障的3个步骤


在调试部署之前,您需要对Kubernetes的工作方式有充分的了解。

由于下载到K8s的每个应用程序中都有三个组件,因此应该从最底部开始以一定顺序对其进行调试。

  1. 首先,您需要确保吊舱能够正常工作,然后...
  2. 检查服务是否将流量传递到Pod,然后...
  3. 检查是否正确配置了Ingress。

视觉呈现:

1)开始寻找问题应该从底部开始。 首先检查Pod是否具有ReadyRunning状态:



2)如果Pod为Ready ,则应确定服务是否在Pod之间分配流量:



3)最后,您需要分析服务与Ingress之间的连接:



1.吊舱诊断


在大多数情况下,问题出在豆荚上。 确保吊舱处于“ Ready且正在Running 。 您可以使用以下命令进行验证:

 kubectl get pods NAME READY STATUS RESTARTS AGE app1 0/1 ImagePullBackOff 0 47h app2 0/1 Error 0 47h app3-76f9fcd46b-xbv4k 1/1 Running 1 47h 

在上面命令的输出中,最后一个Pod被列为RunningReady ,而对于其他两个Pod则没有。

如何理解出了什么问题?

有四个用于诊断Pod的有用命令:

  1. kubectl logs < pod'>允许您从pod的容器中提取日志;
  2. kubectl describe pod < pod'>允许您查看与pod相关的事件列表;
  3. kubectl get pod < pod'>允许您获取存储在Kubernetes中的kubectl get pod < pod'>的YAML配置;
  4. kubectl exec -ti < pod'> bash允许您在其中一个pod容器中运行交互式命令shell

选择哪一个?

事实是,没有通用团队。 这些应结合使用。

常见吊舱问题


pod错误主要有两种类型:启动错误和运行时错误。

启动错误:

  • ImagePullBackoff
  • ImageInspectError
  • ErrImagePull
  • ErrImageNeverPull
  • RegistryUnavailable
  • InvalidImageName

运行时错误:

  • CrashLoopBackOff
  • RunContainerError
  • KillContainerError
  • VerifyNonRootError
  • RunInitContainerError
  • CreatePodSandboxError
  • ConfigPodSandboxError
  • KillPodSandboxError
  • SetupNetworkError
  • TeardownNetworkError

有些错误比其他错误更常见。 以下是一些常见错误以及解决方法。

ImagePullBackOff


当Kubernetes无法获取其中一个Pod容器的图像时,将出现此错误。 这是最常见的三个原因:

  1. 图像名称指定不正确-例如,您在其中输入错误,或者图像不存在;
  2. 指定了不存在的图像标签;
  3. 该图像存储在私有注册表中,Kubernetes无权访问它。

前两个原因很容易消除-只需修复图像名称和标签即可。 如果是后者,则需要在Secret中输入私有注册表的凭据,并在pod中添加指向它的链接。 Kubernetes文档中有一个如何完成此操作的示例

CrashLoopBackOff


如果容器无法启动,则Kubenetes将引发CrashLoopBackOff错误。 通常在以下情况下发生:

  1. 应用程序中存在一个错误,无法启动。
  2. 容器配置不正确
  3. 活力测试失败太多次了。

您必须尝试从容器中获取日志,以找出其失败的原因。 如果难以访问日志,因为容器重启太快,可以使用以下命令:

 kubectl logs <pod-name> --previous 

它显示来自先前容器轮回的错误消息。

RunContainerError


当容器无法启动时,会发生此错误。 它对应于应用程序启动之前的时刻。 通常,其原因是配置不正确,例如:

  • 尝试挂载不存在的卷,例如ConfigMap或Secrets;
  • 尝试将只读卷挂载为读写卷。

kubectl describe pod <pod-name>命令非常适合分析此类错误。

暂挂的豆荚


创建后,窗格将保持“ Pending状态。

为什么会这样呢?

以下是可能的原因(我认为调度程序工作正常):

  1. 群集没有足够的资源(例如处理能力和内存)来运行Pod。
  2. ResourceQuota对象安装在相应的名称空间中,创建pod会使该名称空间超出配额。
  3. Pod与Pending PersistentVolumeClaim绑定。

在这种情况下,建议使用kubectl describe命令并检查“ Events部分:

 kubectl describe pod <pod name> 

如果发生与ResourceQuotas相关的错误,建议使用以下命令查看集群日志

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

未准备好豆荚


如果窗格列出为“正在Running ,但未处于“ Ready状态,则“就绪” 探针将失败。

发生这种情况时,pod无法连接到服务,流量也不会流向该服务。 准备就绪测试由于应用程序问题而失败。 在这种情况下,要查找错误,您需要分析kubectl describe命令输出中的“ Events部分。

2.服务诊断


如果pod列为Running and Ready ,但应用程序仍然没有响应,则应检查服务设置。

服务根据其标签将流量路由到Pod。 因此,要做的第一件事是检查服务中有多少个Pod。 为此,您可以检查服务中的端点:

 kubectl describe service <service-name> | grep Endpoints 

端点是一对格式为<IP-:> ,并且输出中必须存在至少一对这样的值(即,至少一个pod与该服务一起使用)。

如果“ Endpoins部分Endpoins空,则可能有两个选项:

  1. 没有带有正确标签的Pod(提示:检查是否正确选择了名称空间);
  2. 选择器中的服务标签有错误。

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

如何检查服务的可服务性?

无论服务类型如何,都可以使用kubectl port-forward命令连接到该服务:

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

在这里:

  • <service-name> - <service-name>
  • 3000-您在计算机上打开的端口;
  • 80-服务侧的端口。

3.入口诊断


如果您读过这个地方,那么:

  • 豆荚列为“ Running和“ Ready
  • 该服务成功在Pod之间分配流量。

但是,您仍然无法“扩展”到该应用程序。

这意味着很可能是Ingress控制器的配置不正确。 由于Ingress控制器是集群中的第三方组件,因此根据其类型有多种调试方法。

但是在使用特殊工具配置Ingress之前,您可以做一些非常简单的事情。 Ingress使用serviceNameservicePort连接到服务。 您必须验证它们是否正确配置。 您可以使用以下命令执行此操作:

 kubectl describe ingress <ingress-name> 

如果“ Backend空,则很可能出现配置错误。 如果后端到位,但是仍然无法访问该应用程序,则问题可能与以下方面有关:

  • 来自公共Internet的入口可访问性设置;
  • 来自公共Internet的群集可访问性设置。

您可以通过直接连接到Ingress窗格来识别基础结构问题。 为此,请首先找到Ingress控制器的Pod(它可以在其他名称空间中):

 kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS kube-system coredns-5644d7b6d9-jn7cq 1/1 Running kube-system etcd-minikube 1/1 Running kube-system kube-apiserver-minikube 1/1 Running kube-system kube-controller-manager-minikube 1/1 Running kube-system kube-proxy-zvf2h 1/1 Running kube-system kube-scheduler-minikube 1/1 Running kube-system nginx-ingress-controller-6fc5bcc 1/1 Running 

使用describe命令设置端口:

 kubectl describe pod nginx-ingress-controller-6fc5bcc --namespace kube-system \ | grep Ports 

最后,连接到吊舱:

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

现在,计算机上对端口3000的所有请求都将重定向到端口80 pod。

现在可以用吗?

  • 如果是这样,则问题出在基础架构上。 有必要准确找出流量如何路由到群集。
  • 如果不是,则问题出在Ingress控制器上。

如果您无法使Ingress控制器正常工作,则必须对其进行调试。

Ingress控制器的种类很多。 最受欢迎的是Nginx,HAProxy,Traefik等(有关现有解决方案的更多信息,请参见我们的评论 -大约翻译)。您应该使用相应控制器文档中的故障排除指南。 由于Ingress Nginx是最受欢迎的Ingress控制器,因此我们在本文中包含了一些解决相关问题的技巧。

调试Ingress Nginx控制器



Ingress-nginx项目具有kubectl的官方插件kubectl ingress-nginx命令可用于:

  • 分析日志,后端,证书等;
  • 与Ingress的连接;
  • 研究当前配置。

以下三个团队将为您提供帮助:

  • kubectl ingress-nginx lint检查nginx.conf ;
  • kubectl ingress-nginx backend -探索后端(类似于kubectl describe ingress <ingress-name> );
  • kubectl ingress-nginx logs -检查日志。

请注意,在某些情况下,可能需要使用--namespace <name>标志为Ingress控制器指定正确的名称空间。

总结


如果您不知道从哪里开始,那么诊断Kubernetes可能是一项艰巨的任务。 应该始终按照自下而上的原则来解决该问题:首先是Pod,然后再转到服务和Ingress。 本文中描述的调试方法可以应用于其他对象,例如:

  • 闲置的乔布斯和CronJobs;
  • StatefulSets和DaemonSets。

感谢Gergely RiskoDaniel WeibelCharles Christyraj提出的宝贵意见和补充。

译者的PS


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN484954/


All Articles