Ко всем новостям

Дополнительные контейнеры в Kubernetes и где они обитают: от паттернов к автоматизации управления

Публикации в СМИ
Технологии
19.09.2023

Источник: Хабр ""

Всем известно, что pod в Kubernetes может включать в себя несколько контейнеров: для Service Mesh, работы с внешним хранилищем секретов, журналирования и т. д. В итоге это множество вызывает вопросы. Правильно ли использовать столько контейнеров? Как их изолировать от пользовательских приложений? Можно ли вообще исключить дополнительные контейнеры из пользовательских релизов?

Я Максим Чудновский, занимаюсь Synapse Service Mesh в СберТехе. Расскажу, какие есть паттерны применения дополнительных контейнеров в Kubernetes, как они могут помочь в платформенной инженерии, и, самое главное, как полностью автоматизировать процесс управления жизненным циклом таких контейнеров.

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

b0d4582f955d2fd655efe17622dc777d.png

Можно ли использовать много контейнеров в одном поде

Для ответа на этот вопрос обратимся к замечательной книге «Kubernetes Patterns» от O'Reilly.

afe9fea8ae5305eee689857c848ecd89.png

В части, посвящённой структурным паттернам, описано, как организовать своё приложение в Kubernetes с точки зрения структуры пода в Kubernetes: что там должно быть, а от чего лучше отказаться.

В общем виде можно выделить 4 вида дополнительных «полезных» контейнеров:

  1. Init;
  2. Sidecar;
  3. Adapter;
  4. Ambassador.

Давайте рассмотрим их подробнее.

Init Containers

Как видно из названия, init-контейнеры нужны для того, чтобы инициализировать приложение. В отличие от обычных, они имеют собственный жизненный цикл: всегда выполняются первыми, а основные контейнеры стартуют только по их завершению. Это удобно, когда необходимо что-то подготовить, например, можно получить доступ к каким-то секретам или сделать редирект сетевого трафика через модификацию iptables. А после этого запустить само приложение и забыть про эти вещи.

5f9965e3605161f4dd300be04d28567d.png

Sidecar Containers

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

1996fb339aec5962804a84c3d2383cdc.png

Sidecar-контейнеры чаще всего используются для добавления платформенной функциональности, например:

  • Service Mesh — в этом случае добавляется сетевой прокси, который обрабатывает все запросы, добавляет observability, делает mutual TLS и остальные полезные вещи.
  • Журналирование, если вам по каким-то причинам не нравится решение собирать логи через daemon, который бежит на воркере Kubernetes и забирает данные сразу с контейнерного runtime'а.
  • Централизованный аудит.

Adapter Containers

Адаптеры — такие же sidecar’ы, но узкоспециализированные. Они используются тогда, когда в приложение нужно добавить новый API, но не хочется (или не получается) сделать это на уровне приложения.

cce53b2dee0d640cea3d6a0e4a2b3b0b.png

Вот классические примеры:

  • Metrics API. Есть система мониторинга на базе Prometheus и приложение, которое про эту систему мониторинга вообще ничего не знает. У этого приложения есть либо только свои метрики, либо нет вообще нет никаких. Для «неинвазивного» решения проблемы достаточно добавить Prometheus экспортер отдельным контейнером, который опубликует все нужные метрики в правильном формате.
  • Custom API. Позволяет добавить произвольный API по аналогии с примером метрик.
  • RBAC Proxy. Дополнительный контейнер становится точкой входа в приложение и добавляет стандартный RBAC Kubernetes. Это делается очень быстро и во многих случаях бывает полезно.

Ambassador Containers

Эти контейнеры похожи на адаптеры, но работают в обратную сторону: они инкапсулируют в себя всю сложность внешнего API и позволяют использовать его понятным для приложения способом.

e6282fac9c8b0d7a39d8df0afc528c9c.png

Распространённые примеры использования:

  • Kubernetes API Access. Допустим, наше приложение умеет работать только с файлами и может читать оттуда свои конфигурации. При этом количество файлов не ограничено, и состав часто меняется — пользователи добавляют новые и удаляют неактуальные. Стандартная история с ConfigMaps тут не слишком удобная.

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

  • Distributed or Local Cache Access. Можно унифицировать доступ к сложным распределённым кешам со стороны приложения.
  • Data Access within a Data Mesh. Можно построить витрину данных, которая доступна непосредственно приложению.

Как добавлять контейнеры?

Самый простой способ — использовать обычные Kubernetes-манифесты. Достаточно добавить нужные контейнеры в спецификацию деплоймента (template spec). Но этот способ приводит к огромному количеству boilerplate yaml-файлов.

Кажется, что решением могут стать различные template-менеджеры (Helm, Kustomize, CUE и т. д.). Они дадут какое-никакое управление зависимостями: платформенные команды смогут публиковать свои артефакты, на которые уже прикладные разработчики будут ссылаться и использовать. В результате количество yaml-кода сильно сократится.

Но есть нюанс: template-менеджеры в конечном итоге развернут все в тот самый Raw Kubernetes Resource, который будет использован в кластере.

В целом это рабочий подход. Но есть нюанс: у платформенных и прикладных разработчиков разный релизный цикл. И платформенным командам нужно публиковать свои sidecars независимо, без запроса на обновление бизнес-приложения, а сделать это будет невозможно.

Для enterprise-решений это довольно серьезная проблема, поэтому важно разводить эти два релизных процесса. Хорошо, что Kubernetes позволяет это сделать.

Automated Approach — k8s admission

Когда вы создаёте объект внутри Kubernetes (например, делаете kubectl apply -f myfile.yaml), он проходит предобработку из нескольких этапов, которые реализуются с помощью специализированных admission контроллеров.

fc9fe58eb15e8d4afd888b3befa71138.png