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

Раньше сервис деплоили так: написали скрипт, зашли по ssh, остановили процесс, скопировали новый jar, запустили снова. Если нода упала — всё, сервис лежит, кто-то идёт чинить руками. Если нужно пять копий — пять раз делаешь одно и то же.

Kubernetes решает эту проблему иначе: вы описываете, что должно работать, а кластер сам решает как — и поддерживает это состояние непрерывно.

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

Kubernetes работает как постоянный наблюдатель. Вы говорите ему: «хочу три копии этого сервиса, каждой нужно 512 МБ памяти, наружу смотрит порт 8080». Kubernetes сравнивает это с тем, что есть на самом деле, и устраняет расхождения.

Упала одна копия — Kubernetes создаёт новую. Умерла целая нода — поды переезжают на живые машины. Вы ничего не делаете руками: кластер сам поддерживает нужную картину.

Из этого следует важное правило: состояние кластера меняют правкой деклараций, не ручными командами. Зайти и что-то поправить «по-быстрому» — это то же самое, что менять файл на работающем сервере в обход системы контроля версий.

Pod: один процесс (или несколько рядом)

Pod — это наименьшая единица в Kubernetes. В большинстве случаев под — это один контейнер с вашим приложением.

Два свойства пода важно понять с самого начала:

Под одноразовый. Его не лечат — его убивают и создают новый. Если приложение упало, Kubernetes не пытается его починить: он просто запускает свежий контейнер из образа. Из этого следует: никакого важного состояния внутри пода быть не должно. Файлы на диске исчезнут. IP-адрес сменится.

IP пода непостоянен. Пока под жив — у него есть адрес. Когда под пересоздаётся — адрес другой. Полагаться на него нельзя. Для постоянного адреса существует Service — об этом ниже.

Иногда в поде несколько контейнеров: например, ваше приложение плюс агент сбора логов. Они делят одну сеть и один диск. Это называется sidecar-паттерн, но новичку это редко нужно — в 90% случаев под = один контейнер.

Deployment: кто управляет подами

Поды вручную почти никогда не создают. Deployment — это декларация: «запусти N копий вот такого пода и поддерживай их в рабочем состоянии».

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 даёт три вещи:

  • Самовосстановление — упала реплика, Kubernetes создаёт новую.
  • Масштабирование — поменяли replicas: 3 на replicas: 5, через несколько секунд их пять.
  • Обновление без остановки — при смене образа Deployment заменяет поды порциями, не роняя сервис целиком.

Как Deployment находит свои поды? Не по именам — по меткам (labels). В примере выше все поды имеют метку app: order-service, а Deployment ищет именно их через selector.matchLabels. Этот же механизм используется в Service.

Service: постоянный адрес над сменяющимися подами

Поды приходят и уходят, их адреса меняются. Service — это стабильное имя и виртуальный IP, который всегда указывает на живые поды:

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

Теперь любой другой сервис в кластере обращается по имени http://order-service — и Kubernetes направит запрос на один из живых подов с меткой app: order-service.

Важная деталь: под попадает в список доступных адресов только тогда, когда его readiness probe возвращает успех. Если приложение ещё не прогрелось или временно недоступно — трафик на него не идёт. Как настроить probe — в следующей статье.

Как запрос из интернета добирается до пода

Полная цепочка выглядит так:

Интернет → LoadBalancer → Ingress-контроллер → Service → Pod

Ingress — это декларация маршрутизации: «запросы на api.example.com/orders отправляй в Service order-service». Плюс там же настраивается TLS. Выполняет эту декларацию Ingress-контроллер (например, nginx или traefik) — он уже реально слушает входящие запросы.

Когда что-то не работает, эту цепочку проверяют звено за звеном: LoadBalancer поднят? Ingress сконфигурирован правильно? Service видит поды? Поды отвечают на probe?

Namespace: разделяем окружения

Namespace — это папка для объектов кластера. Обычно делают отдельные namespace для каждого окружения: payments-prod, payments-staging.

Изоляция в namespace административная: права доступа, квоты на ресурсы. Сетевой изоляции namespace не даёт — сервисы из разных namespace могут общаться, если явно не запрещено через 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

Первая — посмотреть, что запущено. Вторая — разобраться, почему под не стартует или лежит. Третья — прочитать логи. Четвёртая — временно пробросить порт к себе, чтобы проверить работу сервиса локально.

Что Kubernetes не делает за вас

Kubernetes заменяет упавшие поды — но не чинит код внутри. Если приложение падает из-за бага, Kubernetes будет бесконечно перезапускать под (это называется CrashLoopBackOff) — но причину надо искать в логах и фиксить самостоятельно.

Kubernetes не делает сервис отказоустойчивым сам по себе. Повторные попытки, таймауты, автоматическое отключение неработающего соседа — это по-прежнему задача разработчика. Kubernetes лишь следит, чтобы нужное количество подов было живо.

База данных в Kubernetes — отдельная, сложная тема (StatefulSet, операторы). Большинству команд проще держать управляемую БД вне кластера.

Шпаргалка по объектам

ОбъектЧто делает
PodЗапускает один или несколько контейнеров вместе
DeploymentСледит, чтобы нужное число подов всегда работало
ServiceПостоянное имя и адрес над меняющимися подами
IngressМаршрутизация внешнего трафика к нужному Service
ConfigMap / SecretКонфигурация и секреты отдельно от образа
NamespaceГруппа объектов с правами и квотами

Коротко

  • Kubernetes поддерживает желаемое состояние: вы декларируете, он выполняет и восстанавливает при сбоях.
  • Pod — одноразовая единица. Его не лечат, а пересоздают. Никакого важного состояния внутри.
  • Deployment управляет N копиями пода, даёт самовосстановление, масштабирование и обновление без остановки.
  • Labels — механизм связи: Deployment находит свои поды по меткам, Service — тоже.
  • Service — постоянный адрес над живыми подами. Трафик идёт только на поды с зелёной readiness probe.
  • Ingress маршрутизирует внешний трафик к нужному Service.
  • Namespace разделяет окружения административно, не сетево.
  • Kubernetes заменяет упавшие поды, но не чинит код и не делает сервис отказоустойчивым сам по себе.

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

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