Обзор Kubernetes Patterns
Kubernetes давно стал стандартом де-факто как среды для эксплуатации cloud native
приложений. А именно такие приложения модно делать в настоящее время. Но для того, чтобы понимать почему он так популярен, надо знать подходы, которые он предлагает для решения стандартных проблем разработки. Например, эти проблемы упоминались еще в манифесте 12 factor app от Heroku
.
В свое время мне пришлось знакомиться со всем этим по официальной документации проекта на kubernetes.io. Я справился, прошел сертификацию и получил статус CKA
(Certified Kubernetes Administrator
). Но теперь есть лучший способ, чтобы познакомиться с функционалом этого оркестратора — а именно прочитав книгу Kubernetes Patterns… Или хотя бы это краткое саммари.


По структуре книга напоминает классическую книгу “Design Patterns” банды четырех, которая содержала creational, structural и behavioral паттерны. Но у нас здесь 5 категорий паттернов:
Foundation patterns
— базовые блокиk8s
, на основе которых строится все остальноеBehavioral patterns
— поведенческие паттерны, которые позволяют добиться желаемого поведения, например, запуска периодическихjob
или приложения синглтонаStructural patterns
— структурные паттерны, которые показывают как можно расширить функционал основного контейнера добавив другие контейнеры вpod
Configuration patterns
— конфигурационные паттерны, которые позволяют эффективнее управлять конфигурацией ваших приложенийAdvanced patterns
— продвинутые паттерны, которые раскрывают темы того, как работает самk8s
и как его можно расширять
Общий список паттернов представлен на рисунке ниже.

Но начнем бы с базы, а именно с
Foundational patterns
Все начинается с паттерна Predictable Demands
, который говорит о том, что ваше приложение должно декларировать свои потребности и придерживаться их. Это может относиться как runtime
зависимостям (диск, configMap
, …), так и к запрошенным ресурсам (cpu
, memory
), что позволяет как планировать мощности кластера в целом, так и помогает с шедулингом pods
на конкретные ноды в кластере.
Дальше идет декларативное развертывание (Declarative Deployment
), которое позволяет нам описать как деплоить наше приложение и оркестратор сам позаботиться обо всем:) Среди вариантов развертываний есть: rolling deployment
, fixed deployment
, blue green
, canary release
. Здесь есть крутые gif
, которые демонстрируют эти стратегии в динамике.
Для того, чтобы k8s
мог поддерживать работоспособность приложения ему требуется некоторая помощь от разработчиков, которые должны реализовать health probes
. Эти пробы включают Liveness
, Readiness and Startup Probes
, где каждая имеет свое назначение:
liveness
— проба, которая позволяет понять живо еще приложение или его надо развернуть зановоreadiness
— проба, которая говорит о том, можно ли роутить запросы в приложение или оно не готово, например, в приложении возникли проблемы и мы не хотstartup
— проба для стартующих медленно приложений, которые на старте прогреваются (приветjava
)
Подробнее про настройку этих проб можно почитать в документации.
Следующий паттерн — это Managed Lifecycle
, который говорит о том, что хорошие cloud native
приложения должны определенным образом организовывать свой жизненный цикл. Фактически, за управление этим жизненным циклом отвечает платформа оркестрации, которая стартует приложения, отправляет при необходимости SIGTERM
, SIGKILL
и дергает хуки типа PreStop
, PostStart
и подобные. Важно сделать так, чтобы приложение умело работать с указанными выше событиями, а также использовало при необходимости нужные хуки.
И финальный паттерн в этом разделе Automated Placement
, который относится к ключевому функционалу k8s
, который планирует размещение подов на конкретные ноды кластера с учетом
- запросов конкретных контейнеров
- доступных нод и ресурсов в рамках них (
cpu
,memory
,volumes
, …) - политик размещения (
placement policies
) - правил
affinity
иantiaffinity
, а такжеtaints
иtolerations
В общем, это ключевой функционал, который работает под капотом оркестратора, чтобы обеспечить наш декларативно оформленный deployment
.
Behavioral patterns
Паттерны из этой категории посвящены взаимодействию между подами и платформой оркестрации. Многие из этих паттернов напоминают старых знакомых из мира Linux
, которые просто переехали в мир распределенных систем.
Начинается все с паттерна Batch Job
, который описывает изолированную часть работы, которая работает до выполнения. Следующий паттерн Periodic Job
напоминает работу cron job
и заключается в выполнении какого-то объема работы, привязанное к определенному моменту во времени. Кстати, точных гарантий, что работа начнется ровно в это время нет.
Следующий паттерн — Daemon Service
, который позволяет запускать специальные поды, больше сфокусированные на инфраструктурных задачах, перед запуском подов самого приложения.
Следующий паттерн singleton service
, который позволяет гарантировать запуск только одной копии сервиса, но все еще в режиме высокой доступности (high availability
). Тут интересно, что решение в лоб, через ReplicaSet
с фактором репликации 1 не проходит, так как
Kubernetes primitives such as ReplicaSet, favor availability over consistency — a deliberate decision for achieving highly available and scalable distributed systems. That means a ReplicaSet applies “at least” rather than “at most” semantics for its replicas
Но для реализации поведения singleton service
мы должны придерживаться подхода, что consistency важнее availability
, и такой примитив в Kubernetes
есть и это StatefulSet
. Но если требуется действительно надежное поведение, то придется реализовывать in-app locking
на уровне приложения.
Для реализации stateful приложений внутри k8s
используется паттерн Stateful Service
, который обеспечивает такие фичи как постоянные identity
, сеть, диск, ординальность. Все это реализуется при помощи использования описания сервиса в виде StatefulSet
. Помимо указанных выше есть и другие фичи, такие как partitioned updates
, parallel deployments
и at-most-one guarantee
. Ну и напоследок цитата авторов книги насчет StatefulSet
It provides a good set of building blocks for managing stateful applications in an automated fashion, making them first-class citizens in the cloud-native world
Следующий паттерн относится к тому, как клиенты получают доступ к информации о том, где развернуты инстансы, предоставляющие сервисы приложений. Суть в том, что оркестратор в любой момент может сделать rescheduling
конкретных подов и они переедут на другую ноду, но трафик должен все так же успешно доходить до приложений. За это отвечает Service Discovery
. Механизмы отличаются для service discovery
внутри кластера и для внешнего трафика. Среди разных механизмов есть
- внутренние —
ClusterIP
,Manual IP
,Manual FQDN
,Headless Service
- внешние —
NodePort
,LoadBalancer
,Ingress
Ну и последним паттерном из этой категории является Self Awareness
, который позволяет приложению воспользоваться интроспекцией и получить метаданные о себе для того, чтобы вставить их в приложение. Данные можно получить через Env Variable
и посредством Downward API
, например, мы можем узнать про имя ноды, IP
ноды, имя пода, IP
пода, данные по request
и limit
пода и т.д. Эти данные можно использовать для того, чтобы подтюнить приложение или для расширения информации по логам и метрикам, которые отгружаются приложением.
Structural patterns
Эти паттерны рассказывают про то, как эффективнее использовать такую структуру как pod
, который является единицей развертывания и включает группу контейнеров. Основная логика этих паттернов в том, что мы добавляем специализированные контейнеры в под наряду с контейнерами основного приложения и это расширяет функционал или добавляет удобства.
Ну и все начинается с паттерна Init Container
, который добавляет отдельный жизненный цикл для задач инициализации основного приложения, состоящего из группы контейнеров. Суть в том, что подготовительная работа выполняется init
контейнером, после успеха которой стартует основные контейнеры.
Продолжается все с того, как использовать паттерн Sidecar
для расширения функционала основного приложения без его изменения. По факту, это реализация подхода композиции из объектно-ориентированного мира.
Следующий паттерн Adapter
, который является sidecar
, но сфокусирован на том, чтобы стандартизировать и унифицировать распределенную гетерогенную систему, приведя к каноническому формату. Например, это отлично подходит для инфраструктурных задач типа логирования и мониторинга.
И последний паттерн из этой группы — это Ambassador
, который является sidecar
, но сфокусирован на упрощении взаимодействия приложений со внешним миром. Например, этот паттерн может выступать в качестве прокси и отвязывать основной под от внешних зависимостей.
Configuration patterns
Каждое приложение требует конфигурации. Хранить конфигурацию захардкоженной внутри приложения — давно антипаттерн. В этих паттернах идет речь о том, какие возможности есть у Kubernetes
для конфигурирования приложений.
Простейший подход — это EnvVar Configuration
, в которой для конфигурирования приложения используются переменные окружения (environment variables
). В Kubernetes их можно подтянуть из файла, из ConfigMap
или из Secret
. Этот подход хорош для небольших приложений и плохо масштабируется на большое количество параметров конфигурации.
Если параметров много, то удобнее использовать Configuration Resource
для хранения и передачу параметров в приложения. Такими ресурсами являются ConfigMaps
и Secrets
. Эти ресурсы можно подключать в качестве environment variables
или подключенных volumes
.
Еще один вариант Immutable Configuration
— это хранение конфигурации в отдельном контейнере, который подключается внутрь пода в качестве sidecar к нашему основному приложению.
И последний паттерн Configuration Template
, который позволяет создавать и обрабатывать большие конфигурации во время старта приложений. Сгенерированные конфигурации специфичны для runtime окружения и внутри них используются параметры, которые были подставлены в конфигурационные темплейты.
Advanced patterns
В последней части рассматриваются более сложные паттерны, которые не попали в предыдущие категории. Первый паттерн Controller
является базовым блоком Kubernetes
, который отслеживает состояние и поддерживает ресурсы в нужном состоянии, например, количество реплик приложения для ReplicaSet
.
Второй паттерн Operator
объединяет концепцию Controller
с кастомным определением ресурсов (CRD
, Custom Resource Definitions
). По-факту, этот паттерн позволяет реализовать эксплуатацию кастомного приложения в автоматической форме, напоминающей подход самого Kubernetes
. Подробнее можно прочитать в документации Operator Framework.
Третий паттерн Elastic Scale
очень интересен, так как именно он является killer
фичей для заезжающих в kubernetes
приложений. По-факту, мы можем декларативно описать правила масштабирования среди которых
Horizontal Pod Autoscaling
— увеличение количества инстансов приложения путем увеличения количества подовVertical Pod Autoscaling
— увеличение ресурсов, выделенных для конкретных подовCluster Autoscaling
— увеличение размеров кластера, а именно доступных нод
И последний паттерн Image Builder
переносит аспект билда образов приложений прямо внутрь кластера.
Итого
Книга вышла крайне интересной и полезной для архитекторов. Современные приложения обычно реализуется в cloud native
стиле, где постоянно приходится использовать паттерны, приведенные в данной книге. Правда, сама книга вышла в 2019 году, что уже достаточно давно для мира cloud native
, поэтому помимо книги читайте официальную документацию с kubernetes.io