От переводчика: в апреле 2025 года вышел релиз Kubernetes 1.33, который принёс множество значимых нововведений — читайте наш подробный обзор новых возможностей. А в этом переводе мы рассказываем об одной из важных возможностей из этого релиза — поддержке мультиконтейнерных подов и связанных с ними паттернов, таких как сайдкар (sidecar).

По мере развития нативных облачных архитектур Kubernetes утвердился в качестве основной платформы для развёртывания сложных распределённых систем. Одним из наиболее мощных, но в то же время требующих тонкого подхода паттернов проектирования в этой экосистеме является сайдкар — методика, которая позволяет разработчикам расширять функциональность приложений без глубокого вмешательства в их исходный код.

Происхождение сайдкар-паттерна

Исторически в ИТ-инфраструктурах всегда использовались вспомогательные сервисы для выполнения критически важных задач. До появления контейнеров для управления логированием, мониторингом и сетью полагались на фоновые процессы и демоны-помощники. Микросервисы изменили этот подход, превратив сайдкары в структурированное и осознанное архитектурное решение. 

С ростом популярности микросервисов паттерн «сайдкар» оформился окончательно. Он позволяет разработчикам «выгрузить» часть задач из главного сервиса, не трогая его код. Сервис-меши (service mesh) типа Istio и Linkerd сделали прокси на базе сайдкаров очень популярными. Опыт их эксплуатации показывает, что такие контейнеры-напарники отлично решают вопросы наблюдаемости, безопасности и управления трафиком в распределённых системах.

Как это выглядит в Kubernetes

В Kubernetes сайдкары работают в том же поде, что и основное приложение. Это позволяет им обмениваться данными и совместно использовать ресурсы. Выглядит все так, словно в поде работает не один, а несколько обычных контейнеров… Собственно, так оно и было до версии Kubernetes 1.28 — в ней сайдкар-контейнеры наконец получили нативную поддержку. Теперь их можно прописать в манифесте пода в поле spec.initContainers. Сайдкаром такой контейнер делает политика перезапуска restartPolicy: Always. Посмотрите на пример ниже — это фрагмент манифеста Kubernetes:

initContainers:
  - name: logshipper
    image: alpine:latest
    restartPolicy: Always
  command: ['sh', '-c', 'tail -F /opt/logs.txt']
    volumeMounts:
    - name: data
        mountPath: /opt

Название поля spec.initContainers может вызывать недоумение. Почему сайдкар-контейнер описывается в разделе spec.initContainers? Ведь init-контейнеры (из spec.initContainers) отрабатывают всего один раз перед стартом основного приложения, в то время как сайдкары часто работают параллельно с главным контейнером приложения. Дело в том, что сочетание spec.initContainers и restartPolicy:Always отличает классические init-контейнеры от нативных сайдкаров Kubernetes и гарантирует, что последние работают постоянно.

Отличия от контейнеров приложений

Сайдкары работают вместе с контейнерами приложений в одном поде. Однако они никак не участвуют в базовой логике. Их задача — помогать основному приложению, предоставляя ему дополнительные возможности.

У сайдкар-контейнеров собственный, независимый жизненный цикл. Их можно запускать, останавливать и перезапускать независимо от контейнеров приложения. То есть сайдкары можно обновлять, масштабировать или обслуживать, не затрагивая основное приложение.

Сайдкар-контейнеры живут в тех же пространствах имён, что и основной контейнер. Такое близкое размещение позволяет им тесно взаимодействовать и использовать ресурсы (например, сети и хранилища) совместно.

Для Kubernetes корректное завершение работы сайдкар-контейнера не так важно. Если другие контейнеры исчерпают время, выделенное на корректное завершение работы (graceful shutdown), сайдкары получат сигнал SIGTERM, а затем SIGKILL — у них не будет времени завершиться корректно. Поэтому ненулевые коды выхода (0 означает успешный выход) для сайдкаров при завершении работы пода — это нормально, и внешним инструментам обычно следует их игнорировать.

Отличия от init-контейнеров

Сайдкар-контейнеры работают рядом с основным контейнером, расширяя его функциональность и предоставляя дополнительные сервисы.

Сайдкары работают одновременно с контейнером основного приложения. Они активны в течение всего жизненного цикла пода, и их можно запускать и останавливать независимо от основного контейнера. В отличие от init-контейнеров, сайдкары поддерживают пробы (probes), которые позволяют отследить их состояние, и обработчики жизненного цикла PostStart и PreStop.

Сайдкары могут напрямую взаимодействовать с контейнерами основного приложения, потому что, как и init-контейнеры, они находятся в одном пространстве имён.

Init-контейнеры останавливаются до того, как запускаются основные контейнеры, поэтому они не могут обмениваться сообщениями с контейнером приложения в поде. Передача данных возможна только в одну сторону (например, init-контейнер может записать информацию в том emptyDir).

Изменение образа сайдкар-контейнера не приведёт к перезапуску всего пода, однако инициирует перезапуск самого контейнера.

Когда следует и не следует использовать сайдкары

Сайдкар-паттерн бывает очень кстати, но обычно это не лучший выбор по умолчанию — его стоит применять, только если это действительно необходимо. Сайдкар — это всегда усложнение, повышенный расход ресурсов и потенциальное увеличение сетевых задержек. Поэтому сначала подумайте, нельзя ли обойтись без него (например, встроенными библиотеками или какой-то общей инфраструктурой).

Когда стоит использовать сайдкары:

  • При необходимости расширить возможности приложения, не трогая его основной код.

  • Для реализации общих (сквозных) задач, таких как сбор логов, мониторинг или безопасность.

  • При работе с legacy-приложениями, которым требуются современные сетевые возможности.

  • При разработке микросервисов, которые должны масштабироваться и обновляться независимо друг от друга.

Когда не стоит использовать сайдкары:

  • Если для вас главное — экономия ресурсов.

  • Если критически важна минимальная задержка в сети.

  • Если задачу можно решить более простыми способами.

  • Если нужно максимально упростить поиск и устранение проблем.

Четыре основных паттерна для подов с несколькими контейнерами

Паттерн Init

Init-контейнер выполняет важные подготовительные шаги перед запуском основного контейнера приложения. В отличие от обычных контейнеров, init-контейнеры запускаются, выполняют свою задачу и останавливаются.

Идеально подходят для:

  • подготовки конфигов;

  • загрузки секретов;

  • проверки, доступны ли нужные зависимости;

  • миграций баз данных.

Init-контейнер обеспечивает запуск приложения в предсказуемой, контролируемой среде, при этом не нужно вносить изменения в код этого приложения.

Паттерн Ambassador

Ambassador-контейнер предоставляет локальные вспомогательные сервисы для пода, которые обеспечивают простой доступ к сетевым сервисам. Обычно ambassador-контейнеры отправляют сетевые запросы от имени контейнера приложения и берут на себя решение таких задач, как обнаружение сервисов (service discovery), проверка подлинности узла (peer identity verification) или шифрование при передаче данных (encryption in transit).

Идеально подходят для:

  • разгрузки клиентского приложения от забот, связанных с сетевым подключением;

  • реализации сетевых фич, которые будут работать независимо от языка приложения;

  • добавления слоёв безопасности вроде TLS;

  • внедрения надёжных предохранителей (circuit breakers) и механизмов повторных запросов.

Паттерн Configurator

Сайдкар-помощник динамически обновляет настройки приложения. Так у приложения всегда будут свежие параметры, а его работа не прервётся. Зачастую такой помощник отвечает и за начальную настройку, без которой приложение не сможет запуститься.

Сценарии использования:

  • получение переменных окружения и секретов;

  • отслеживание изменений в конфигурации;

  • отделение управления конфигурацией от логики приложения.

Паттерн Adapter

Контейнер типа «Адаптер» (иногда называемый «Фасад») обеспечивает взаимодействие между основным контейнером приложения и внешними сервисами. Это достигается путём перевода форматов данных, протоколов или API из одного вида в другой.

Сильные стороны:

  • умеет преобразовывать старые форматы данных;

  • помогает наладить связь между разными протоколами;

  • упрощает интеграцию несовместимых сервисов.

Подведем итоги

Сайдкары обеспечивают огромную гибкость, но это не палочка-выручалочка на все случаи жизни. Каждый добавленный сайдкар — это усложнение, рост потребляемых ресурсов и, возможно, дополнительная головная боль при эксплуатации. Всегда сначала подумайте, нельзя ли обойтись решением попроще. Главное — использовать сайдкары стратегически: как точные инструменты для конкретных архитектурных проблем, а не как стандартный способ сделать всё. Если применять их правильно, они помогут повысить безопасность, облегчить работу с сетью и управление конфигами в мире контейнеров. Так что выбирайте с умом, внедряйте осторожно, и пусть ваши сайдкары сделают вашу контейнерную экосистему лучше.

P. S.

Читайте также в нашем блоге:

Комментарии (0)