前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解 K8S Pod 调试与实践技巧

深入理解 K8S Pod 调试与实践技巧

作者头像
我的小碗汤
发布2023-03-20 09:05:52
6690
发布2023-03-20 09:05:52
举报
文章被收录于专栏:我的小碗汤我的小碗汤

调试运行中的容器和 Pod 不像直接调试进程那么容易,本文介绍了通过临时容器共享命名空间的方式调试业务容器进程的方法。调试 pod 最简单的方法是在有问题的 pod 中执行命令,并尝试排除故障。这种方法很简单,但有许多缺点。

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

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

kubectl exec不够用时(比如容器已经崩溃,或者容器镜像没有包含调试实用程序,比如 distroless 镜像),或者正在运行的 pod 没有调试所需的特权时,临时容器 ephemeral container 对于交互式故障排除非常有用。

https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/

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

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

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

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

https://kind.sigs.k8s.io/

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

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

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

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

创建简单工作负载

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

代码语言:javascript
复制
kubectl create deployment nginx --image=nginx

诊断网络故障

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

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

代码语言:javascript
复制
kubectl debug -it pod-name --image=<ephemeral-container> -- command

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

代码语言:javascript
复制
systemd-cgls -u kubelet-kubepods-besteffort.slice

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

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

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

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

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

代码语言:javascript
复制
tcpdump -n port 80

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

代码语言:javascript
复制
curl http://pod-ip-adderss

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

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

接下来看第二个用例。

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

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

为此,我们需要:

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

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

代码语言:javascript
复制
kubectl debug -it <pod-name > --image=nicolaka/netshoot --target <container-name> -- bash
📷

正如上面截图可以看到:

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

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

代码语言:javascript
复制
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

📷

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

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

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

📷

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

通过节点上的 shell 进行调试

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

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

代码语言:javascript
复制
kubectl debug node/<node-name> -it --image=<image-name>

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

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-10-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 进击云原生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用临时调试容器进行调试
  • 创建简单工作负载
  • 诊断网络故障
  • 利用临时容器跟踪/分析进程
  • 通过节点上的 shell 进行调试
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档