bigywater.tech
Kubernetes · 84

kubectl debug:临时容器与节点调试

线上容器没有 shell,怎么排查?kubectl debug 的临时容器和直接 exec 有什么不同?复制 Pod、调试节点各自做了什么?profile 又改变了什么?这篇一个个实际执行,把生成的 Pod spec 也读出来。

0 次重启
加临时容器后主容器 restartCount 仍为 0,Pod uid 不变
privileged
debug node 生成的 Pod:hostNetwork / hostPID / hostIPC + / 挂到 /host
5 种 profile
general / baseline / restricted / netadmin / sysadmin 对应的 securityContext 各不相同

临时容器

实测 · 本机执行输出
  kubectl debug app --image=busybox:1.36 --container=dbg1:退出码 0;[]
  dbg1 的输出(没有 --target,不共享进程命名空间):
    进程列表(没有 --target):
    PID USER TIME COMMAND
     1 root 0:00 sh -c echo "进程列表(没有 --target):"; ps; echo "我的 /etc/os-release 来自:"; head -1 /etc/os-release 2>/de
     11 root 0:00 ps
    我的 /etc/os-release 来自:
    busybox-image
  dbg2(--target=main,加入主容器的进程命名空间)的输出:
    PID USER TIME COMMAND
     1 root 0:00 nginx: master process nginx -g daemon off;
     25 101 0:00 nginx: worker process
     26 101 0:00 nginx: worker process
     27 101 0:00 nginx: worker process
     28 101 0:00 nginx: worker process
     29 101 0:00 nginx: worker process
     30 101 0:00 nginx: worker process
    conf.d
    fastcgi.conf
    fastcgi_params
  Pod 的 spec.ephemeralContainers:[('dbg1', 'busybox:1.36', None), ('dbg2', 'busybox:1.36', 'main')];status.ephemeralContainerStatuses:[('dbg1', 'terminated', 'Completed'), ('dbg2', 'terminated', 'Completed')]
  主容器 restartCount=0(加临时容器不会重启 Pod);Pod uid 不变
  想删除一个临时容器(patch remove):退出码 1;The Pod "app" is invalid: spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`,`spec.initContainers[*].image`,`spec.activeDeadlineSeconds`,`spec.tolerations` (only additions to existing tolerations),`spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)
  直接 patch 加一个带 resources 的临时容器:退出码 1;The Pod "app" is invalid: * spec.ephemeralContainers[0].resources: Forbidden: cannot be set for an Ephemeral Container * spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`,`spec.initContainers[*].image`,`spec.activeDeadlin

Pod app 的主容器是 nginx(只读根文件系统,没有调试工具)。kubectl debug app --image=busybox:1.36 --container=dbg1 往运行中的 Pod 加了一个临时容器,Pod 的 spec.ephemeralContainers 多了一项,主容器 restartCount 仍是 0、uid 不变。dbg1 没有 --target,ps 只看到自己;dbg2 加了 --target=main,加入主容器的进程命名空间,ps 看到 PID 1 是 nginx master 和 6 个 worker,还能通过 /proc/1/root 读主容器的 /etc/nginx。临时容器创建后删不掉(patch remove 被拒:pod updates may not change fields other than …),也不能设置 resources。

复制一份来调试

实测 · 本机执行输出
  kubectl debug app --copy-to=app-copy --image=busybox:1.36 -- sleep 3600:退出码 0;副本 app-copy 的 main 容器 image=busybox:1.36,command=['sleep', '3600'];原 Pod app 的 main image=nginx:1.27-alpine(原 Pod 没动)
  副本是一个独立的 Pod:ownerReferences=None;labels=None(原 Pod 也没有标签);nodeName=kx-main-worker2(原 Pod 在 kx-main-worker,副本由调度器重新选了节点)
  --share-processes 的副本 app-share:shareProcessNamespace=True;容器 ['main', 'dbg3']
  在 dbg3 里 ps:['PID USER TIME COMMAND', ' 1 65535 0:00 /pause', ' 7 root 0:00 nginx: master process nginx -g daemon off;', ' 31 101 0:00 nginx: worker process', ' 32 101 0:00 nginx: worker process'](能看到 main 的 nginx 进程)

kubectl debug app --copy-to=app-copy --image=busybox:1.36 -- sleep 3600 复制出一个独立的 Pod(没有 ownerReferences,调度器把它放在 worker2,原 Pod 在 worker),main 容器换成 busybox 并改了命令;原 Pod 的 main 仍是 nginx,没有被动过。加 --share-processes 复制出 app-share(shareProcessNamespace=true),在 dbg3 里 ps 能看到 /pause 和 nginx 进程。副本是个普通 Pod,调试完要自己删。

调试节点

实测 · 本机执行输出
  kubectl debug node/worker --image=busybox:1.36 -- chroot /host …:退出码 0;Creating debugging pod node-debugger-kx-main-worker-gzw7k with container debugger on node kx-main-worker.
  生成的 Pod node-debugger-kx-main-worker-gzw…(命名空间 default):nodeName=worker;hostNetwork=True;hostPID=True;hostIPC=True;volumes=[('host-root', '/')];容器 securityContext={'privileged': True}
  在节点根目录里 chroot 后执行的输出:
    kx-main-worker
    6
    PRETTY_NAME="Debian GNU/Linux 13 (trixie)"

kubectl debug node/kx-main-worker --image=busybox:1.36 -- chroot /host … 创建了一个叫 node-debugger-kx-main-worker-… 的 Pod(在 default 命名空间),nodeName 是 worker,hostNetwork、hostPID、hostIPC 都是 true,宿主机根目录挂在 /host,容器是 privileged: true(sysadmin 配置)。chroot /host 之后看到的主机名是 kx-main-worker,crictl ps 有 6 行,os-release 是 Debian GNU/Linux 13——已经是节点自己的系统。这个 Pod 的权限等同于 root 登录节点。

profile

实测 · 本机执行输出
  --profile=general:{'capabilities': {'add': ['SYS_PTRACE']}}
  --profile=baseline:None
  --profile=restricted:{'allowPrivilegeEscalation': False, 'capabilities': {'drop': ['ALL']}, 'runAsNonRoot': True, 'seccompProfile': {'type': 'RuntimeDefault'}}
  --profile=netadmin:{'capabilities': {'add': ['NET_ADMIN', 'NET_RAW']}}
  --profile=sysadmin:{'privileged': True}

--profile 决定调试容器的 securityContext:general 加 SYS_PTRACE;baseline 没有额外设置;restricted 要求 allowPrivilegeEscalation=false、drop ALL、runAsNonRoot、seccomp RuntimeDefault(能在 restricted 的命名空间里用);netadmin 加 NET_ADMIN 和 NET_RAW;sysadmin 是 privileged: true。

分步演示

kubectl debug
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0);目标 Pod 是只读根文件系统的 nginx:1.27-alpine,调试镜像 busybox:1.36;因为是脚本非交互执行,命令用 -- 带一次性命令,输出用 kubectl logs -c 取回;节点调试的 Pod 生成在 default 命名空间,实验后已删除;每种情形各一次
    • 没有验证:交互式 kubectl debug -it 的附着行为;--target 在不支持的运行时上的表现(会静默忽略);ephemeralContainers 对 Pod 状态与资源计量的影响;Windows 节点调试;kubectl debug 的 --custom 自定义;临时容器与 PodSecurity 准入;/proc/1/environ 读取其他容器环境变量需要的权限(实验中没有得到稳定结果)
    京ICP备2026067502号-1京公网安备11010502063487号