在我之前的文章中,我向你展示了如何使用8 个命令调试 Kubernetes 集群。现在我们需要看看,当你的工作负载没有像你预期的那样工作时会发生什么。
如果你遇到可怕的 CrashLoopBack 或其他故障,这并不重要。本文的命令将帮助你缩小工作负载问题的范围,以便你可以修复它们。
大多数命令将使用 kubectl 命令或通过krew安装的或插件。如果你不想使用插件,通常也可以从 kubectl获取相同的信息,但插件会格式化数据以使其更易于调试。
我们将假设你的代码有效,并且你知道哪个应用程序损坏以及它在何处运行。Kubernetes 无法修复损坏的代码。但是,如果你的容器无法启动或应用程序出现间歇性错误,你可以从这里开始。我们将跳过细节——例如查找应用程序正在运行的集群、region或命名空间,或者哪个版本是当前版本——因为这些对于你的环境来说是独一无二的。
有不同类型的工作负载错误,因此我们将其分解为故障排除的三个阶段:
- 工作负载无法运行
- 无法访问工作负载
- 调试特定的 pod
这个例子的命令和截图使用称为虚拟工作负载的“spider”,你可能看到在命令中带有`spider*,$LABEL 或$POD,针对你的环境,你应该用你的工作负载名称替换它。
工作负载无法运行
kubectl get events --field-selector type=Warning --all-namespaces
kubectl get nodes -o wide --label-columns topology.kubernetes.io/zone
kubectl resource-capacity --pods --util --sort cpu.util
kubectl get all --show-labels
kubectl lineage pod ${POD}
kail -l ${LABEL}
第一类错误适用于集群中的所有工作负载。无论是deployment、DaemonSet 还是 cron job都没有关系。在每种情况下,在你的节点上运行的东西都是一组称为 pod 的容器。Pod 是 Kubernetes 中最小的工作单元,因此我们需要查看 Pod 来修复应用程序问题也就不足为奇了。
就像集群故障排除一样,你应该从广度优先的方法开始,然后缩小特定问题的范围。应用程序可能不会在任何地方都失败,所以我们应该首先看看它失败的地方,发生了什么变化,以及有什么不同。
所有这些命令的最终目标是让你进入日志行或错误消息,说明为什么某些东西没有运行。这可能来自你的基础设施提供商、Kubernetes 控制器或你的应用程序。
1. kubectl get events --field-selector type=Warning --all-namespaces
首先,我们应该在集群中尽可能广泛地开始。根据集群中工作负载的大小和数量,此命令可能有很多输出。在较小的集群中,它可能足以指出工作负载为何不工作的一些明显问题。
你可能会在此命令中看到控制器和 Kubernetes 组件的错误,这可能会向你显示失败的原因或位置。在我们的示例截图中,你可以看到有警告,因为我们无法为 pod 分配 IP 地址。我们可能会在 kubelet 日志中看到这些相同的错误,但是查看集群中的所有警告将向我们展示错误如何级联到不同的控制器中。
2. kubectl get nodes -o wide –label-columns topology.kubernetes.io/zone
此输出对于任何调试过程都是相当常见的。你应该能够快速识别任何未处于“ready”状态或可能具有不同版本的 kubelet 或不同容器运行时的节点。通过添加拓扑区域输出,你还可以查看是否有任何节点问题与特定区域相关,该区域可能存在其他问题,例如网络分区或依赖服务不可用。
3. kubectl resource-capacity –pods –util –sort cpu.util
即使在容器世界中,你仍然必须处理 CPU 和内存资源。该resource-capacity插件,可以为你节省大量的命令,帮你快速找出如何节点和Pod使用的资源情况。你可以使用kubectl krew install resource-capacity命令安装这个插件.
请务必注意:此插件要求你在集群中安装metrics-server。运行后,你应该能够使用此命令查找资源受限或未设置限制的潜在问题。
4. kubectl get all –show-labels
此命令不会向我们显示所有内容,但我们真正关心的是deployment、Pod 和service。通过包含每个工作负载的标签,我们可以看到pod-template-hash 标签之类的东西,这将为我们提供一个哈希值,你可以在我们的deployment和 pod 之间进行匹配。如果有 Pod 没有运行,我们就知道下一步该往哪里看。
在这一点上,最好也查看一下service,看看它是什么类型。如果它是 LoadBalancer 类型,那么你应该确保已配置负载均衡器。如果你的所有 Pod 都在运行,那么应用程序问题可能不是来自 Pod。以防万一,我们应该获取其中一个 pod 名称,以便我们可以在接下来的几个命令中对其进行更多检查。
5. kubectl lineage pod ${POD}
该lineage 命令是另一个kubectl插件,可以显示Kubernetes创建了什么资源,什么依赖于它。如果你曾经使用过kubectl tree,你就会熟悉 lineage,但是 lineage 有一些额外的功能。你可以使用kubectl krew install lineage来安装这个插件.
关于此命令,我最喜欢的功能之一是它不仅显示集群中的 ReplicaSet 和service等 Kubernetes 资源,而且还显示事件、RBAC(基于角色的访问控制)、节点,并具有原生 helm 支持。默认情况下,该命令将显示依赖项,但通过该--dependencies 标志,你可以查看依赖于资源的内容。
你还可以查看 metrics-server之类的服务,并查看所有 ClusterRoleBindings 以及该服务背后的 Pod 和节点。
6. kail -l ${LABEL}
我们最后的工作负载故障排除命令将根据标签向我们显示工作负载的所有日志。kail 是一个独立的工具,而不是一个kubectl 插件,可以通过brew install boz/repo/kail. 使用它的好处是,它可以完成一些通常用单个kubectl命令很难做到的事情。
例如,你可以使用--ns,查询来自一个特定的名称空间所有日志;使用--ing查询ingress规则匹配的所有Pod。
无法访问工作负载
kubectl get service -o wide
kubectl get endpointslices -o wide
kubectl port-forward deploy $DEPLOYMENT $LOCAL_PORT:$POD_PORT
7. kubectl get service -o wide
你应该首先查看集群中的服务,因为这是流量路由进出集群的主要方式。如果你使用 ingress 进行流量路由,那么你还需要使用kubectl get ingress -o wide. 要检查的重要事情是它是什么类型的服务,是否有外部 IP 地址或负载平衡器,以及使用了哪些标签。
根据我们之前从列出工作负载中收集的数据,我们应该能够将 pod 上使用的标签与服务上的匹配标签进行比较。如果它们不匹配,它们将不会成为 EndpointSlice 的一部分。
8. kubectl get endpointslices -o wide
接下来我们可以查看 EndpointSlices。这将向我们展示命名空间中的每个服务以及哪些 pod IP 地址与该服务相关联。如果你看到没有任何端点的服务,则需要验证 pod 是否已准备就绪且标签是否匹配。
9. kubectl port-forward deploy/DEPLOYMENT LOCAL_PORT:POD_PORT
此命令将让我们绕过负载均衡器或入口控制器,以查看是否可以将流量直接发送到deployment中的 Pod 之一。如果你怀疑某个 pod 有问题,你还可以将流量直接转发到 pod。这将帮助我们排除我们的服务、负载均衡器和一些网络配置的错误,因为你的连接通过 Kubernetes API 服务器。
调试特定的 Pod
kubectl debug -it --image=debian $POD
kubectl label pod $POD app-
kubectl blame pod
如果我们已经走了这么远但仍然没有解决问题,我们可以使用一些额外的命令来查看特定的 pod,看看我们是否可以确定发生了什么。
10. kubectl debug pod –it –image=debian POD
debug 命令需要 在你的集群上启用临时容器。目前,这是 Kubernetes 1.22 的 alpha 功能,因此它可能尚未在你的集群中可用。
有时,解决问题的最快方法是使用交互式 shell。有几种不同的方法可以在正在运行的 pod 中获取 shell,但这debug 是我最喜欢的。该debug 命令不同于exec , 因为exec要求你的 pod 已经安装了调试工具。但是,该debug 命令将让你指定一个新容器,你可以将其“挂载”到正在运行的 Pod,然后使用你自己的工具。
你可以为你的工具提供任何你想要的容器;不同的错误可能需要不同的工具。我通常有一个带有预安装工具的专用调试容器,但如果你没有,你可以使用你熟悉的完整发行版来安装你需要的任何工具。使用临时容器调试某些东西的一件很酷的事情是,这也适用于已构建且没有其他文件或包管理器的静态二进制容器。
该debug命令还可用于在节点上获取交互式 shell。这类似于通过 SSH 连接到节点,但 debug 命令在安装了工具的情况下以特权模式运行容器。如果你使用的是最小容器操作系统或不在节点上配置 SSH 访问,这将特别有用。
在Kubernetes 文档中,还有更多关于将交互式 shell 连接到 pod 的选项。
11. kubectl label pod $POD app-**
这是我在 Kubernetes 中最喜欢的调试命令之一。默认情况下,deployment会为你的 Pod 添加一个标签,例如app=nginx. 当你使用服务公开deployment时,它也会在该标签上匹配。通过运行此命令,你将从 pod 中删除app 标签。
因为副本控制器和service服务对象匹配标签,所以一旦你删除了应用程序标签,一个新的 Pod 将替换你从中删除标签的 Pod,但它会让你的 Pod 继续运行。你现在拥有了一个 Pod,你可以对其进行故障排除,而无需担心向其发送生产流量或从水平 Pod 自动缩放器扩展或缩减 Pod。当你删除标签时,实际上不会跟踪 pod。
在截图中,你可以看到我删除了标签app,这导致一个新的 pod 替换了它,并留下了旧的 pod 可供我调试。
12. kubectl blame pod $POD
blame 命令是一个伟大的插件,你可以用它来看看有什么Pod的零件清单发生了变化,谁或什么改变了他们。你可以使用kubectl krew install blame进行安装. 通过此输出,你可以快速找出哪些控制器修改了清单,并可以查看这些组件以了解它们更改它的原因。
这里的输出并不完美;它不会显示对清单的所有修改。由于 webhook 或默认值,一些字段在存储到 etcd 之前被修改。但是,了解字段更改的频率以及哪些控制器正在修改清单中的哪些字段仍然非常强大。
其他优秀插件
还有一些其他插件可以更深入地研究工作负载,但其中一些需要集群中的特定功能或节点上的其他守护程序。
值得一提的两个是可以安装的inspecktor-gadget和kubectl-capture,它可以创建使用诸如sysdig-inspect 之类的工具得到的捕获文件。
这两个插件都要求你在节点上安装 DaemonSets,但如果你需要深入研究工作负载的问题,它们会非常强大。他们都使用内核级应用程序,使用eBPF 来理解发生的一切。
调试工作负载的 UI 工具
所有这些命令都可以很好地帮助你入门。你应该能够更多地了解你的工作负载并找出问题所在。还有其他值得一提的故障排除选项。在某些情况下,这些 UI 可以在同一屏幕中组合来自多个这些命令的信息。
首先要提到的是k9s。此工具在你的终端中作为终端用户界面 (TUI) 运行,使你可以更轻松地浏览资源和查看其他信息。你可以从 GitHub 存储库安装 k9s,并开始在任何 Kubernetes 集群中使用它。
https://github.com/derailed/k9s
另一种选择是 Mirantis 的 Lens。Lens 是一个独立的应用程序,能够快速切换 Kubernetes 集群,并为你进行故障排除带来大量附加信息。如果你想要功能更齐全的 Kubernetes UI,Lens 是一个不错的选择。你可以从Lens | The Kubernetes IDE安装它 。
译文链接:Living with Kubernetes: 12 Commands to Debug Your Workloads – The New Stack