Deployment в Kubernetes — это основной контроллер для декларативного управления жизненным циклом stateless-приложений в кластере. Вместо ручного создания и обновления подов (Pods) вы описываете желаемое состояние приложения в YAML-манифесте: сколько должно работать реплик, какой образ контейнера использовать и как проводить обновления. Kubernetes непрерывно сравнивает фактическое состояние кластера с этим описанием и автоматически вносит корректировки, обеспечивая отказоустойчивость и минимальный простой. Это фундаментальный инструмент для любого DevOps-инженера, работающего с production-средами.
Эта статья предоставляет готовые, проверенные конфигурации и шаблоны манифестов для production-развертывания. Вы найдете детальные примеры для веб-приложений, API-сервисов и микросервисов, а также пошаговое руководство по ключевым настройкам: стратегиям обновления, проверкам жизнеспособности и управлению ресурсами. Используйте эти шаблоны, чтобы избежать типичных ошибок и сэкономить время при настройке.
Кратко: какой Deployment YAML нужен для production
Deployment используют для stateless-приложений, когда поды взаимозаменяемы, а Kubernetes должен поддерживать заданное количество реплик и выполнять обновление без простоя. Минимальный production deployment обычно включает конкретную версию образа, согласованные selector и labels, стратегию RollingUpdate, проверки livenessProbe и readinessProbe, а также resources requests limits.
В статье последовательно разобраны базовый YAML, поля strategy, probes, ресурсы, rollback и типичные ошибки. Для быстрого перехода к нужной задаче используйте разделы: создание Deployment, структура манифеста, RollingUpdate и Recreate, production-примеры, Best Practices, чеклист и FAQ.
Готовый production-манифест Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: production-app
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: production-app
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
template:
metadata:
labels:
app: production-app
spec:
containers:
- name: app-container
image: nginx:1.25-alpine
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"Манифест можно применить командой kubectl apply -f deployment.yaml, а результат обновления проверить через kubectl rollout status deployment/production-app. Значения ресурсов и параметры probes необходимо адаптировать под фактическое приложение и его метрики.
Как быстро создать Deployment
Самый простой способ создать Deployment — использовать команду kubectl или минимальный YAML-манифест. Вот базовый пример для быстрого старта:
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app
spec:
replicas: 2
selector:
matchLabels:
app: example-app
template:
metadata:
labels:
app: example-app
spec:
containers:
- name: app
image: nginx:alpine
ports:
- containerPort: 80Примените манифест командой: kubectl apply -f deployment.yaml. Это создаст 2 реплики приложения на основе образа nginx:alpine.
По своей философии Deployment действует как слой управления (governance layer) для вашего приложения. Он обеспечивает соблюдение правил (например, количество реплик, стратегия обновления) и документирует конфигурацию через YAML. В этом руководстве мы детально разберем структуру манифеста, стратегии обновления RollingUpdate и Recreate, а также предоставим готовые практические примеры для веб-приложений, микросервисов и приложений с состоянием.
Что такое Deployment и почему он — основа управления приложениями в Kubernetes
Deployment — это объект API Kubernetes, который управляет развертыванием и обновлением набора идентичных подов. Его ключевая роль — обеспечить декларативное управление желаемым состоянием (desired state). Вы не даете кластеру команды «создать 3 пода» или «обновить образ». Вместо этого вы заявляете: «Я хочу, чтобы работало 3 реплики моего приложения на образе app:v2.0». Контроллер Deployment, работающий в плоскости управления Kubernetes, постоянно отслеживает это состояние и реактивно вносит изменения для его достижения и поддержания.
Без Deployment вам пришлось бы вручную управлять подами, что чревато ошибками, простоями и сложным масштабированием. Deployment абстрагирует эту работу, предоставляя надежный механизм для развертывания, масштабирования (изменения replicas), обновления и отката приложений.
Желаемое состояние: как Deployment обеспечивает порядок в кластере
Концепция желаемого состояния (desired state) — краеугольный камень Kubernetes. Вы описываете цель в YAML-манифесте, а система непрерывно работает для её достижения. Deployment выступает в роли исполнителя этой философии для рабочих нагрузок без состояния. Он не управляет подами напрямую, а создает и управляет объектом ReplicaSet, который, в свою очередь, гарантирует наличие указанного количества идентичных подов.
Схема работы: Deployment -> ReplicaSet -> Pod(s). При обновлении образа приложения Deployment создает новый ReplicaSet с обновленным шаблоном пода и начинает плавно переносить нагрузку на новые поды, управляя жизненным циклом старого ReplicaSet. Такой подход обеспечивает документированность (весь процесс описан в YAML), воспроизводимость и контроль.
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: 80replicas и 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 и память. Лимиты предотвращают истощение ресурсов узла.
- livenessProbe, readinessProbe: Проверки жизнеспособности и готовности. Критически важны для production, так как позволяют Kubernetes понимать, жив ли контейнер и готов ли он принимать трафик.
Стратегии обновления: 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) на время перезапуска.
Используйте эту стратегию только в особых случаях:
- Приложения, которые не поддерживают работу в двух разных версиях одновременно (например, из-за изменений в схеме общей базы данных).
- Критичные изменения конфигурации, требующие полного перезапуска всех экземпляров.
- Если ваше приложение не имеет внешнего состояния и быстрый перезапуск допустим.
Для сложных обновлений, например, с миграцией данных, может быть полезно ознакомиться с практиками безопасного деплоя в 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 не гарантирует устойчивых идентификаторов подов или порядка запуска.
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>.
Часто задаваемые вопросы (FAQ)
Как настроить RollingUpdate в Kubernetes Deployment?
Стратегия RollingUpdate настраивается в секции spec.strategy манифеста Deployment. Укажите type: RollingUpdate и задайте параметры rollingUpdate.maxUnavailable и rollingUpdate.maxSurge. Эти параметры определяют, сколько подов может быть временно недоступно и сколько дополнительных подов может быть создано в процессе обновления. Например, maxUnavailable: 1 и maxSurge: 1 гарантируют, что во время обновления будет недоступно не более одного пода, а общее количество подов не превысит желаемое более чем на один.
Что такое livenessProbe и readinessProbe?
livenessProbe — это проверка, которая определяет, жив ли контейнер. Если проверка не проходит, Kubernetes перезапускает контейнер. Она используется для восстановления после зависаний (deadlock). readinessProbe — это проверка, которая определяет, готов ли контейнер принимать трафик. Если проверка не проходит, под исключается из балансировки нагрузки. Это критически важно для плавного обновления (RollingUpdate), чтобы трафик не направлялся на еще не готовые поды.
Как ограничить ресурсы CPU и памяти в Kubernetes?
Ограничения ресурсов задаются в секции resources для каждого контейнера в манифесте пода. Параметр requests определяет гарантированный минимум ресурсов, который планировщик резервирует для пода. Параметр limits задает жесткий верхний предел потребления. Если контейнер превысит лимит по памяти, он будет принудительно завершен (OOMKilled). Превышение лимита по CPU приведет к искусственному замедлению (throttling). Рекомендуется всегда задавать оба параметра для всех production-нагрузок.
Чем Deployment отличается от ReplicaSet?
ReplicaSet поддерживает заданное количество идентичных подов, но Deployment дополнительно управляет версиями приложения, создает новые ReplicaSet при изменении шаблона и предоставляет стратегии обновления и отката. Поэтому для обычного развертывания stateless-приложения используют Deployment, а не ReplicaSet напрямую.
Как понять статус rollout в Kubernetes?
Выполните команду kubectl rollout status deployment/<name>. Она показывает, завершено ли обновление и стали ли новые поды готовыми. Для дополнительной диагностики используйте kubectl get pods, kubectl describe deployment/<name> и проверку событий namespace.
Когда использовать Recreate вместо RollingUpdate?
Recreate нужен, когда приложение не может одновременно работать в двух версиях или когда перед запуском новой версии необходимо полностью остановить старую. Следует учитывать downtime: все текущие поды будут удалены до создания новых.
Как исправить mismatch selector/labels в Deployment?
Проверьте, что значения в spec.selector.matchLabels полностью совпадают с соответствующими значениями в spec.template.metadata.labels. Несовпадение не позволяет Deployment корректно связать ReplicaSet с подами. После создания Deployment поле spec.selector нельзя изменить обычным обновлением, поэтому для исправления может потребоваться удалить объект и создать его заново с согласованными labels.