linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • Симулятор
  • База знаний
  • Собеседование
Index
Categories
All entries
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
home/linux/kb/Контейнеры (бонус)/kubernetes-pod-lifecycle

kb/containers ── Контейнеры (бонус) ── intermediate

Kubernetes pod lifecycle - от Pending до Terminated

Pod проходит фазы Pending → Running → Succeeded/Failed/Unknown. Init-containers выполняются последовательно до основных. Probes: startup → readiness/liveness. SIGTERM + grace period при удалении.

view as markdownaka: pod-lifecycle, k8s-pod, init-container, readiness-probe, liveness-probe, pod-phases

Зачем понимать lifecycle

В k8s pod, атом deployment'а: 1+ контейнеров с общим network/IPC namespace и томами. Между моментом kubectl apply и окончательным Running pod проходит цепь состояний, в каждом могут быть проблемы. Если знаешь lifecycle, диагностируешь "почему не стартует" / "почему перезагружается" / "почему не может graceful-shutdown" за минуту.

Phases, поле .status.phase

Pod имеет ровно одну фазу:

PhaseЧто значит
Pendingпринят API, ещё не Running. Может быть scheduling, image-pull, init-container'ы.
Runningscheduled на ноду, минимум один контейнер запущен. Не означает что все проходят readiness!
Succeededвсе контейнеры завершились с exit 0 (для Job/CronJob)
Failedминимум один контейнер завершился с non-zero и не будет рестартован
Unknownkubelet не смог сообщить статус (нода обвалилась, network split)

Phase, слишком грубый. Реальное состояние, в .status.conditions.

Conditions, детальная картина

yaml
status:
  phase: Running
  conditions:
  - type: PodScheduled
    status: "True"
    lastTransitionTime: "..."
  - type: Initialized
    status: "True"           # все init-containers OK
  - type: ContainersReady
    status: "True"           # все основные containers ready
  - type: Ready
    status: "True"           # = ContainersReady && readiness-probe pass
  • PodScheduled, scheduler нашёл ноду
  • Initialized, init-containers завершились с exit 0
  • ContainersReady, все основные контейнеры прошли readiness-probe
  • Ready, pod готов получать трафик (включается в Service endpoints)

Pod может быть Running но не Ready, это нормальная ситуация при старте или после liveness-probe сбоя.

Init containers

Контейнеры в spec.initContainers запускаются последовательно ДО основных, каждый должен exit 0:

yaml
apiVersion: v1
kind: Pod
spec:
  initContainers:
  - name: wait-for-db
    image: busybox
    command: ['sh', '-c', 'until nc -z db 5432; do sleep 1; done']
  - name: migrate
    image: myapp:v1
    command: ['./migrate']
  containers:
  - name: app
    image: myapp:v1

Семантика:

  • Если init-container падает, pod рестартует с первого init-контейнера
  • restartPolicy: Always для pod не применяется к init (init всегда рестартует на failure)
  • Init-containers могут иметь свои resources, securityContext

Use cases:

  • Wait for dependencies (DB, configmap)
  • DB migrations
  • Permissions fix на mount'е (chown /data перед основным процессом)
  • Generate config из templates с envsubst

Probes, startup, readiness, liveness

Три типа health-check, выполняемых kubelet'ом на ноде:

startup-probe

yaml
startupProbe:
  httpGet: { path: /healthz, port: 8080 }
  failureThreshold: 30
  periodSeconds: 10
  • Проверяется первой, отключает остальные probes пока работает.
  • Защищает медленно стартующие приложения от ложного liveness-fail.
  • При success, больше не запускается, начинают работать readiness/liveness.
  • При failure threshold, kubelet убивает контейнер.

Без startup-probe медленный стартап → liveness-probe убивает, бесконечный restart-loop.

readiness-probe

yaml
readinessProbe:
  httpGet: { path: /ready, port: 8080 }
  initialDelaySeconds: 5
  periodSeconds: 10
  failureThreshold: 3
  • Не убивает pod, просто снимает endpoint из Service при failure.
  • Возвращается в Service когда снова passes.
  • Идеально для warmup (cache не прогрет, БД-конект ещё не установлен).

liveness-probe

yaml
livenessProbe:
  httpGet: { path: /healthz, port: 8080 }
  periodSeconds: 10
  failureThreshold: 3
  • Убивает контейнер при failure (рестартует через restartPolicy).
  • Используй ТОЛЬКО для самовосстановления "deadlock'нувшего" приложения. Не для проверки upstream-зависимостей.
  • Анти-паттерн: проверять БД в liveness, если БД лагает, k8s убьёт все pod'ы → каскадный сбой.

Probe types

TypeЧто
httpGetHTTP 200-399 = OK; на любом path/port
tcpSocketTCP connect возможен = OK
execcommand exit 0 = OK
grpc (1.27+)gRPC health-check stream

Restart Policy

  • Always (default для Deployment/ReplicaSet/StatefulSet), рестартует при любом exit
  • OnFailure (Job/CronJob default), рестартует только при non-zero
  • Never, не рестартует вообще

Только для Pod-level. На уровне controller'ов (Deployment), другая логика (replicas).

Termination, graceful shutdown

Когда kubectl delete pod или scale-down:

1. API: pod.metadata.deletionTimestamp = now
2. Pod удаляется из Service-endpoints (Ready=False)
3. preStop hook (если есть)              ← синхронно
4. SIGTERM в pid 1 контейнера            ← начинается grace period
5. ... ждём terminationGracePeriodSeconds (default 30s)
6. SIGKILL если не завершился
7. Pod удалён из API
yaml
spec:
  terminationGracePeriodSeconds: 60
  containers:
  - name: app
    lifecycle:
      preStop:
        exec:
          command: ['sh', '-c', 'sleep 5 && kill -TERM 1']

preStop:

  • Выполняется до SIGTERM
  • Полезен для drain-режима (сообщить LB "не шли мне больше")
  • sleep 5, типичная пауза для distribution-of-removal в Service

Главные ошибки:

  • PID 1 не обрабатывает SIGTERM, некоторые языки/shell-script не пробрасывают сигнал. Используй tini или dumb-init как PID 1.
  • Долгая graceful-операция > terminationGracePeriodSeconds, k8s SIGKILL'ит. Увеличь grace, или сделай работу неблокирующей.

OOM в pod'е

k8s ставит cgroup-limit на memory. При превышении:

  • Контейнер OOMKilled, kernel OOM-killer убивает процесс контейнера
  • В status: lastState.terminated.reason: OOMKilled
  • Pod рестартует если restartPolicy=Always

Проверка:

bash
kubectl describe pod mypod | grep -A2 'Last State'
# Last State:     Terminated
# Reason:        OOMKilled
# Exit Code:     137                    ← 128 + 9 (SIGKILL)

Лечение: увеличить resources.limits.memory или fix-leak в приложении.

ImagePullBackOff и CrashLoopBackOff

  • ImagePullBackOff, registry недоступен / image-tag неверный / нет imagePullSecret. kubectl describe pod → events.
  • CrashLoopBackOff, контейнер падает быстро после старта, kubelet экспоненциально увеличивает delay между рестартами (10s → 20s → 40s ... до 5 min).

Дебаг:

bash
kubectl logs mypod -c container1                # текущий
kubectl logs mypod -c container1 --previous     # предыдущий instance
kubectl describe pod mypod                      # events внизу
kubectl get events --sort-by='.lastTimestamp'   # глобальные events

Когда что-то пошло не так

  • Pod stuck в Pending, нет ноды с нужными resources/labels. kubectl describe pod → events: FailedScheduling. Проверь kubectl describe node (Allocatable, taints).
  • Pod stuck в ContainerCreating, image pulls слишком долго или volume не маунтится. kubectl describe pod events.
  • OOMKilled без явных причин, limits слишком низкие, или JVM не знает про cgroup-limit (надо -XX:+UseContainerSupport для Java 8u131+, на Java 11+ default).
  • Liveness-probe убивает pod после deploy'а, initialDelaySeconds мал, приложение ещё стартует. Используй startup-probe.
  • kubectl delete pod висит, finalizer'ы или terminationGracePeriodSeconds очень большой. kubectl delete pod --grace-period=0 --force.
  • Контейнер живой, но не получает трафик, readiness-probe failed. kubectl describe pod → conditions: ContainersReady=False.
  • Init-container завершается, но pod не движется, exit non-zero. kubectl logs mypod -c <init-name>.

Полезные kubectl-команды

bash
kubectl get pod -o wide                       # узнать ноду + IP
kubectl get pod -o jsonpath='{.status.containerStatuses[*].state}'
kubectl exec -it mypod -- sh
kubectl debug -it mypod --image=busybox       # ephemeral container 1.25+
kubectl port-forward pod/mypod 8080:8080      # local-test без Service
kubectl rollout status deployment/myapp
kubectl rollout restart deployment/myapp      # rolling-rollout без правки spec

§ команды

bash
kubectl get pod mypod -o jsonpath='{.status.phase}'

Текущая phase pod'а - первая checkbox при дебаге

bash
kubectl describe pod mypod | grep -A3 'Last State'

Причина рестарта (OOMKilled, Error, Completed) с exit-code

bash
kubectl logs mypod --previous -c container1

Логи прошлого instance контейнера - что было перед рестартом

bash
kubectl get events --sort-by='.lastTimestamp' -A | tail -30

Последние events кластера - источник 'почему pod не стартует'

bash
kubectl exec -it mypod -- sh

Зайти в контейнер - debug изнутри (если sh есть)

bash
kubectl debug -it mypod --image=busybox --target=container1

Ephemeral debug-container в pod'е - не нужен sh в исходном image

bash
kubectl delete pod mypod --grace-period=0 --force

Принудительное удаление - используй когда terminating висит

§ см. также

  • namespacesLinux namespacesNamespaces - механизм ядра, который даёт процессу собственный изолированный view на ресурс (сеть, mount-points, PID, UID, IPC, hostname, time). На них построены все контейнеры.
  • cgroupscgroups (v2)cgroups v2 - иерархическая виртуальная FS под `/sys/fs/cgroup` через которую ядро лимитирует CPU/память/I/O процессов. Docker/k8s/systemd пишут сюда.
  • signalsСигналы (SIGTERM, SIGKILL, SIGHUP)Сигнал - асинхронное уведомление процессу от ядра или другого процесса. TERM - попроси завершиться, KILL - убей сразу, HUP - перечитай конфиг.
  • runc-and-runscrunc, runsc, kata - container runtimesrunc - стандартный OCI-runtime, namespaces+cgroups+seccomp. runsc/gVisor - userspace-ядро для дополнительной изоляции. kata - облегчённая VM на контейнер. Performance ↔ isolation trade-off.
  • oci-specOCI spec - стандарт контейнеровOCI - три спеки: Image (слои + manifest), Runtime (config.json + rootfs для runc), Distribution (registry API). Стандарт после Docker'а; runc, podman, containerd, CRI-O - всё OCI-compatible.
  • kubelet-internalskubelet - архитектура агента ноды Kuberneteskubelet - демон на каждой ноде. Получает PodSpec через API, запускает контейнеры через CRI, монтирует volumes через CSI, следит за health. При pressure делает eviction. Image GC и cgroup-tree - тоже его.
  • kubernetes-services-and-ingressKubernetes Service и Ingress - сетевая публикация подовService - стабильный VIP перед группой подов (label selector). Типы: ClusterIP (внутри), NodePort (порт на каждой ноде), LoadBalancer (внешний LB облака), ExternalName (CNAME). Ingress - L7 reverse-proxy (nginx/traefik) для HTTP-роутинга.
  • kubernetes-storageKubernetes storage - PV, PVC, StorageClass, CSIPV - физический volume. PVC - запрос pod'а. StorageClass + CSI - шаблон для dynamic provisioning. ReadWriteOnce типичный (block), ReadWriteMany нужен NFS/CephFS. Эфемерные (emptyDir, configMap) живут пока жив pod.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки