深入理解 Kubernetes Pod 调试

简介: 深入理解 Kubernetes Pod 调试

调试运行中的容器和 Pod 不像直接调试进程那么容易,本文介绍了通过临时容器共享命名空间的方式调试业务容器进程的方法。原文: Debugging Kubernetes Pods: Deep Dive


image.png

调试 pod 最简单的方法是在有问题的 pod 中执行命令,并尝试排除故障。这种方法很简单,但有许多缺点。


  • 正在运行的应用 pod 可能没有排除现有问题所需的所有工具。
  • 如果想执行一些需要额外权限的操作,需要重新启动应用 pod,以添加新的权限。
  • 在 docker 镜像中添加调试工具会引入安全风险,提升容器权限也是如此。


因此,我们需要探索其他调试 pod 的方法。


使用临时调试容器进行调试


kubectl exec不够用时(比如容器已经崩溃,或者容器镜像没有包含调试实用程序,比如 distroless 镜像),或者正在运行的 pod 没有调试所需的特权时,[临时容器(ephemeral container)](https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/ "临时容器(ephemeral container "临时容器(ephemeral container)")")对于交互式故障排除非常有用。


临时容器背后的主要思想是,K8S 将具有选定自定义镜像的新容器添加到现有 pod 中,而不需要重新启动该 pod。这个新的容器可以共享目标容器的资源,包括:


  • Linux 网络命名空间
  • Linux 进程命名空间
  • 访问共享卷
  • 访问 K8S 节点


我将为每个用例提供一个示例。


在开始演示前,需要有一个版本为 1.23 的 k8s 集群,建议使用kind,但也可以使用其他任何配置器。


我们从创建演示集群开始。


创建 kind 集群

创建新集群很简单,只需运行命令kind create cluster


示例:


image.png


一旦创建了集群,需要验证是否启动并可访问。


示例:


image.png


所有操作都将从主kind节点执行,所以需要通过docker exec -it  bash访问。


示例:


image.png


创建简单工作负载


假设需要调试 Nginx,我们创建一个单副本 Nginx 部署,通过运行以下命令来完成。


kubectl create deployment nginx --image=nginx


image.png


诊断网络故障


诊断网络故障需要共享网络命名空间。当将临时容器附加到运行中的 pod 时,这是默认的 Linux 命名空间。


接下来我们创建第一个临时容器,使用nicolaka/netshoot作为新的临时容器的镜像,该镜像包含许多故障排除工具,如tcpdumpstrace


kubectl debug -it pod-name --image=<ephemeral-container> -- command



示例:


image.png


我们确认一下两个容器共享相同的 Linux 命名空间。在主节点上打开一个新 shell,并运行此命令:


systemd-cgls -u kubelet-kubepods-besteffort.slice



示例:


image.png


从上面的例子中,可以得到两个容器的主进程 ID:


  • 2612 -> 临时容器的主进程 ID
  • 2259 -> Nginx 容器的主进程 ID


接下来,检查每个进程的 Linux 命名空间。


image.png


从截图中可以发现,两个进程具有相同的 Linux 网络命名空间 ID。


现在我们从临时容器中抓取 Nginx 容器的网络数据包。


从临时容器 shell 运行此命令:


tcpdump -n port 80



示例:


image.png


现在,试着从 k8s 主节点向这个 pod 发送一些请求。


curl http://pod-ip-adderss


image.png


现在观察临时容器终端,会发现 TCP 报文会被打印出来:


image.png


第一个演示完成,现在我们可以从临时容器捕获网络数据包了。


接下来看第二个用例。


利用临时容器跟踪/分析进程


下一个用例是从临时容器跟踪应用容器中运行的进程。


为此,我们需要:


  • 这两个容器必须共享相同的 Linux 进程命名空间。
  • 临时容器必须具有 Linux capability SYS_PTRACE


创建临时容器时,通过添加额外参数--target ,可以轻松共享 Linux 进程命名空间。


kubectl debug -it <pod-name > --image=nicolaka/netshoot --target <container-name> -- bash



示例:


image.png


正如上面截图可以看到:


  1. 为了共享进程命名空间,需要添加额外的命令行参数--target
  2. 从临时容器中,可以看到nginx容器中所有正在运行的进程
  3. 因为临时容器没有ptrace系统调用所需权限,因此无法跟踪nginx进程。该系统调用被strace命令用来暂停 Linux 进程,记录nginx发送给内核的每个系统调用。


如何解决这个问题?很不幸,我没有找到从kubectl命令向临时容器传递额外权限的方法。因此,我们将构造并发送 HTTP 请求到 kube API 服务器,而不使用kubectl命令。


curl -v -XPATCH -H "Content-Type: application/json-patch+json" \
'http://127.0.0.1:8001/api/v1/namespaces/default/pods/nginx-8f458dc5b-wkvq4/ephemeralcontainers' \
--data-binary @- << EOF
[{
"op": "add", "path": "/spec/ephemeralContainers/-",
"value": {
"command":[ "/bin/sh" ],
"stdin": true, "tty": true,
"image": "nicolaka/netshoot",
"name": "debug-strace",
"securityContext": {"capabilities": {"add": ["SYS_PTRACE"]}},
"targetContainerName": "nginx" }}]
EOF


现在可以在权限不被拒绝的情况下调用strace


image.png


本例给临时容器添加了执行SYS_PTRACE的权限,但具体给什么权限取决于所用的调试器,或者简单点可以给临时容器特权访问,从而不需要担心需要允许哪个系统调用。


另外,可以从临时容器访问nginx容器的文件系统。根文件系统位于/proc//root目录下。


我们看看是否可以从临时容器访问nginx配置。


示例:


image.png


好了,接下来我们看一下临时容器的最后一个用例。


通过节点上的 shell 进行调试

有时候我们需要访问 k8s 节点,但却没有对节点的 ssh 或控制台访问权限。


这时候可以通过临时容器访问节点。


kubectl debug node/<node-name> -it --image=<image-name>



在节点上创建调试会话时,请记住:


  • kubectl debug会根据节点名称自动生成新 Pod 的名称。
  • 容器运行在主机 IPC、Network 和 PID 命名空间中。
  • 节点根文件系统将挂载在/host上。


如果希望临时容器的根文件系统与节点相同,只需要将chroot /host


示例:

image.png


延伸阅读


Debug Running Pods


Manage containers in namespaces by using nsenterDebugging With Ephemeral Containers


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
2月前
|
存储 Kubernetes 调度
【赵渝强老师】什么是Kubernetes的Pod
Pod 是 Kubernetes 中的基本逻辑单位,代表集群上的一个应用实例。它可以由一个或多个容器组成,并包含数据存储和网络配置等资源。Pod 支持多种容器执行环境,如 Docker。Kubernetes 使用 Pod 管理容器,具有简化部署、方便扩展和调度管理等优点。视频讲解和图示详细介绍了 Pod 的组成结构和使用方式。
|
1天前
|
Kubernetes 容器 Perl
【赵渝强老师】Kubernetes中Pod的探针
在K8s集群中,kubelet通过三种探针(存活、就绪、启动)检查Pod容器的健康状态。存活探针确保容器运行,失败则重启;就绪探针确保容器准备好服务,失败则从Service中剔除;启动探针确保应用已启动,失败则重启容器。视频讲解和图片详细介绍了这三种探针及其检查方法(HTTPGet、Exec、TCPSocket)。
【赵渝强老师】Kubernetes中Pod的探针
|
2月前
|
存储 Kubernetes Docker
【赵渝强老师】Kubernetes中Pod的基础容器
Pod 是 Kubernetes 中的基本单位,代表集群上运行的一个进程。它由一个或多个容器组成,包括业务容器、基础容器、初始化容器和临时容器。基础容器负责维护 Pod 的网络空间,对用户透明。文中附有图片和视频讲解,详细介绍了 Pod 的组成结构及其在网络配置中的作用。
【赵渝强老师】Kubernetes中Pod的基础容器
|
2月前
|
Prometheus Kubernetes 监控
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
|
2月前
|
运维 Kubernetes Shell
【赵渝强老师】K8s中Pod的临时容器
Pod 是 Kubernetes 中的基本调度单位,由一个或多个容器组成,包括业务容器、基础容器、初始化容器和临时容器。临时容器用于故障排查和性能诊断,不适用于构建应用程序。当 Pod 中的容器异常退出或容器镜像不包含调试工具时,临时容器非常有用。文中通过示例展示了如何使用 `kubectl debug` 命令创建临时容器进行调试。
|
2月前
|
Kubernetes 调度 容器
【赵渝强老师】K8s中Pod中的业务容器
Pod 是 Kubernetes 中的基本调度单元,由一个或多个容器组成。除了业务容器,Pod 还包括基础容器、初始化容器和临时容器。本文通过示例介绍如何创建包含业务容器的 Pod,并提供了一个视频讲解。示例中创建了一个名为 &quot;busybox-container&quot; 的业务容器,并使用 `kubectl create -f firstpod.yaml` 命令部署 Pod。
|
2月前
|
Kubernetes 容器 Perl
【赵渝强老师】K8s中Pod中的初始化容器
Kubernetes的Pod包含业务容器、基础容器、初始化容器和临时容器。初始化容器在业务容器前运行,用于执行必要的初始化任务。本文介绍了初始化容器的作用、配置方法及优势,并提供了一个示例。
|
2月前
|
存储 Kubernetes 调度
深入理解Kubernetes中的Pod与Container
深入理解Kubernetes中的Pod与Container
109 0
|
2月前
|
Kubernetes Java 调度
Kubernetes中的Pod垃圾回收策略是什么
Kubernetes中的Pod垃圾回收策略是什么
|
2月前
|
存储 Kubernetes 调度
深度解析Kubernetes中的Pod生命周期管理
深度解析Kubernetes中的Pod生命周期管理