Запустіть Sidecar: Готуємось до основного запуску додатку

Мультиконтейнерні Pods та бокові контейнери стали невід’ємними елементами сучасних DevOps та хмарних обчислень. Хоча рідна підтримка бокових контейнерів у Kubernetes, введена в версії v1.29, гарантує, що вони запускаються перед основним додатком, багато команд виявляють, що “запущено” не завжди означає “готово до роботи”. У цій статті ми розглянемо розширені стратегії, які допоможуть забезпечити повну готовність ваших бокових контейнерів перед запуском контейнера додатка.
Невеликий огляд
З версією Kubernetes v1.29 бокові контейнери можуть бути визначені в .spec.initContainers
з параметром restartPolicy: Always
. Це надає їм семантику життєвого циклу Pod, подібну до ініціалізаційних контейнерів, але без блокування завершення Pod:
spec:
initContainers:
- name: logshipper
image: alpine:latest
restartPolicy: Always # семантика бокового контейнера
command: ['sh','-c','tail -F /opt/logs.txt']
volumeMounts:
- name: data
mountPath: /opt
Ключові відмінності від традиційних мультиконтейнерних Pods:
- Послідовність: Рідні бокові контейнери (initContainers з параметром restartPolicy) завжди запускаються перед
.spec.containers
. - Завершення: Бокові контейнери завершуються після основного додатка під час м’якого завершення.
- Завдання: Бокові контейнери в Job Pods не блокують завершення і можуть існувати довше, ніж контролер Job.
Проблема
Незважаючи на гарантований порядок запуску, kubelet запускає ініціалізаційні контейнери асинхронно – часто паралельно, як видно в джерелі kubelet. Якщо ваш додаток залежить від того, щоб боковий контейнер був повністю готовий (наприклад, для агрегації логів або безпекового проксі), вам потрібен надійний сигнал “готовності” від бокового контейнера перед продовженням.
“У продакшені ми спостерігали, як наш додаток зазнавав невдачі протягом кількох секунд, якщо боковий контейнер для логування не відкрив свій сокет. Нам була потрібна детермінована послідовність запуску без зміни коду додатка.” — Учасник Kubernetes, SIG Node
Проба готовності
Проба готовності позначає контейнер як Готовий для маршрутизації сервісу, але вона не контролює запуск сусідніх контейнерів. Розглянемо боковий контейнер NGINX з пробою, яка ніколи не проходить:
readinessProbe:
exec:
command: ["/bin/sh","-c","exit 1"] # завжди невдала
periodSeconds: 5
Результат: Pod показує 1/2 Running (основний додаток вже запущений, хоча боковий контейнер ніколи не готовий). Проби готовності контролюють лише трафік сервісу, а не порядок запуску.
Проба запуску
startupProbe
блокує запуск контейнера (тобто виконання основного процесу) до моменту успішного проходження проби. Розмістивши пробу запуску на вашому ініціалізаційному контейнері бокового контейнера, ви можете затримати запуск основного додатка, поки боковий контейнер не буде повністю функціональним.
initContainers:
- name: nginx-sidecar
image: nginx:latest
restartPolicy: Always
ports:
- containerPort: 80
startupProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 3
failureThreshold: 10
Оскільки ініціалізаційні контейнери запускаються перед .spec.containers
, ваш основний додаток не стартує, поки HTTP-проба не поверне 200. Цей підхід є простим та ефективним, але збільшує затримку запуску Pod.
Хук життєвого циклу PostStart
Ви також можете реалізувати postStart
хук на боковому контейнері, який активно перевіряє свою готовність перед завершенням. Приклад:
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- |
until curl -sf http://localhost:80; do
echo "Очікування NGINX..."
sleep 5
done
echo "NGINX готовий"
Хоча це забезпечує готовність, це додає навантаження на скрипти та пов’язує специфікацію Pod з кастомною логікою оболонки.
Проба живучості
Проба живучості перезапустить невдалий боковий контейнер, але не затримає запуск інших контейнерів. Вона корисна для перевірок здоров’я під час виконання, але не для послідовності запуску:
livenessProbe:
exec:
command: ["/bin/sh","-c","exit 1"]
periodSeconds: 10
Невдачі призведуть лише до перезапуску бокового контейнера, залишаючи основний додаток без змін.
Безпекові наслідки
Багато бокових контейнерів виконують функції проксі, WAF або елементів сервісної сітки. Невміння забезпечити їх готовність може залишити вашу програму вразливою:
- Бокові контейнери для аутентифікації: Видавці токенів повинні бути активні перед запитами клієнтів.
- Проксі для шифрування: Може не бути ініційовано завершення TLS, що призводить до трафіку в відкритому вигляді.
- Двигуни політики: Бокові контейнери на основі OPA можуть неправильно блокувати або дозволяти запити, якщо не готові.
Впровадження startupProbe
або postStart
хуків зменшує площу атаки під час ініціалізації Pod.
Складність проти підтримуваності
Хоча розширені проби гарантують порядок, вони вводять додаткову конфігурацію та затримки. Розгляньте:
- Операційні витрати: Більше YAML – більше підтримки.
- Час запуску: Затримка пропорційна інтервалам проб і порогам.
- Спостережуваність: Події між контейнерами потребують покращеного логування та метрик.
Як альтернативу, рефакторинг основного додатка для повторних спроб підключень або затримки критичних операцій може спростити специфікацію Pod, але вимагатиме змін у додатку.
Майбутні функції та напрямок розвитку
KEP щодо пріоритету бокових контейнерів (заплановано на v1.30) пропонує рідну підтримку пріоритетів запуску бокових контейнерів та воріт готовності, що охоплюють кілька контейнерів. Після реалізації ви зможете оголосити явні залежності без кастомних проб.
Тим часом деякі інструменти, підтримувані CNCF, такі як Argo Rollouts, вже підтримують просунуті канаркові стратегії з обізнаними про бокові контейнери readinessGates
та фазами хуків, що ще більше спрощує безпечні розгортання.
Підсумок висновків
Поведение запуску на перший погляд:
Проба/Хук | Боковий контейнер перед додатком? | Додаток чекає? | У разі невдачі |
---|---|---|---|
readinessProbe | Так, але паралельно | Ні | Додаток продовжує |
livenessProbe | Так, але паралельно | Ні | Боковий контейнер перезапускається |
startupProbe | Так | Так | Додаток затримується |
postStart hook | Так | Так (кастомний) | Додаток затримується |
Рекомендація: Використовуйте startupProbe
на ініціалізаційних контейнерах бокового контейнера для детермінованої послідовності запуску. Моніторте критичні шляхи за допомогою метрик Prometheus та логів, а також стежте за KEP Kubernetes для рідної підтримки у v1.30.
Успішних розгортань!