kubectl debug с ephemeral containers
Современные production-images — distroless или scratch. Никакого shell, никакого tar, curl, ps. kubectl exec мгновенно становится бесполезен: exec: "sh": executable file not found. Раньше единственным выходом было — пересоздать Pod с debug-image, теряя state. С v1.25 GA в Kubernetes есть ephemeral containers и команда kubectl debug, которая инжектирует временный контейнер прямо в running Pod, не убивая его.
Сетевая диагностика: ping, dig, ss, nc, traceroute
Что такое ephemeral container
EphemeralContainer — это специальный тип container spec, который добавляется в running Pod после его создания. Список — в spec.ephemeralContainers. Управление — через subresource /ephemeralcontainers apiserver-а (не через обычный kubectl patch для всего Pod-а).
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: app
image: gcr.io/distroless/static
ephemeralContainers:
- name: debugger
image: busybox:1.36
targetContainerName: app # share PID namespace with app
stdin: true
tty: true
securityContext:
runAsUser: 0
Ограничения ephemeral container:
- Нет
restartPolicy— выполняется один раз. - Нет
livenessProbe,readinessProbe,startupProbe. - Нет
ports. - Нет
resources(нельзя задать requests/limits). - Не может быть удалён из Pod-а — после добавления остаётся в списке навсегда (можно
kubectl delete podцеликом). - Использует тот же Pod-level networking — видит те же поды через Service, имеет тот же Pod IP.
Ephemeral container ДОБАВЛЯЕТСЯ к существующему Pod, не пересоздаёт его. PV volumes, Pod IP, namespace — всё то же. Поэтому ты можешь debug-ить state, который мог бы быть потерян при recreation.
kubectl debug: три основных режима
Режим 1: подсадить ephemeral container в running Pod
# Базовое
kubectl debug -it my-pod --image=busybox:1.36
# С shared PID namespace для inspection main container
kubectl debug -it my-pod --image=busybox:1.36 --target=app
# Netshoot — всё для network debug
kubectl debug -it my-pod --image=nicolaka/netshoot --target=app
Флаг --target=<container> критически важен. Без него ephemeral container запускается в отдельном PID namespace (только свои процессы). С --target=app — shared PID namespace с целевым контейнером. Из ephemeral можно:
ps aux— увидеть процессы целевого контейнера.cat /proc/<pid>/environ— посмотреть env-переменные.cat /proc/<pid>/cwd— узнать current dir.gdb attach <pid>— debug live процесса (нуженCAP_SYS_PTRACE).ls /proc/<pid>/root— увидеть filesystem целевого контейнера.
Режим 2: copy-to — клон Pod с изменённым контейнером
Когда нужно заменить image на debug-вариант (например, добавить дополнительные printk):
# Клонировать Pod с заменой image на тот же but с shell
kubectl debug my-pod \
--copy-to=my-pod-debug \
--container=app \
--image=my-app:debug \
-- sh
Создаётся новый Pod my-pod-debug (оригинал не трогается), с тем же spec, но container app использует debug-image. PV / labels / annotations — копируются. Старый Pod продолжает обслуживать трафик, новый — для debug.
Альтернатива — --copy-to + --share-processes сохраняя оригинальный container:
kubectl debug my-pod \
--copy-to=my-pod-debug \
--share-processes \
--image=busybox:1.36 \
--container=debugger
# В копии: оригинальный app + новый debugger в shared PID
Режим 3: node debugging
Для отладки самой ноды (а не приложения):
kubectl debug node/node-1 -it --image=alpine
Под капотом kubectl создаёт обычный Pod (не ephemeral), который:
- Запускается на этой конкретной ноде (через
nodeName). - Имеет
hostNetwork: true,hostPID: true,hostIPC: true. - Монтирует rootfs ноды в
/host:volumeMounts.mountPath=/host. - Запускается как root.
Это даёт доступ ко всей ноде — можно chroot /host чтобы попасть в её реальный rootfs, читать /var/log ноды, делать journalctl -u kubelet, инспектировать iptables / nftables правила.
kubectl debug node/<name> — это де-факто root SSH на ноду через apiserver. Очень мощно и очень опасно. RBAC должен жёстко ограничивать verb=create на pods для не-админов. На большинстве managed K8s (EKS, GKE, AKS) этот доступ работает «из коробки» если у тебя cluster-admin.
Netshoot — стандарт для network debug
nicolaka/netshoot — это специальный image, набитый network tools:
kubectl debug -it my-pod --image=nicolaka/netshoot --target=app
Внутри есть:
curl,wget,httpie— HTTP запросы.dig,nslookup,host— DNS.tcpdump,tshark— packet capture.iperf3,mtr,traceroute— performance / route.nmap— port scan.nc(netcat),socat— TCP/UDP tools.iproute2,iptables,nftables— routing.ngrep,tcpflow— application-level inspection.
Это де-факто стандарт для network debug в Kubernetes. Если что-то не работает с network — kubectl debug --image=nicolaka/netshoot.
CKAD-задача: debug distroless app
Дано: Deployment запущен с distroless image, Pod показывает Running 1/1, но через Service не отвечает. Логи показывают connection refused.
# 1. exec не работает — нет shell
kubectl exec -it my-pod -- sh
# error: exec: "sh": executable file not found in $PATH
# 2. Подсаживаем netshoot
kubectl debug -it my-pod --image=nicolaka/netshoot --target=app
# Внутри ephemeral container:
# 3. Видим процессы app через shared PID
ps aux
# PID 1: /app/server
# 4. Проверяем, на каком порту слушает app
netstat -tlnp
# или ss -tlnp
# tcp 0.0.0.0:9090 LISTEN 1/server
# 5. Готово — app слушает на 9090, но Service targetPort=8080.
# Чинить — Service или containerPort.
# 6. Дополнительно: можем dig DNS, curl localhost, etc.
curl localhost:9090/health
dig kubernetes.default.svc.cluster.local
Killer-моменты
- Ephemeral containers GA с v1.25. Раньше — feature gate.
- Нельзя удалить ephemeral container — он остаётся в Pod spec навсегда. Можно
kubectl delete podцеликом. На production-Pod-ах это означает: после debug-сессии Pod «помечен» в спецификации. --target=<container>для shared PID — без него ephemeral в своём pid-ns, не видит процессы целевого.--copy-toне пересоздаёт оригинал — клон. Старый продолжает работать.kubectl debug node— это не ephemeral, а обычный privileged Pod с hostNetwork/hostPID/host-rootfs mount.- netshoot — must-know image для CKAD/CKA.
- subresource
/ephemeralcontainers— отдельный API endpoint, отдельные RBAC permissions: verb=patchилиupdate, resource=pods/ephemeralcontainers.