Learning Platform
Глоссарий Troubleshooting
Урок 16.04 · 25 мин
Продвинутый
kubectl debugephemeral containersdistrolessnetshootshared PIDnode debugging

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.
NOTE

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=appshared 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 целевого контейнера.
Shared PID namespace через --target
kubectl debug --target=appkubectl делает POST /pods/<name>/ephemeralcontainers с EphemeralContainer.targetContainerName=app. Apiserver валидирует и обновляет Pod spec.
kubelet получает updatekubelet watch Pod, видит новый ephemeral container в spec. Через CRI Create + Start запускает контейнер в SHARED PID namespace с targetContainer (как в обычном sidecar с shareProcessNamespace=true).
ephemeral: busyboxИмеет /bin/sh, ps, netstat, wget. Запускается в PID namespace целевого контейнера — ps aux показывает процессы app, можно убивать, attach gdb, читать /proc/<pid>/root.
target: app (distroless)Основной процесс приложения. Distroless image — никаких tools. Но через shared PID namespace его процессы видны из ephemeral container, можно читать /proc/<pid>/* (env, cwd, fd, root).
ОТДЕЛЬНЫЕ namespacesMOUNT и USER namespaces НЕ shared. Файловая система ephemeral container — busybox image. Чтобы попасть в FS app — через /proc/<pid>/root симлинк (отдельный mount-ns viewable от ptrace).

Режим 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 правила.

WARNING

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.

Проверка знанийKnowledge check
Зачем нужен флаг --target в kubectl debug и что произойдёт без него?
ОтветAnswer
--target=<container> подсаживает ephemeral container в SHARED PID namespace с целевым контейнером. Это позволяет: ps aux показывает процессы targetContainer, gdb attach к PID-ам, чтение /proc/<pid>/environ /cwd /root для inspection. Без --target ephemeral в СВОЁМ pid-ns — видит только свои процессы, ему недоступны процессы основного контейнера. Для network debug network namespace всегда shared (это уровень Pod), поэтому без --target всё ещё можно curl/dig на endpoint-ы Pod-а — но не видеть, что делает основной процесс.
Проверка знанийKnowledge check
Можно ли удалить добавленный ephemeral container, если debug завершён?
ОтветAnswer
Нет. Ephemeral container добавляется в spec.ephemeralContainers через subresource /ephemeralcontainers, но не имеет операции delete. Запись остаётся в Pod spec навсегда — даже после того, как процесс ephemeral завершился. Сам контейнер останавливается, но запись висит. Единственный способ убрать — kubectl delete pod (если pod managed Deployment-ом, replica будет пересоздана без ephemeral). Это design decision: ephemeral — это аудит-trail, нельзя 'замести следы' после debug.
Проверка знанийKnowledge check
В чём разница между kubectl debug --copy-to и просто kubectl run debug-pod с тем же image?
ОтветAnswer
--copy-to наследует ВЕСЬ spec оригинального Pod: containers, volumes, volumeMounts, env, configmaps, serviceAccount, securityContext, networking. Можно тестировать копию в идентичной среде, при этом оригинал продолжает обслуживать трафик (он сохранён). kubectl run создаёт минимальный Pod из шаблона — много полей не настроится автоматически. Use case --copy-to: 'у меня production-Pod, хочу его клонировать с debug-image и потестить, не трогая оригинал'.
Проверка знанийKnowledge check
kubectl debug node/worker-1 — что именно создаётся и какие host resources становятся доступны?
ОтветAnswer
Создаётся ОБЫЧНЫЙ Pod (не ephemeral!) на node worker-1: hostNetwork=true (тот же сетевой stack ноды, можно делать tcpdump на eth0 ноды), hostPID=true (видны процессы ноды — kubelet, containerd, system services), hostIPC=true, volumeMount /host -> хост / (root filesystem ноды). securityContext: privileged + runAsUser=0. После chroot /host получается полный root shell на ноде. Это де-факто SSH через apiserver, очень мощно — и опасно. RBAC verb=create на pods даёт это.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. kubectl debug -it my-pod --image=busybox --target=app — что именно делает флаг --target=app?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5