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
- Ожидание сервиса (как в примере выше, через
nc). - Скачивание статичных ассетов в emptyDir, потом main их раздаёт.
- Генерация конфига: init берёт template плюс env, envsubst, кладёт в emptyDir, main читает.
- Проверка прав на PVC: монтируется общий volume, init выставляет права, main стартует уже на готовом.
- Импорт сертификатов из vault или Secret в правильное место.
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
Что часто ломается
restartPolicy: Alwaysу init поставили не подумав. Такой контейнер превращается в sidecar и никогда не завершится, а Pod будет ждать от него только успешного старта. Для подготовки окружения поле не ставят: обычный init отрабатывает и выходит.- Init нужно много ресурсов, но
requestsстоят на main. Шедулер считает максимум из init и main, не сумму. Это вычеркивает класс ошибок «init не влез», но в редких кейсах удивляет. - nc отсутствует в образе. Нужен busybox, не distroless.
Домашка
Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.
./run.sh start k8s-init-container # развернуть стартовое состояние
./run.sh verify k8s-init-container # проверить текущий шаг
Коротко
- initContainer отрабатывает до основных контейнеров и должен выйти с кодом 0.
- Init-контейнеры запускаются последовательно, в порядке списка.
- Типичные задачи: ожидание зависимости, генерация конфига, подготовка volume.
- Обычный init не идёт в счётчик READY и не поддерживает probes.
restartPolicy: Alwaysу init делает из него native sidecar с probes и рестартом на месте.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс