内容简介:容器技术的一个最佳实践是构建尽可能精简的容器镜像。但这一实践却会给排查问题带来麻烦:精简后的容器中普遍缺失常用的排障工具,部分容器里甚至没有 shell (比如 FROM scratch )。 在这种状况下,我们只能通过日志或者到宿主机上通过 docker-cli 或 nsenter 来排查问题,效率很低。Kubernetes 社区也早就意识到了这个问题,在 16 年就有相关的 Issue我们先不着急进入 Quick Start 环节。 kubectl-debug 本身非常简单,因此只要理解了它的工作原理,
背景
容器技术的一个最佳实践是构建尽可能精简的容器镜像。但这一实践却会给排查问题带来麻烦:精简后的容器中普遍缺失常用的排障工具,部分容器里甚至没有 shell (比如 FROM scratch )。 在这种状况下,我们只能通过日志或者到宿主机上通过 docker-cli 或 nsenter 来排查问题,效率很低。Kubernetes 社区也早就意识到了这个问题,在 16 年就有相关的 Issue Support for troubleshooting distroless containers 并形成了对应的 Proposal 。 遗憾的是,由于改动的涉及面很广,相关的实现至今还没有合并到 Kubernetes 上游代码中。而在 一个偶然的机会下(PingCAP 一面要求实现一个 kubectl 插件实现类似的功能),我开发了 kubectl-debug :通过启动一个安装了各种排障 工具 的容器,来帮助诊断目标容器。
工作原理
我们先不着急进入 Quick Start 环节。 kubectl-debug 本身非常简单,因此只要理解了它的工作原理,你就能完全掌握这个工具,并且还能用它做 debug 之外的事情。 如果你想和更多 Kubernetes 技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态
我们知道,容器本质上是带有 Cgroup 资源限制和 Namespace 隔离的一组进程。因此,我们只要启动一个进程,并且让这个进程加入到目标容器的各种 Namespace 中,这个进程就能 “进入容器内部”(注意引号),与容器中的进程”看到”相同的根文件系统、虚拟网卡、进程空间了——这也正是 docker exec 和 kubectl exec 等命令的运行方式。
现在的状况是,我们不仅要 “进入容器内部”,还希望带一套工具集进去帮忙排查问题。那么,想要高效管理一套工具集,又要可以跨平台,最好的办法就是把工具本身都打包在一个容器镜像当中。 接下来,我们只需要通过这个”工具镜像”启动容器,再指定这个容器加入目标容器的的各种 namespace,自然就实现了 “携带一套工具集进入容器内部”。事实上,使用 docker-cli 就可以实现这个操作:
export TARGET_ID=666666666 # 加入目标容器的 network, pid 以及 ipc namespace docker run -it --network=container:$TARGET_ID --pid=container:$TARGET_ID --ipc=container:$TARGET_ID busybox
这就是 kubectl-debug 的出发点: 用工具容器来诊断业务容器 。背后的设计思路和 sidecar 等模式是一致的:每个容器只做一件事情。
具体到实现上,一条 kubectl debug <target-pod> 命令背后是这样的:
步骤分别是:
- 插件查询 ApiServer:demo-pod 是否存在,所在节点是什么
- ApiServer 返回 demo-pod 所在所在节点
- 插件请求在目标节点上创建 Debug Agent Pod
- Kubelet 创建 Debug Agent Pod
- 插件发现 Debug Agent 已经 Ready,发起 debug 请求(长连接)
- Debug Agent 收到 debug 请求,创建 Debug 容器并加入目标容器的各个 Namespace 中,创建完成后,与 Debug 容器的 tty 建立连接
接下来,客户端就可以开始通过 5,6 这两个连接开始 debug 操作。操作结束后,Debug Agent 清理 Debug 容器,插件清理 Debug Agent,一次 Debug 完成。效果如下图:
开始使用
Mac 可以直接使用 brew 安装:
brew install aylei/tap/kubectl-debug
所有平台都可以通过下载 binary 安装:
export PLUGIN_VERSION=0.1.1 # linux x86_64 curl -Lo kubectl-debug.tar.gz https://github.com/aylei/kubectl-debug/releases/download/v${PLUGIN_VERSION}/kubectl-debug_${PLUGIN_VERSION}_linux_amd64.tar.gz # macos curl -Lo kubectl-debug.tar.gz https://github.com/aylei/kubectl-debug/releases/download/v${PLUGIN_VERSION}/kubectl-debug_${PLUGIN_VERSION}_darwin_amd64.tar.gz tar -zxvf kubectl-debug.tar.gz kubectl-debug sudo mv kubectl-debug /usr/local/bin/
Windows 用户可以在 Release 页面 进行下载。
下载完之后就可以开始使用 debug 插件:
kubectl debug target-pod --agentless --port-forward
kubectl 从 1.12 版本之后开始支持从 PATH 中自动发现插件。1.12 版本之前的 kubectl 不支持这种插件机制,但也可以通过命令名 kubectl-debug 直接调用。
可以参考项目的 中文 README 来获得更多文档和帮助信息。
典型案例
基础排障
kubectl debug 默认使用 nicolaka/netshoot 作为默认的基础镜像,里面内置了相当多的排障工具,包括:
使用 iftop 查看容器网络流量:
使用 drill 诊断 DNS 解析:
使用 tcpdump 抓包:
访问目标容器的根文件系统:
容器技术(如 Docker)利用了 /proc 文件系统提供的 /proc/{pid}/root/ 目录实现了为隔离后的容器进程提供单独的根文件系统(root filesystem)的能力(就是 chroot 一下)。当我们想要访问 目标容器的根文件系统时,可以直接访问这个目录:
这里有一个常见的问题是 free top 等依赖 /proc 文件系统的命令会展示宿主机的信息,这也是容器化过程中开发者需要适应的一点(当然了,各种 runtime 也要去适应,比如臭名昭著的 Java 8u121 以及更早的版本不识别 cgroups 限制 问题就属此列)。
诊断 CrashLoopBackoff
排查 CrashLoopBackoff 是一个很麻烦的问题,Pod 可能会不断重启, kubectl exec 和 kubectl debug 都没法稳定进行排查问题,基本上只能寄希望于 Pod 的日志中打印出了有用的信息。 为了让针对 CrashLoopBackoff 的排查更方便, kubectl-debug 参考 oc debug 命令,添加了一个 --fork 参数。当指定 --fork 时,插件会复制当前的 Pod Spec,做一些小修改, 再创建一个新 Pod:
- 新 Pod 的所有 Labels 会被删掉,避免 Service 将流量导到 fork 出的 Pod 上
- 新 Pod 的 ReadinessProbe 和 LivnessProbe 也会被移除,避免 kubelet 杀死 Pod
- 新 Pod 中目标容器(待排障的容器)的启动命令会被改写,避免新 Pod 继续 Crash
接下来,我们就可以在新 Pod 中尝试复现旧 Pod 中导致 Crash 的问题。为了保证操作的一致性,可以先 chroot 到目标容器的根文件系统中:
结尾的碎碎念
kubectl-debug 一开始只是 PingCAP 在面试时出的 homework,第一版完成在去年年底。当时整个项目还非常粗糙,不仅文档缺失,很多功能也都有问题:
- 不支持诊断 CrashLoopBackoff 中的 Pod
- 强制要求预先安装一个 Debug Agent 的 DaemonSet
- 不支持公有云(节点没有公网 IP 或公网 IP 因为防火墙原因无法访问时,就无法 debug)
- 没有权限限制,安全风险很大
而让我非常兴奋的是,在我无暇打理项目的情况下,隔一两周就会收到 Pull Request 的通知邮件,一直到今天,大部分影响基础使用体验的问题都已经被解决, kubectl-debug 也发布了 4 个版本( 0.0.1, 0.0.2, 0.1.0, 0.1.1 )。尤其要感谢 @tkanng ,TA 在第一个 PR 时还表示之前没有写过 Go, 而在 0.1.1 版本中已经是这个版本绝大部分 feature 的贡献者,解决了好几个持续很久的 issue,感谢!
最后再上一下项目地址: https://github.com/aylei/kubectl-debug
假如在使用上或者对项目本身有任何问题,欢迎提交 issue,也可以在 文章评论区留言讨论。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。