Deployment в Kubernetes — это основной контроллер для декларативного управления жизненным циклом stateless-приложений в кластере. Вместо ручного создания и обновления подов (Pods) вы описываете желаемое состояние приложения в YAML-манифесте: сколько должно работать реплик, какой образ контейнера использовать и как проводить обновления. Kubernetes непрерывно сравнивает фактическое состояние кластера с этим описанием и автоматически вносит корректировки, обеспечивая отказоустойчивость и минимальный простой. Это фундаментальный инструмент для любого DevOps-инженера, работающего с production-средами.
По своей философии Deployment действует как слой управления (governance layer) для вашего приложения, аналогично тому, как системы вроде Eidos AGI устанавливают guardrails для AI-агентов. Он обеспечивает соблюдение правил (например, количество реплик, стратегия обновления) и документирует конфигурацию через YAML, что схоже с ведением Architectural Decision Records (ADR). В этом руководстве мы детально разберем структуру манифеста, стратегии обновления RollingUpdate и Recreate, а также предоставим готовые практические примеры для веб-приложений, микросервисов и приложений с состоянием.
Что такое Deployment и почему он — основа управления приложениями в Kubernetes
Deployment — это объект API Kubernetes, который управляет развертыванием и обновлением набора идентичных подов. Его ключевая роль — обеспечить декларативное управление желаемым состоянием (desired state). Вы не даете кластеру команды «создать 3 пода» или «обновить образ». Вместо этого вы заявляете: «Я хочу, чтобы работало 3 реплики моего приложения на образе app:v2.0». Контроллер Deployment, работающий в плоскости управления Kubernetes, постоянно отслеживает это состояние и реактивно вносит изменения для его достижения и поддержания.
Этот принцип аналогичен работе реактивных UI-фреймворков, таких как Floem, где состояние интерфейса (сигнал) автоматически вызывает обновления представления. В Kubernetes состояние (например, количество готовых реплик) — это сигнал, на который реагируют контроллеры. Без Deployment вам пришлось бы вручную управлять подами, что чревато ошибками, простоями и сложным масштабированием. Deployment абстрагирует эту работу, предоставляя надежный механизм для развертывания, масштабирования (изменения replicas), обновления и отката приложений.
Желаемое состояние: как Deployment обеспечивает порядок в кластере
Концепция желаемого состояния (desired state) — краеугольный камень Kubernetes. Вы описываете цель в YAML-манифесте, а система непрерывно работает для её достижения. Deployment выступает в роли исполнителя этой философии для рабочих нагрузок без состояния. Он не управляет подами напрямую, а создает и управляет объектом ReplicaSet, который, в свою очередь, гарантирует наличие указанного количества идентичных подов.
Схема работы: Deployment -> ReplicaSet -> Pod(s). При обновлении образа приложения Deployment создает новый ReplicaSet с обновленным шаблоном пода и начинает плавно переносить нагрузку на новые поды, управляя жизненным циклом старого ReplicaSet. Такой подход обеспечивает документированность (весь процесс описан в YAML), воспроизводимость и контроль, подобно тому, как governance-системы устанавливают правила и отслеживают выполнение задач для AI-агентов.
Deployment vs другие контроллеры: когда что использовать
Выбор правильного контроллера критически важен для корректной работы приложения. Deployment предназначен в первую очередь для stateless-приложений, где каждый под является взаимозаменяемой единицей.
- StatefulSet: Используйте для stateful-приложений, требующих устойчивых сетевых идентификаторов (стабильные имена хостов), упорядоченного и безопасного развертывания/масштабирования, а также постоянного хранилища (PersistentVolume). Примеры: базы данных (MySQL, PostgreSQL), кластеры Kafka, Elasticsearch.
- DaemonSet: Используйте, когда необходимо запустить под на каждом (или на некоторых) узле кластера. Идеален для системных демонов: сборщики логов (Fluentd), мониторинг (Node Exporter), сетевые плагины.
- Job / CronJob: Используйте для выполнения разовых задач (Job) или задач по расписанию (CronJob), которые должны завершиться. После выполнения поди останавливаются. Примеры: миграции БД, пакетная обработка, ночные репорты.
Для большинства веб-приложений, API-сервисов и микросервисов без сохранения состояния на локальном диске Deployment является правильным и достаточным выбором.
Структура YAML-манифеста Deployment: разбор ключевых полей
Практическая работа с Deployment начинается с YAML-манифеста. Понимание каждого поля необходимо для эффективного управления. Вот базовый каркас:
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: example-app
template:
metadata:
labels:
app: example-app
spec:
containers:
- name: app-container
image: nginx:1.25-alpine
ports:
- containerPort: 80
replicas и selector: управление масштабом и связывание
Поле spec.replicas определяет желаемое количество идентичных реплик (подов) вашего приложения, которые должны работать одновременно. Это основа для горизонтального масштабирования. Изменить количество можно как правкой манифеста и применением kubectl apply, так и командой kubectl scale deployment/example-app --replicas=5.
Поле spec.selector критически важно для связывания Deployment с управляемыми им подами. Deployment использует селектор matchLabels для поиска подов, которыми он должен управлять. Метки (labels), указанные здесь, должны точно совпадать с метками, заданными в spec.template.metadata.labels. Это механизм, с помощью которого созданный Deployment'ом ReplicaSet находит «свои» поды. Используйте уникальные, осмысленные пары ключ-значение, например, app: example-app, component: api.
template: определение контейнеров и их конфигурации
Блок spec.template — это шаблон пода (Pod Template). Именно здесь определяется само приложение. Внутри template.spec вы описываете контейнеры аналогично обычному Pod-манифесту.
- containers: Список контейнеров в поде. Для большинства приложений он состоит из одного элемента.
- name: Уникальное имя контейнера внутри пода.
- image: Имя Docker-образа и его тег. Всегда указывайте конкретный тег (не
latest) для воспроизводимости. - ports: Список портов, которые контейнер открывает.
- resources: Запросы (requests) и лимиты (limits) на CPU и память. Лимиты — это guardrails, предотвращающие истощение ресурсов узла, аналогично ограничениям для AI-агентов.
- livenessProbe, readinessProbe: Проверки жизнеспособности и готовности. Критически важны для production, так как позволяют Kubernetes понимать, жив ли контейнер и готов ли он принимать трафик. Их настройка — это форма проверки задачи перед допуском к работе, как в системах управления вроде Eidos AGI.
Стратегии обновления: RollingUpdate и Recreate для минимизации downtime
Одна из ключевых функций Deployment — управляемое обновление приложения. Стратегия обновления задается в поле spec.strategy.type. Выбор правильной стратегии напрямую влияет на доступность сервиса во время деплоя.
RollingUpdate: плавное обновление без простоев
Стратегия RollingUpdate (используется по умолчанию) обеспечивает постепенное обновление реплик приложения без остановки всего сервиса. Новые поды создаются с новой версией, и после их готовности (readinessProbe проходит) старые поды постепенно удаляются. Доступность поддерживается на протяжении всего процесса.
Поведение управляется двумя параметрами в spec.strategy.rollingUpdate:
- maxUnavailable: Максимальное количество подов, которые могут быть недоступны во время обновления. Может быть абсолютным числом (например, 1) или процентом от replicas (например, 25%). Установка в 0 означает, что нельзя удалять старые поды, пока новые не станут готовы.
- maxSurge: Максимальное количество подов, которые могут быть созданы сверх желаемого количества replicas. Может быть абсолютным числом или процентом. Установка в 1 позволяет создать одну новую реплику перед удалением старой, ускоряя обновление.
Пример для 3 реплик: maxUnavailable: 1 и maxSurge: 1. При обновлении Kubernetes может: 1) создать 1 новый под (всего 4), 2) после его готовности удалить 1 старый под (остается 3), 3) повторять цикл, пока все поды не будут обновлены. Для веб-приложений и микросервисов часто используют maxUnavailable: 25% и maxSurge: 25% для баланса скорости и доступности.
Recreate: когда нужна полная остановка
Стратегия Recreate полностью останавливает текущую версию приложения (удаляет все поды) перед созданием новых. Это приводит к простою (downtime) на время перезапуска.
Используйте эту стратегию только в особых случаях:
- Приложения, которые не поддерживают работу в двух разных версиях одновременно (например, из-за изменений в схеме общей базы данных).
- Критичные изменения конфигурации, требующие полного перезапуска всех экземпляров.
- Если ваше приложение не имеет внешнего состояния и быстрый перезапуск допустим.
Этот сценарий требует особого внимания, подобно выполнению рискованной операции миграции в системах управления, где необходимо предварительное документирование решения (ADR) и полный контроль над процессом. Для сложных обновлений, например, с миграцией данных, может быть полезно ознакомиться с практиками безопасного деплоя в production.
Практические примеры развертывания разных типов приложений
Теория закрепляется практикой. Ниже приведены готовые к использованию манифесты для типичных сценариев.
Пример 1: Развертывание веб-приложения (Nginx)
Базовый stateless Deployment для веб-сервера с проверкой готовности.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-web
spec:
replicas: 2
selector:
matchLabels:
app: nginx-web
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: nginx-web
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
readinessProbe: # Проверка готовности
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"
Пример 2: Развертывание микросервиса (API сервис)
Deployment для REST API сервиса с настройкой ресурсов и обеими проверками (liveness и readiness).
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service
spec:
replicas: 3
selector:
matchLabels:
app: api-service
version: v1
template:
metadata:
labels:
app: api-service
version: v1
spec:
containers:
- name: api
image: myregistry/api-service:2.5.1
ports:
- containerPort: 8080
env:
- name: DB_HOST
value: "postgres-service"
livenessProbe: # Проверка, жив ли контейнер
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readinessProbe: # Проверка, готов ли принимать трафик
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits: # Guardrails для ресурсов
memory: "512Mi"
cpu: "500m"
Пример 3: Развертывание приложения с состоянием (с временным хранилищем)
Deployment для приложения, которому нужно временное хранилище на уровне пода (например, для кэша). Важно: для истинно stateful-приложений с постоянными данными используйте StatefulSet.
apiVersion: apps/v1
kind: Deployment
metadata:
name: cache-app
spec:
replicas: 2
selector:
matchLabels:
app: cache-app
template:
metadata:
labels:
app: cache-app
spec:
containers:
- name: app
image: redis:7-alpine
ports:
- containerPort: 6379
volumeMounts:
- name: cache-storage
mountPath: /data
volumes:
- name: cache-storage
emptyDir: {} # Временное хранилище, живет пока жив под.
Внимание: Использование emptyDir в Deployment означает, что данные будут потеряны при пересоздании или перемещении пода на другой узел. Для данных, которые должны сохраняться, необходимо использовать PersistentVolumeClaim и понимать, что Deployment не гарантирует устойчивых идентификаторов подов или порядка запуска. В таких случаях изучите различия в инструментах конфигурации, чтобы выбрать правильный подход для хранения конфигов, и рассмотрите переход на StatefulSet.
Best Practices и guardrails для production-сред
Следование проверенным практикам превращает Deployment из рабочего инструмента в надежный механизм управления production-нагрузкой.
Настройка проверок жизнеспособности (liveness/readiness probes)
Probes — это механизм обратной связи приложения с Kubernetes.
- livenessProbe определяет, жив ли контейнер. Если проверка падает, Kubernetes перезапускает контейнер. Используйте для обнаружения «зависших» состояний (deadlock).
- readinessProbe определяет, готов ли контейнер принимать трафик. Пода с непройденной проверкой исключается из балансировщиков нагрузки Service. Критично для плавного обновления (RollingUpdate).
Настраивайте разные эндпоинты для liveness и readiness. Liveness-эндпоинт должен быть легковесным и не зависеть от внешних сервисов (БД, кэш). Readiness-эндпоинт может проверять доступность всех критичных зависимостей. Правильные интервалы (initialDelaySeconds, periodSeconds) предотвращают ложные перезапуски.
Управление ресурсами и предотвращение инцидентов
Всегда задавайте resources.requests и resources.limits.
- requests: Гарантированное количество CPU/памяти, которое планировщик Kubernetes резервирует для пода. Под будет размещен на узле, где есть достаточно свободных ресурсов.
- limits: Максимальное количество ресурсов, которое контейнер может использовать. Если контейнер превышает лимит по памяти (OOM), он будет убит. Превышение лимита по CPU приведет к throttling.
Отсутствие limits — частая причина инцидентов, когда один контейнер исчерпывает память узла, вызывая падение всех остальных подов на нем. Слишком завышенные requests ведут к неэффективному использованию кластера. Начинайте с умеренных значений, основанных на метриках мониторинга, и корректируйте. Для оркестрации более сложных зависимостей и шаблонов развертывания рассмотрите использование инструментов вроде Helm. Шпаргалка по командам Helm CLI поможет ускорить работу.
Итоговый чеклист для production Deployment:
- Всегда используйте readinessProbe и livenessProbe.
- Всегда задавайте limits и requests для CPU и памяти.
- Используйте стратегию RollingUpdate с настроенными maxUnavailable/maxSurge.
- Избегайте тега образа
latest, используйте семантическое версионирование. - Применяйте метки (labels) для организации ресурсов и селекторов.
- Храните манифесты в системе контроля версий (Git) — это ваши ADR для инфраструктуры.
- Мониторьте статус развертываний:
kubectl get deployments,kubectl rollout status deployment/<name>,kubectl describe deployment/<name>. - Знайте, как выполнить откат:
kubectl rollout undo deployment/<name>.
Следуя этим принципам, вы создадите отказоустойчивую, предсказуемую и легко управляемую среду для ваших приложений в Kubernetes, минимизируя риски и простои, аналогично тому, как системы управления обеспечивают безопасное выполнение задач в сложных средах.