← Kubernetes: конфигурация
6 мин · просто · Урок 6 из 8

Init-контейнеры

Контейнеры, которые отрабатывают до основных: порядок запуска, типичные сценарии и превращение init в native sidecar.

Что такое initContainer

initContainer это контейнер, который выполняется ДО основных и должен завершиться с exit 0. Только после этого kubelet поднимает обычные containers. Если init упал, main даже не стартует, Pod висит в Init:Error.

Зачем: подготовка окружения. Дождаться готовности БД, скачать ассеты в общий emptyDir, сгенерировать конфиг через envsubst, проверить права на смонтированный PVC, прогреть кэш. Всё это можно было бы сунуть в основной образ через bash-обёртку, но тогда main становится мусорным комбайном. Init вытаскивает подготовку в отдельный контейнер с отдельным образом.

initContainers крутятся строго последовательно, в порядке списка. Каждый должен выйти с exit 0, иначе Pod не перейдёт в Running. Между init и main можно шарить emptyDir: init скачал, main читает.

Минимальный YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  template:
    spec:
      initContainers:
        - name: wait-for-db
          image: busybox:1.36
          command:
            - sh
            - -c
            - 'until nc -z db 5432; do echo waiting; sleep 2; done'
      containers:
        - name: main
          image: busybox:1.36
          command: ["sh", "-c", "sleep 3600"]

nc -z host port пробует открыть TCP-соединение и сразу закрыть. Не открылось, exit non-zero, цикл until крутится дальше. Самый дешёвый «жди порт», работает в любом busybox.

Зависимость так и не появилась: init крутится бесконечно, Pod висит в Init и со стороны выглядит поломанным. Причину видно только в kubectl logs <pod> -c <init>.

Init не считается в READY

kubectl get pod для Pod с init покажет Init:0/1, потом Init:1/2, потом PodInitializing, и только потом Running 1/1. Обычный init-контейнер не поддерживает readinessProbe и не идёт в счётчик READY 1/1. Исключение это sidecar-форма (см. ниже): probes у неё работают, и её readiness влияет на готовность Pod.

Статус init смотрят отдельно:

kubectl get pod <name> -o jsonpath='{.status.initContainerStatuses[*].name}'
kubectl describe pod <name>

Что часто кладут в init

restartPolicy: Always превращает init в sidecar

У initContainer есть своё поле restartPolicy. Если поставить туда Always, контейнер перестанет быть одноразовым: он стартует до основных, продолжает работать всё время жизни Pod и гасится после них. Это и есть native sidecar, GA с 1.33.

initContainers:
  - name: log-shipper
    image: busybox:1.36
    restartPolicy: Always
    command: ["sh", "-c", "tail -F /var/log/app/app.log"]

Отличия от обычного init: Pod не ждёт его завершения (достаточно успешного старта), у него работают liveness/readiness/startup probes, и при падении kubelet перезапускает его на месте, а не пересоздаёт весь Pod.

время ------------------------------>

обычный init:
  init-1  [==]
  init-2      [==]
  main            [==============]

init с restartPolicy: Always:
  sidecar [============================]
  main            [==============]

Так описывают агентов логов, mesh-прокси, экспортеры метрик. Без restartPolicy init остаётся обычным: отработал, вышел, пропал.

Антипаттерн: миграция БД в init

Длинные миграции БД в init не кладут. Каждый рестарт Pod запускает их заново. Миграция может занять минуты, кластер думает что Pod застрял и начинает паниковать. Миграция должна быть отдельным Job, который катится один раз перед раскаткой Deployment.

Связанные команды

kubectl get pod -w                      # видно фазы Init:0/1, Init:1/1, Running
kubectl describe pod <name>             # секция Init Containers
kubectl logs <pod> -c wait-for-db       # лог init
kubectl explain pod.spec.initContainers

Что часто ломается

Домашка

Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-init-container     # развернуть стартовое состояние
./run.sh verify k8s-init-container    # проверить текущий шаг

Коротко

Прошли материал до конца? Отметьте урок пройденным.