Kubernetes 故障排除可视化指南

笔记。 翻译。:本文是在公共领域发布的项目材料的一部分 学习8s,培训公司和个人管理员使用 Kubernetes。 在其中,项目经理 Daniele Polencic 分享了关于在 K8s 集群上运行的应用程序出现一般问题时应采取哪些步骤的可视化说明。

Kubernetes 故障排除可视化指南

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

Kubernetes 故障排除可视化指南

查找和修复集群中错误的流程图。 原文(英文)可在 PDF и 如图.

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

  • 部署 - 这是一种创建应用程序副本的方法,称为 pod;
  • 服务 — 在 Pod 之间分配流量的内部负载均衡器;
  • 入口 — 流量如何从外部世界到达服务的描述。

这是一个快速的图形摘要:

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

Kubernetes 故障排除可视化指南

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

Kubernetes 故障排除可视化指南

3) Deployment 创建 Pod 并监控它们(它们不是手动创建的)。

Kubernetes 故障排除可视化指南

假设您想部署一个简单的应用程序 你好世界。 它的 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?
  • 我应该为每个服务创建一个新端口,这样它们就不会发生冲突吗?
  • 标签名称重要吗? 它们应该在任何地方都一样吗?

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

部署与服务的关系

您会感到惊讶,但部署和服务根本没有联系。 相反,Service 绕过 Deployment 直接指向 Pod。

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

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

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

1) 假设该服务将流量定向到某个 pod:

Kubernetes 故障排除可视化指南

2)创建pod时,必须指定 containerPort 对于 Pod 中的每个容器:

Kubernetes 故障排除可视化指南

3)创建服务时,必须指定 port и targetPort. 但使用哪一个来连接容器呢?

Kubernetes 故障排除可视化指南

4)通过 targetPort。 必须匹配 containerPort.

Kubernetes 故障排除可视化指南

5) 假设容器中打开了3000端口,那么该值 targetPort 应该是一样的。

Kubernetes 故障排除可视化指南

在 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 在部署部分的顶部? 应该匹配吗?

此标签是特定于部署的,服务不使用它来路由流量。 换句话说,它可以被删除或分配不同的值。

选择器怎么样 matchLabels?

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

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

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

kubectl get pods --show-labels

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

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

哪里 any-name=my-app 是一个标签 any-name: my-app.

还有什么困难吗?

您可以连接到 Pod! 为此,您需要使用命令 port-forward 在 kubectl. 它允许您连接到服务并检查连接。

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

在这里:

  • service/<service name> - 服务名称; 在我们的例子中是 my-service;
  • 3000是电脑上需要开放的端口;
  • 80 - 字段中指定的端口 port 服务。

如果连接已建立,则设置正确。

如果连接失败,则表明标签有问题或端口不匹配。

Service与Ingress的关系

提供对应用程序的访问的下一步涉及设置 Ingress。 Ingress 需要知道如何找到服务,然后找到 Pod 并将流量定向到它们。 Ingress 通过名称和开放端口查找所需的服务。

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

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

下图总结了端口连接:

1) 如您所知,Service 会监听特定的 port:

Kubernetes 故障排除可视化指南

2)Ingress有一个参数叫 servicePort:

Kubernetes 故障排除可视化指南

3)该参数(servicePort) 必须始终匹配 port 在服务定义中:

Kubernetes 故障排除可视化指南

4) 如果Service中指定了80端口,则需要 servicePort 也等于 80:

Kubernetes 故障排除可视化指南

实际操作中,需要注意以下几行:

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 pod(它可能位于不同的命名空间中)并运行命令 describe找出端口号:

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

最后,连接到 pod:

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

现在,每次您向计算机上的端口 3000 发送请求时,该请求都会通过 Ingress 控制器转发到 pod 的端口 80。 通过去 http://localhost:3000,您应该看到应用程序生成的页面。

端口总结

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

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

不幸的是,仅仅知道如何正确构建 YAML 配置是不够的。

当出现问题时会发生什么?

Pod 可能无法启动或崩溃。

诊断 Kubernetes 中应用程序问题的 3 个步骤

在开始调试部署之前,您需要充分了解 Kubernetes 的工作原理。

由于K8s中下载的每个应用程序都具有三个组件,因此应该按照一定的顺序对它们进行调试,从最底层开始。

  1. 首先,您需要确保 Pod 正常工作,然后......
  2. 检查服务是否向 Pod 提供流量,然后...
  3. 检查 Ingress 配置是否正确。

视觉表现:

1)你应该从最底层开始寻找问题。 首先检查 pod 是否有状态 Ready и Running:

Kubernetes 故障排除可视化指南

2) 如果 Pod 准备就绪 (Ready),您应该查明该服务是否在 Pod 之间分配流量:

Kubernetes 故障排除可视化指南

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

Kubernetes 故障排除可视化指南

1. Pod 的诊断

大多数情况下,问题与 Pod 有关。 确保 Pod 列为 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 被列为 Running и Ready然而,另外两人却并非如此。

如何理解出了什么问题?

有四个有用的命令可用于诊断 pod:

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

你应该选择哪一个?

事实是,不存在通用命令。 应结合使用这些方法。

典型的 Pod 问题

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

启动错误:

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

运行时错误:

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

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

图像拉回关闭

当 Kubernetes 无法获取其中一个 pod 容器的映像时,就会出现此错误。 以下是三个最常见的原因:

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

前两个原因很容易消除 - 只需更正图像名称和标签即可。 对于后者,您需要在 Secret 中输入封闭注册表的凭据,并在 pod 中添加指向它的链接。 在 Kubernetes 文档中 有一个例子 如何做到这一点。

崩溃循环回退

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

  1. 应用程序中存在一个错误,导致其无法启动;
  2. 容器 配置不正确;
  3. 活性测试失败次数过多。

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

kubectl logs <pod-name> --previous

它显示容器先前版本的错误消息。

运行容器错误

当容器无法启动时会出现此错误。 它对应于应用程序启动之前的时刻。 通常是由于设置不正确造成的,例如:

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

该团队非常适合分析此类错误 kubectl describe pod <pod-name>.

Pod 处于 Pending 状态

创建后,Pod 保持在状态 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

Pod 尚未就绪

如果 pod 列为 Running,但未处于状态 Ready,意味着检查其准备情况 (就绪探针) 失败。

发生这种情况时,Pod 不会连接到服务,并且没有流量流向它。 就绪测试失败是由应用程序中的问题引起的。 在这种情况下,要找到错误,您需要分析该部分 Events 在命令输出中 kubectl describe.

2. 服务诊断

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

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

kubectl describe service <service-name> | grep Endpoints

端点是一对形式的值 <IP-адрес:порт>,并且输出中必须至少存在一对这样的(即,至少有一个 Pod 与该服务一起工作)。

如果节 Endpoins 空,有两种选择:

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

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

如何检查服务的功能?

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

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

在这里:

  • <service-name> - 服务名称;
  • 3000是你在电脑上打开的端口;
  • 80 - 服务端端口。

3. 入口诊断

如果您已经读到这里,那么:

  • pod 列为 Running и Ready;
  • 该服务成功在 Pod 之间分配流量。

但是,您仍然无法访问该应用程序。

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

但在使用特殊工具来配置 Ingress 之前,您可以做一些非常简单的事情。 入口用途 serviceName и servicePort 连接到该服务。 您需要检查它们是否配置正确。 您可以使用以下命令执行此操作:

kubectl describe ingress <ingress-name>

如果列 Backend 为空,很有可能配置错误。 如果后端已就位,但应用程序仍然无法访问,则问题可能与以下内容有关:

  • 从公共互联网进入辅助功能设置;
  • 来自公共互联网的集群可访问性设置。

您可以通过直接连接到 Ingress Pod 来识别基础设施的问题。 为此,首先找到 Ingress Controller 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

最后,连接到 pod:

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

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

现在有用吗?

  • 如果是,那么问题出在基础设施上。 有必要弄清楚流量是如何路由到集群的。
  • 如果不是,则问题出在 Ingress 控制器上。

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

Ingress 控制器有很多种。 最流行的是 Nginx、HAProxy、Traefik 等。 (有关现有解决方案的更多信息,请参阅 我们的评论 - 大约。 译) 您应该参阅相关控制器文档中的故障排除指南。 因为 入口 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 — 检查日志。

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

总结

如果您不知道从哪里开始,对 Kubernetes 进行故障排除可能会很困难。 您应该始终自下而上解决问题:从 pod 开始,然后继续到服务和 Ingress。 本文中描述的调试技术可以应用于其他对象,例如:

  • 空闲作业和 CronJobs;
  • StatefulSet 和 DaemonSet。

我表达我的感激之情 盖尔盖利里斯科, 丹尼尔·韦贝尔 и 查尔斯·克里斯蒂拉吉 提出宝贵意见和补充。

译者PS

另请阅读我们的博客:

来源: habr.com

添加评论