Kubernetes: рабочие нагрузки
Deployment, ReplicaSet, StatefulSet и DaemonSet, Job и CronJob, плавающие обновления и откат, HPA и семейство автоскейлинга.
12 вопросов
JuniorТеорияОчень частоЧто такое Deployment в Kubernetes и как он связан с ReplicaSet и с Pod?
Что такое Deployment в Kubernetes и как он связан с ReplicaSet и с Pod?
Deployment — контроллер для stateless-приложений: он объявляет желаемый образ и число реплик. Он управляет объектом ReplicaSet, который держит столько одинаковых Pod запущенными — Pod и есть контейнеры. При обновлении он создаёт новый ReplicaSet и переносит Pod, поэтому вы правите Deployment, а не Pod напрямую.
Типичные ошибки
- ✗Считать Deployment одним Pod, а не контроллером над ReplicaSet
- ✗Править Pod напрямую вместо spec самого Deployment
- ✗Думать, что Deployment общается с Pod без ReplicaSet между ними
Уточняющие вопросы
- →Что происходит со старым ReplicaSet после успешного плавающего обновления?
- →Почему масштабирование Deployment меняет реплики, но не создаёт новый ReplicaSet?
JuniorТеорияЧастоВ чём разница между Job и CronJob в Kubernetes и когда нужен каждый?
В чём разница между Job и CronJob в Kubernetes и когда нужен каждый?
Job запускает Pod до завершения — повторяет, пока не наберётся заданное число успешных прогонов, затем останавливается; это разовая пакетная работа вроде миграции. CronJob — планировщик, создающий новый Job по cron-расписанию, для повторяющейся работы вроде ночных бэкапов. То есть CronJob — фабрика Job по времени.
Типичные ошибки
- ✗Менять роли местами — считать, что расписание несёт Job
- ✗Ждать, что Job работает вечно как Deployment, а не завершается
- ✗Думать, что CronJob сам делает работу, а не создаёт Job
Уточняющие вопросы
- →Что задают поля
completionsиparallelismу Job? - →Почему запуски CronJob могут пропускаться или накладываться и как это предотвратить?
JuniorКодЧастоДопишите минимальный манифест Deployment для приложения с 3 репликами и портом контейнера.
Допишите минимальный манифест Deployment для приложения с 3 репликами и портом контейнера.
Задайте spec.replicas: 3 и добавьте ports под контейнером с containerPort: 8080. selector.matchLabels должен совпадать с template.metadata.labels (app: web), иначе Deployment не подхватит ни одного Pod. apiVersion — apps/v1, kind — Deployment; template — это Pod-спека, которую ReplicaSet штампует три раза.
Типичные ошибки
- ✗Метки selector не совпадают с метками шаблона, и Pod не управляются
- ✗Класть
containerPortилиreplicasна неверный уровень вложенности - ✗Ставить
kind: Pod/apiVersion: v1вместоDeployment/apps/v1
Уточняющие вопросы
- →Что API отклонит при apply, если selector не совпадает с метками шаблона?
- →Почему
containerPortинформационный, а не то, что реально открывает приложение?
MiddleТеорияЧастоНа что масштабирует HorizontalPodAutoscaler (HPA) и что должно быть настроено, чтобы он работал?
На что масштабирует HorizontalPodAutoscaler (HPA) и что должно быть настроено, чтобы он работал?
HPA меняет число реплик Deployment под целевую метрику — обычно средний CPU. Ему нужен metrics-server (или адаптер кастомных метрик), отдающий живое потребление, а Pod должны объявлять requests, чтобы у процентной цели была база. Он масштабирует в пределах minReplicas/maxReplicas и не изменяет Pod.
Типичные ошибки
- ✗Путать HPA (число реплик) с VPA (requests у Pod)
- ✗Забывать про metrics-server и requests как условие для процентной цели
- ✗Думать, что HPA масштабирует узлы, а не Pod
Уточняющие вопросы
- →Почему цель по проценту CPU молча ломается, если Pod не объявляют requests?
- →Как HPA сводит несколько метрик к одному желаемому числу реплик?
MiddleТеорияЧастоКак откатить плохой Deployment и что на самом деле делает kubectl rollout undo?
Как откатить плохой Deployment и что на самом деле делает kubectl rollout undo?
kubectl rollout undo deploy/x возвращает к предыдущей ревизии. Kubernetes хранит старые ReplicaSet (в пределах revisionHistoryLimit), поэтому масштабирует прежний ReplicaSet вверх — это плавающее обновление. --to-revision=N целится в конкретную; rollout history их перечисляет. Он не удаляет Deployment и не трогает данные.
Типичные ошибки
- ✗Считать, что undo удаляет и пересоздаёт Deployment из сохранённого файла
- ✗Думать, что откат возвращает данные или тома, а не только Pod-шаблон
- ✗Полагать, что хранится лишь одна ревизия, и
--to-revisionнедоступен
Уточняющие вопросы
- →Как
revisionHistoryLimitвлияет на то, к каким ревизиям можно откатиться? - →Почему сам откат подчиняется той же стратегии плавающего обновления?
MiddleТеорияЧастоКак работает плавающее обновление и что задают maxSurge и maxUnavailable?
Как работает плавающее обновление и что задают maxSurge и maxUnavailable?
Плавающее обновление заменяет Pod постепенно — Deployment поднимает новые Pod и гасит старые по чуть-чуть, поэтому приложение остаётся доступным. maxSurge ограничивает число Pod сверх желаемого во время выката; maxUnavailable — сколько ниже него может отсутствовать. Новые Pod должны пройти readiness.
Типичные ошибки
- ✗Думать, что выкат удаляет все старые Pod до создания новых
- ✗Путать
maxSurge/maxUnavailableс ручками разделения трафика - ✗Забывать, что readiness гейтит каждый шаг выката
Уточняющие вопросы
- →Как взаимодействуют maxSurge: 0 и maxUnavailable: 0 и почему такая конфигурация недопустима?
- →Почему падающая readiness-проба останавливает плавающее обновление?
MiddleТеорияЧастоКогда использовать StatefulSet вместо Deployment и какие гарантии он добавляет?
Когда использовать StatefulSet вместо Deployment и какие гарантии он добавляет?
StatefulSet — для stateful-приложений со стабильной идентичностью: базы данных, кластерные хранилища. В отличие от взаимозаменяемых Pod у Deployment, каждый Pod получает стабильное имя и DNS-хостнейм, липкий PersistentVolumeClaim, переживающий пересоздание, и упорядоченные, по одному, создание/масштаб/обновление. Deployment — для stateless, заменяемых реплик.
Типичные ошибки
- ✗Считать StatefulSet просто Deployment под другим именем
- ✗Ждать, что Pod делят один PVC, а не каждый держит свой липкий
- ✗Упускать упорядоченное, по одному, создание, масштаб и обновление
Уточняющие вопросы
- →Как headless Service у StatefulSet даёт каждому Pod стабильное DNS-имя?
- →Что происходит с PVC Pod у StatefulSet при пересоздании Pod?
MiddleТеорияИногдаЧто такое DaemonSet и приведите два реальных случая, где он уместен?
Что такое DaemonSet и приведите два реальных случая, где он уместен?
DaemonSet запускает ровно один свой Pod на каждом узле (или на каждом, подходящем под selector) и сам добавляет Pod при появлении нового узла. В отличие от Deployment, число реплик вы не задаёте — его решает число узлов. Типичные случаи: понодовый сборщик логов вроде Fluent Bit и агент мониторинга вроде node-exporter.
Типичные ошибки
- ✗Задавать число реплик у DaemonSet вместо того, чтобы его решало число узлов
- ✗Думать, что он размещает Pod где угодно, а не по одному на узел
- ✗Забывать, что он сам добавляет Pod при появлении нового узла
Уточняющие вопросы
- →Как toleration позволяют DaemonSet работать на узлах control-plane с taint?
- →Как DaemonSet выкатывает обновление по своим Pod на каждом узле?
MiddleДебаггингИногдаПлавающее обновление застряло на 2 из 5 реплик, новые Pod не становятся Ready — разберитесь.
Плавающее обновление застряло на 2 из 5 реплик, новые Pod не становятся Ready — разберитесь.
Новые Pod Running, но 0/1 Ready — их readiness-проба отдаёт 503, и Deployment не выводит больше старых Pod: maxUnavailable ограничивает выкат, и он застревает. Чините причину readiness (зависимость, неверный path/port или малую задержку), а не число реплик. Если приложение медленно прогревается, добавьте startupProbe.
Типичные ошибки
- ✗Поднимать реплики или ресурсы вместо починки сбоя readiness
- ✗Удалять readiness-пробу, чтобы силой завершить выкат
- ✗Путать падающую readiness-пробу с ошибкой скачивания образа
Уточняющие вопросы
- →Когда верный фикс —
startupProbe, а когда — большийinitialDelaySeconds? - →Как
maxUnavailable: 0меняет поведение этого зависшего выката?
SeniorДебаггингИногдаHPA показывает TARGETS <unknown>/80% и не масштабирует — найдите обрыв в пути метрик.
HPA показывает TARGETS <unknown>/80% и не масштабирует — найдите обрыв в пути метрик.
<unknown> значит, что HPA не может прочитать метрику и не вычисляет число реплик. Падение kubectl top указывает на корень: нет metrics-server, и resource-metrics API ничего не отдаёт. Почините metrics-server и проверьте, что Pod объявляют requests CPU — цели по CPU% нужна база. Это не проблема порога или min/max.
Типичные ошибки
- ✗Снижать процент цели вместо восстановления конвейера метрик
- ✗Игнорировать, что падающий
kubectl topсигналит об отсутствии metrics-server - ✗Забывать, что цели по CPU% нужны requests у Pod для вычисления
Уточняющие вопросы
- →Почему HPA по проценту CPU требует, чтобы Pod объявляли requests CPU?
- →Как отличить сбой metrics-server от отсутствующего адаптера кастомных метрик?
SeniorТеорияИногдаСравните horizontal, vertical и cluster автоскейлинг — что масштабирует каждый и когда они конфликтуют?
Сравните horizontal, vertical и cluster автоскейлинг — что масштабирует каждый и когда они конфликтуют?
HorizontalPodAutoscaler (HPA) меняет число реплик под нагрузкой; VerticalPodAutoscaler (VPA) меняет requests у Pod; Cluster Autoscaler добавляет или убирает узлы, когда Pod негде разместить. HPA и VPA конфликтуют на одной метрике CPU — VPA поднимает requests и мешает HPA по CPU% — поэтому сочетайте VPA с HPA только на кастомных метриках.
Типичные ошибки
- ✗Путать, кто из них масштабирует реплики, requests или узлы
- ✗Запускать VPA и HPA на одной метрике CPU, из-за чего они борются
- ✗Считать, что Cluster Autoscaler меняет размер Pod, а не число узлов
Уточняющие вопросы
- →Почему Cluster Autoscaler может добавить узлы, но не суметь их убрать?
- →Как безопасно сочетать VPA и HPA на одной нагрузке?
SeniorКодРедкоЗапуски CronJob накладываются и копятся — исправьте через concurrencyPolicy и лимиты истории.
Запуски CronJob накладываются и копятся — исправьте через concurrencyPolicy и лимиты истории.
Задайте concurrencyPolicy: Forbid, чтобы новый запуск пропускался, пока предыдущий Job ещё идёт (или Replace, чтобы отменить старый). Ограничьте историю через successfulJobsHistoryLimit и failedJobsHistoryLimit (например 3 и 1); startingDeadlineSeconds пропускает просроченные тики. Forbid убирает накопление, а лимиты — старые Job из namespace.
Типичные ошибки
- ✗Думать, что
concurrencyPolicy: Allowпредотвращает наложение (он его разрешает) - ✗Путать лимиты истории с настройками повторов или параллелизма
- ✗Использовать
suspend(который останавливает все запуски) для фикса наложения
Уточняющие вопросы
- →Чем
ForbidиReplaceразличаются, когда запуск ещё идёт? - →Что делает
startingDeadlineSeconds, когда контроллер пропускает расписание?