Pod, Deployment, Service: кто за что отвечает

Первый вопрос по Kubernetes почти всегда про иерархию объектов — по ответу видно, писал ли кандидат манифесты сам.

Вопрос: «Объясните разницу между Pod, Deployment и Service. Что произойдёт, если удалить Pod, созданный вручную, и Pod, созданный Deployment?»

Что на самом деле проверяет интервьюер

Проверяют понимание декларативной модели: в Kubernetes вы описываете желаемое состояние, а контроллеры непрерывно приводят к нему реальность. Кандидат, который это понял, легко объяснит и самовосстановление, и масштабирование, и rolling update. Кандидат, который заучил определения, застрянет на уточняющем вопросе про удаление пода.

Развёрнутый ответ: три уровня

Pod — минимальная единица планирования

Pod — это один или несколько контейнеров, которые всегда живут на одной ноде, разделяют сетевой namespace (общий IP, общаются между собой через localhost) и могут делить тома. Pod эфемерен: у него нет постоянного IP, и он не переезжает — он умирает, а вместо него создаётся новый, с новым именем и новым адресом.

Несколько контейнеров в одном поде — это паттерн sidecar: основной контейнер приложения плюс вспомогательный (сборщик логов, прокси сервис-меша, обновлятор конфигурации). Класть в под два независимых приложения — типичная ошибка: они не смогут масштабироваться раздельно.

Deployment — контроллер, который следит за подами

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

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api          # по этой метке Deployment находит свои поды
  template:
    metadata:
      labels:
        app: api        # метка должна совпадать с селектором
    spec:
      containers:
        - name: api
          image: registry.local/api:1.4.2
          ports:
            - containerPort: 8080

Теперь можно ответить на вторую часть вопроса. Удалили под, созданный вручную (kind: Pod) — он исчез навсегда, восстанавливать его некому. Удалили под Deployment — ReplicaSet через секунду заметит, что реплик стало 2 вместо 3, и создаст новый под. Это и есть самовосстановление: не магия, а контроллер, который в цикле сравнивает желаемое состояние с фактическим.

Service — стабильный адрес для меняющихся подов

Поды приходят и уходят, IP меняются — обращаться к ним напрямую нельзя. Service даёт постоянные имя и виртуальный IP (ClusterIP), а список фактических адресов подов держит в объекте Endpoints/EndpointSlice, отбирая поды по меткам, а не по принадлежности к Deployment.

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api          # любые поды с этой меткой попадут под балансировку
  ports:
    - port: 80         # порт самого Service
      targetPort: 8080 # порт контейнера
  type: ClusterIP

Внутри кластера сервис доступен по DNS-имени api, а полностью — api.production.svc.cluster.local. Типы сервисов, которые нужно назвать:

ТипЧто даёт
ClusterIPадрес только внутри кластера (по умолчанию)
NodePortпорт из диапазона 30000–32767 на каждой ноде
LoadBalancerвнешний балансировщик от облачного провайдера
Headless (clusterIP: None)DNS возвращает IP всех подов; нужен StatefulSet и клиентской балансировке

Для HTTP наружу обычно используют не LoadBalancer на каждый сервис, а Ingress (или Gateway API): один внешний балансировщик и маршрутизация по домену и пути, плюс терминация TLS.

Чем отличаются другие контроллеры

  • StatefulSet — для приложений с состоянием: стабильные имена подов (db-0, db-1), персональный том у каждой реплики, строгий порядок запуска и остановки.
  • DaemonSet — ровно по одному поду на каждой ноде: агенты логов, мониторинга, CNI.
  • Job / CronJob — разовые и периодические задачи, где под должен завершиться, а не работать вечно.

Типичные ошибки кандидатов

  • Говорят «Deployment создаёт поды», не упоминая ReplicaSet — и потом не могут объяснить механику rolling update.
  • Считают, что Service связан с Deployment. Связь идёт только по меткам, поэтому опечатка в labels даёт сервис без единого endpoint — классический баг «503 при живых подах».
  • Путают port и targetPort.
  • Кладут в один Pod фронтенд и бэкенд «чтобы было проще».
  • Выставляют наружу десяток LoadBalancer вместо одного Ingress — дорого и неудобно.

Как ответить кратко (20–30 секунд)

«Pod — минимальная единица планирования, один или несколько контейнеров с общими сетью и томами; он эфемерен и своего постоянного IP не имеет. Deployment — контроллер, который через ReplicaSet поддерживает заданное число реплик и умеет катить новые версии: удалённый под он пересоздаст, а созданный вручную под восстанавливать некому. Service даёт стабильный DNS-адрес и балансирует трафик между подами, отбирая их по меткам — поэтому несовпадение labels и selector даёт сервис без endpoints. Наружу HTTP выставляю через Ingress, а не через LoadBalancer на каждый сервис.»

Проверьте себя
1. Что произойдёт, если удалить Pod, принадлежащий Deployment с replicas: 3?
AНичего, приложение будет работать на двух репликах до ручного вмешательства
BReplicaSet обнаружит расхождение с желаемым состоянием и создаст новый Pod
CDeployment перейдёт в состояние Failed
DУдалится весь Deployment целиком
2. Service создан, поды работают, но запросы возвращают 503 и kubectl get endpoints показывает пустой список. Наиболее вероятная причина?
AНе хватает CPU на нодах
BСелектор Service не совпадает с метками подов
CНе указан тип LoadBalancer
DПоды запущены в другом namespace от того же Deployment
3. Какой контроллер выбрать, чтобы агент сбора логов работал ровно по одному экземпляру на каждой ноде кластера?
ADeployment с replicas равным числу нод
BStatefulSet
CDaemonSet
DCronJob