← назад к разделу

Backend-разработчику не нужно администрировать Kubernetes — но нужно понимать среду, в которой живёт его сервис. Probes, ресурсы, graceful shutdown, «почему под перезапустился ночью» — всё это вопросы к разработчику, а не к платформенной команде. Эта статья — минимальная модель Kubernetes, достаточная, чтобы остальные статьи раздела (и инциденты на проде) читались осознанно.

Идея: желаемое состояние

Kubernetes — это цикл сверки (reconciliation loop): вы декларируете желаемое состояние («три реплики этого образа, столько-то памяти, наружу порт 8080»), кластер непрерывно сравнивает его с фактическим и устраняет расхождение. Под упал — будет создан новый. Нода умерла — поды переедут на живые. Вы описываете «что», Kubernetes решает «как» — в этом отличие от императивных скриптов деплоя «зайди по ssh и перезапусти».

Из этой идеи следует главное культурное правило: состояние кластера меняют правкой деклараций, не руками. kubectl edit на проде — то же самое, что hotfix правкой класса в работающем Tomcat.

Pod: единица исполнения

Pod — не «контейнер», а группа контейнеров с общей сетью и диском, неделимая единица планирования. В 90% случаев в поде один контейнер — ваше приложение; остальные 10% — sidecar-ы (прокси service mesh, агент логов).

Два свойства пода определяют всё остальное:

  • Pod смертен и одноразов. Его не «лечат» — его убивают и создают новый. Никакого состояния внутри пода: файлы исчезнут, IP сменится. Всё долгоживущее — в БД, S3, внешних кешах.
  • У пода есть IP, но полагаться на него нельзя — он живёт ровно столько, сколько под. Отсюда необходимость Service (ниже).

Deployment: реплики и обновления

Напрямую поды почти никогда не создают. Deployment декларирует «N реплик такого-то шаблона пода» и управляет их жизнью через ReplicaSet:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 3
  selector:
    matchLabels: { app: order-service }
  template:
    metadata:
      labels: { app: order-service }
    spec:
      containers:
        - name: app
          image: registry.local/order-service:1.42.0
          ports:
            - containerPort: 8080
          resources:
            requests: { cpu: "500m", memory: "768Mi" }
            limits: { memory: "768Mi" }

Deployment даёт три вещи: самовосстановление (упавшая реплика пересоздаётся), масштабирование (replicas: 5 — и через секунды их пять) и rolling update — смена образа порциями без остановки сервиса (механика — в статье про деплой).

Связующий механизм всего Kubernetes — labels и selectors: Deployment находит «свои» поды не по именам, а по меткам (app: order-service). Тот же принцип использует Service.

Service: стабильный адрес над смертными подами

Поды приходят и уходят, их IP меняются. Service — постоянное имя и виртуальный IP, за которым живёт актуальный список подходящих под selector подов (endpoints):

apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector: { app: order-service }
  ports:
    - port: 80
      targetPort: 8080

Теперь любой сервис кластера зовёт http://order-service (внутри namespace) — и попадает на одну из живых реплик. Балансировка примитивная (по соединениям), но для межсервисного HTTP её хватает. Важная деталь, которая свяжется с probes: под попадает в endpoints только когда его readiness probe зелёная — так Kubernetes не шлёт трафик на ещё не прогретое приложение.

Путь запроса снаружи

Полная цепочка, по которой пользовательский запрос доходит до вашего кода:

Internet → LoadBalancer → Ingress controller → Service → endpoints → Pod:8080

Ingress — декларация маршрутизации «host/path → такой-то Service» плюс TLS; исполняет её Ingress-контроллер (nginx, traefik). Подробно сеть разобрана отдельной статьёй — для начала достаточно держать в голове эту цепочку: при «сервис не отвечает» проверяется каждое её звено.

Namespace и kubectl

Namespace — папка для объектов: payments-prod, payments-staging. Изоляция административная (права, квоты), не сетевая (сетевую дают NetworkPolicy). Минимальный набор команд разработчика:

kubectl -n payments-prod get pods
kubectl -n payments-prod describe pod order-service-7d4b9c-x2x4v
kubectl -n payments-prod logs deploy/order-service --tail=200
kubectl -n payments-prod port-forward svc/order-service 8080:80

Этого хватает для 80% задач; полный разбор отладки — в эксплуатации.

Чего Kubernetes не делает

  • Не чинит приложение. Перезапуск CrashLoop-пода бесконечен, но причина — в вашем коде или конфиге.
  • Не делает сервис отказоустойчивым сам по себе. Ретраи, таймауты, circuit breaker — по-прежнему ваша работа; k8s лишь заменяет упавшие реплики.
  • Не управляет данными. БД в k8s — отдельная дисциплина (StatefulSet, операторы), и для большинства команд managed-БД вне кластера проще.
  • Не отменяет понимание JVM. Память, GC и ресурсы контейнера взаимодействуют нетривиально — разбор.

Словарь объектов

ОбъектЧто декларируетАналогия
PodГруппа контейнеров, единица исполненияПроцесс
DeploymentN реплик пода + стратегия обновленияsystemd-юнит с автоперезапуском, на N машин
ServiceСтабильное имя над живыми подамиВнутренний балансировщик + DNS-запись
IngressМаршрутизация снаружи: host/path → Servicenginx-конфиг как объект кластера
ConfigMap / SecretКонфигурация / секреты отдельно от образаapplication.yml, вынесенный из jar
NamespaceГруппа объектов с правами и квотамиПапка / проект
HPAАвто-масштабирование по метрикам«replicas: auto»

Что почитать дальше

  • Spring Boot в Kubernetes — probes, ресурсы и JVM, graceful shutdown: то, за что отвечает именно разработчик.
  • Сеть и трафик — Service-типы, DNS, Ingress и Gateway API подробно.
  • Деплой и конфигурация — манифесты, Helm, rolling update.
  • Эксплуатация и отладка — kubectl-набор и типичные инциденты.