当下我司某客户的容器云上应用投产规模已达200多系统,经常遇到线上Pod状态异常时,因Pod应用日志输出不足,难以诊断的问题;同时还要面对Pod容器镜像最小化导致缺少调试命令;程序所在的Pod崩溃偶发性难以复现,重启Pod就会丢失问题现场等场景。本文介绍的kubectl debug ,提供了一种快速、临时的方式来创建调试容器,以便在运行的 Pod 中进行故障排查和排除,极大地丰富了调试措施,助力线上应用持续安全运营。
一、kubectl debug命令原理
kubectl debug使用的是kubernetes中的临时容器(Ephemeral Containers)这一特性。通过在需要调试的Pod中添加一个临时容器,来提供更多调试功能。区别于以往通过kubectl exec 连接到Pod中只能提供一个交互式命令行终端,使用kubectl debug 向Pod中添加一个临时容器,意味着不仅可以获得一个交互式命令行终端,还可以将需要的工具打包带入要调试的Pod。
临时容器原理:通过向需要调试的Pod中添加一个新的容器,来共享当前Pod的命名空间。此命名空间是指Pod的宿主机Linux系统中的命名空间,而非Kubernetes环境中的namespace。容器的原理是在宿主机的Linux系统中创建了6个命名空间以及一个cgroup (Linux内核4.6版本以后也被划为命名空间范畴) 来隔离出一个运行环境以供程序使用。每个容器在创建时都会在其宿主机系统中创建对应的namespace,容器的启动进程就是该隔离环境中的1号进程,而临时容器不再创建新的namespace,而是将你新创建的容器加入到当前Pod的namespace中,以此来共享Pod的各种资源。也就实现了将新容器加入到当前Pod的目的,为使用者提供了一个方便的调试环境。
二、Kubernetes开启debug特性
1、开启debug特性
临时容器这一特性在Kubernetes v1.16版本提供支持,在v1.25版本稳定。在Kubernetes v1.23及以上版本中,该功能默认开启。针对v1.23以下的 K8S 版本,需要通过以下方式,手动开启,开启方法如下:(1)启用临时容器特性需要修改kube-apiserver、kube-contoller-manager、kube-scheduler以及kubelet的相关配置,在/etc/kubernetes/manifests路径下有这几个关键组件的静态Pod的yaml文件,在此修改即可。在kube-apiserver 、kube-controller-manager以及kube-scheduler的配置文件的command中添加以下配置:
- --feature-gates=EphemeralContainers=true
(2)进入/var/lib/kubelet目录下,修改kubelet的配置 kubeadm-flags.env,同样添加上述配置- --feature-gates=EphemeralContainers=true。
(3)静态Pod的配置文件被修改后,会自动重启相关Pod以加载最新配置,而kubelet需要使用 systemctl restart kubelet来手动重启。重启后,Kubernetes环境的相关配置就被加载,临时容器特性已被启用。
2、待调试Pod开启共享特性
在Kubernetes中,Pod或Deploy等工作负载创建的Pod中会有一个或多个容器,可以通过配置spec.shareProcessNamespace: true来配置Pod内的多个容器共享进程命名空间,该配置可在部署之时自行考虑是否开启。如果使用了某些sidecar机制或多个容器分离命名空间以保证安全等设计,需要考虑开启此特性是否会对服务造成影响。
三、kubectl debug使用
接下来用一个简单的例子,来介绍kubectl debug的使用。在例子中,目标Pod是一个简单的Ubuntu系统,启动命令为 sleep 3600。
1、kubectl debug调试当前容器
当容器崩溃或容器镜像不包含调试程序(例如无发行版镜像等)而导致kubectl exec无法运行时,临时容器对于交互式排除故障很有用。
使用busybox容器作为临时容器插入到当前Pod中,具体操作如下:
图1 添加debug容器
上图中可以看到,在kubectl debug命令中并没有像常规的Pod或docker容器启动时候附带启动命令,busybox插入到容器中后,1号进程仍然是sleep 3600,即目标容器的启动进程,当前容器只是加入到了目标Pod的进程命名空间中。查看Pod的状态:
图2 查看pod状态
查看pod的状态,其中容器数量仍然显示为1/1,因为临时容器只会在当前Pod运行,临时容器会随着Pod退出、重启而消失。在Pod的详细状态中可以看到刚刚创建的临时容器:
图3 查看pod详细信息
2、kubectl debug创建Pod副本
有些时候Pod的配置参数使得在某些情况下很难执行故障排查。例如,在容器镜像中不包含shell或者应用程序在启动时崩溃的情况下,就不能通过运行kubectl exec来排查容器故障。在这些情况下,可以使用kubectl debug 来创建Pod的副本,通过更改配置帮助调试。
kubectl debug 支持在添加临时容器时创建新的Pod副本,如下所示,在目标Pod中加入临时容器并创建为新的Pod副本。
图4 创建pod副本
与之前的操作不同的是,创建新的Pod副本后,原Pod中没有添加临时容器:
图5 查看原pod详细信息
而是将原Pod中的容器与临时容器生成为新的副本Pod,在这个新生成的Pod中,临时容器也不再被标识为临时容器。
图6 查看副本pod状态
3、kubectl debug在节点上调试
如果添加临时容器或者创建pod副本调试都不起作用,可以找到运行 Pod 的节点,然后创建一个 Pod 运行在该节点上。
kubectl debg支持在节点上创建一个交互式 Shell。
图7 worker-s001创建容器
在节点上创建调试会话,注意以下要点:
(1)kubectl debug 基于节点的名字自动生成新的 Pod 的名字。
如图3-4所示,创建了node-debugger-worker-s001-v2xg4的容器。
节点的根文件系统会被挂载在 /host目录。
图8 worker-s001文件系统挂载/host目录
(3)新的调试容器运行在主机IPC命名空间、主机网络命名空间以及主机 PID命名空间内,Pod没有特权,因此读取某些进程信息可能会失败,并且 chroot /host 也可能会失败。如果你需要一个特权 Pod,需要手动创建或使用 --profile=sysadmin 标志。
(4)完成节点调试时,使用kubectl delete清理调试 Pod。
图9 删除节点调试pod
文章作者 | 曹伍
原文始发于微信公众号(EBCloud):容器不停服的故障定位方法
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论