Kubernetes Ephemeral Containers:线上调试入口和权限边界
在不把 curl/dig/tcpdump 打进生产镜像的前提下,安全地进入 Pod 排查 DNS/网络/依赖问题。
Ephemeral Container(临时调试容器)允许你在 不修改 Deployment 镜像 的情况下,把一个调试容器“挂”到现有 Pod 上,用来排查线上问题。
它特别适合:
- 生产镜像极简(distroless/scratch),没有
curl/dig/tcpdump - 你需要在 Pod 内部 复现网络/DNS/依赖问题
- 你希望生产镜像保持干净、安全、可审计
前置条件
- Ephemeral Containers 从 Kubernetes 1.25 起进入 Stable;更早版本不要照抄本文命令
- 需要 RBAC 权限:
pods/ephemeralcontainers(注意是子资源)
最常用的一条命令
给指定 Pod 加一个临时调试容器:
kubectl debug -n <ns> -it pod/<pod> --image=busybox:1.36 --target=<container-name>
说明:
--image选一个你信任的调试镜像--target请求加入目标容器的进程命名空间,方便查看进程;容器运行时必须支持该能力,否则可能仍看不到目标进程- 如果你只是想做网络/DNS 检查,不一定需要
--target
你能用它做什么(实战场景)
1)DNS 与服务解析
nslookup kubernetes.default.svc.cluster.local
nslookup <svc>.<ns>.svc.cluster.local
cat /etc/resolv.conf
很多“服务突然不可用”的根因其实是:
- DNS 被 NetworkPolicy egress 拦了
- CoreDNS 异常
- 节点网络/CNI 问题导致间歇性解析失败
2)验证 Service 连通性(从 Pod 内)
wget -S -O- http://<service>.<ns>.svc.cluster.local:8080/readyz
nc -vz <service>.<ns>.svc.cluster.local 8080
你想验证的是:在同一 Pod 网络命名空间里,请求到底能不能走通。
3)readiness 失败但 distroless 里没有 curl
临时容器仍受 Pod NetworkPolicy 约束,所以它看到的是应用真实网络边界:
kubectl debug -n <ns> -it pod/<pod> --image=curlimages/curl:8.5.0
curl -sS -i http://127.0.0.1:8080/readyz
如果外部探活失败而 Pod 内部成功,优先看 Service selector、endpoints 和节点网络,而不是先改应用。
4)怀疑 NetworkPolicy 拦住 egress
在 Pod 网络命名空间里验证 DNS 和目标端口:
nslookup <dependency>.<ns>.svc.cluster.local
nc -vz <dependency>.<ns>.svc.cluster.local 5432
同时对比不同 namespace 的结果。如果只有某些 namespace 不通,通常是 label 或 policy 选择器问题。
5)检查环境变量与挂载(尽量只读)
排障时常见的“配置错了”:
- env 变量缺失/写错
- ConfigMap/Secret 没挂载成功
- 文件路径不一致
建议排障动作尽量只读:
envls -la /pathcat /etc/hosts
选什么调试镜像更合理
不同任务需要不同工具:
- BusyBox:够小,适合基础网络与文件检查
- Alpine:可拓展,但临时安装包可能需要外网访问(不一定允许)
- 工具箱镜像:带
curl/dig/tcpdump/mtr等,效率高但体积大、风险也更大
生产建议维护一个“认证过的调试镜像”:
- 固定 digest(可复现)
- 定期安全扫描
- 只包含必要工具
这样排障不会临时“随便拉一个镜像”,降低供应链风险。
理解 --target:什么时候必须用
同一个 Pod 内的容器本来就共享网络命名空间,因此多数 DNS、Service 和回环地址排障不需要 --target。
你更可能需要 --target 的情况:
- 想看目标容器进程(或在允许情况下
strace) - 想对“卡死”的进程做诊断
如果容器运行时不支持 target process namespace,或平台策略不允许相应权限,调试容器可能启动但看不到目标进程;网络与 DNS 检查仍可继续。
重要限制(别把它当成长期方案)
Ephemeral containers 的定位就是“临时排障”,因此:
- 不是 Pod spec 的一部分,不应该成为“长期修复”
- 不会被重启(退出就退出了)
- 不应该对外提供服务端口
正确修复应该回到:
- 配置/镜像/代码/部署清单
- GitOps/CI 的流程
安全与流程(最容易被忽视,但最重要)
临时调试容器本质上是“把人带进生产 Pod”:
- 需要更严格的 RBAC(限制谁能用)
- 需要审计(谁、什么时候、为什么)
- 需要流程(事故单/工单编号,排查结论落档)
一个最小 RBAC 思路是把“看 Pod”和“改 ephemeralcontainers 子资源”分开:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ephemeral-debug
namespace: app
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/ephemeralcontainers"]
verbs: ["get", "update"]
如果排障动作可能读取 Secret 环境变量、挂载内容或业务数据,就先和安全团队对齐三件事:
- 哪些 namespace 允许临时调试;
- 允许使用哪些认证过的调试镜像;
- 是否允许节点级调试,以及需要什么审批。
推荐做法:
- RBAC 最小化:只给少数 SRE/值班组
- 统一调试镜像:防止供应链风险
- 只读排障优先:尽量不改线上文件与状态
高风险场景:先复制 Pod,再调试
有时你不想直接触碰生产 Pod,比如需要安装包、重启应用进程、注入更重的诊断工具。如果当前 kubectl 版本和集群策略支持,可以复制一个隔离副本再排查。
kubectl debug -n <ns> -it pod/<pod> \
--image=ubuntu:24.04 \
--share-processes \
--copy-to=<pod>-debug
kubectl delete pod -n <ns> <pod>-debug
复制出的 Pod 可能仍连接真实依赖。先确认 Service selector 不会选中它,并避免执行有副作用的消费者或定时任务。
这类场景的原则很简单:风险越高,越先“复制后调试”,而不是在线上 Pod 里试错。
Bonus:当问题在“节点层”而非 Pod 层
有时候根因在节点或平台:
- CNI 路由/iptables/eBPF 问题
- 磁盘压力导致驱逐
- kubelet/containerd 异常
kubectl debug node/<node> 创建的调试 Pod 默认不一定具备执行 chroot /host 所需的权限。确实需要主机级权限时,显式使用 sysadmin profile,并把它视为特权操作:
kubectl debug node/<node> -it \
--image=ubuntu:24.04 \
--profile=sysadmin \
-- chroot /host
进入后再检查 ip a、ip r、ss -lntp、节点 /etc/resolv.conf 和 CNI 配置。不要为了方便把节点调试权限下放给普通应用账号。
排查结束也要收尾
临时容器可能会保留在 Pod status 里,直到 Pod 被删除。退出终端只是最低要求:
- 记录执行过的命令、关键输出和结论。
- 关联工单或事故单,方便复盘。
- 真正修复走配置、镜像和发布流程,不要把“临时手改”当成方案。
上线前自检
- 生产镜像保持极简,不打包调试工具
- 用 ephemeral containers 快速复现 Pod 内真实网络/DNS
- RBAC 控制
pods/ephemeralcontainers,并审计使用记录 - 排障只读优先,修复走发布流程而不是“线上手改”
临时容器的三个使用边界
Q: 生产环境能用吗? A: 可以用于排障,但不会自动重启。建议用 RBAC 限制谁可以注入临时容器。
Q: 为什么不能挂载新卷或暴露端口? A: 临时容器设计用于调试,限制变更以避免影响业务。
Q: 怎么查看临时容器日志?
A: 用 kubectl logs <pod> -c <ephemeral-container-name>,必要时 kubectl describe pod 查看状态。