Урок 03 · Kubernetes на практике

Pod и Deployment

Что-то не запустилось или осталось непонятным? Задайте вопрос в комментариях к разбору этого урока в канале — разберёмся вместе.

У вас уже есть образ hello-fastapi:0.1 из урока 1 и живой кластер из урока 2. Пора соединить их вместе — но не командой docker run, а декларативно, как это делает Kubernetes. Для этого понадобятся два новых объекта: Pod, самая маленькая единица запуска, и Deployment, который этими Pod'ами управляет и не даёт им бесследно исчезать.

Pod — не то же самое, что контейнер

Pod — минимальная единица, которую вообще можно запустить в Kubernetes. Формально он может объединять несколько контейнеров с общей сетью и диском, но на практике в 90% случаев внутри Pod'а — один контейнер. Тогда зачем вообще эта обёртка, если можно было просто запускать контейнеры?

  • Pod эфемерен по своей природе. Kubernetes не «чинит» упавший Pod — он его выбрасывает и создаёт новый, с новым именем и новым IP. Это осознанный контракт, а не баг.
  • Голый Pod, созданный вручную, никто не пересоздаст. Уроните узел, на котором он жил, — и Pod просто исчезнет вместе с ним. Никто не заметит и не восстановит.
  • Именно поэтому Pod'ы почти никогда не создают напрямую — их создаёт объект уровнем выше, который следит, чтобы нужное количество Pod'ов существовало всегда.

Deployment и ReplicaSet: кто на самом деле следит за Pod'ами

Deployment — это декларация желаемого состояния: «я хочу, чтобы работало N копий вот такого контейнера». Сам Deployment Pod'ами не занимается — он создаёт под собой ReplicaSet, а уже ReplicaSet непрерывно сверяет факт с желаемым числом и досоздаёт Pod'ы, если их стало меньше.

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

Схема: Deployment описывает желаемое состояние, ReplicaSet поддерживает нужное число Pod'ов, Pod'ы — это реально работающие контейнеры МАНИФЕСТ Deployment replicas: 2 желаемое состояние создаёт КОНТРОЛЁР ReplicaSet текущих: 2/2 сверяет и чинит разницу держит POD × 2 Ваш контейнер hello-fastapi #1 hello-fastapi #2 упадёт один — появится новый
Вы правите только Deployment. ReplicaSet и Pod'ы — это исполнительный слой, с которым вы работаете лишь для диагностики.
Источник Официальная документация — Kubernetes Docs: Pods и Kubernetes Docs: Deployments

Практика: задеплойте свой FastAPI-образ

Понадобится образ hello-fastapi:0.1, собранный в уроке 1, и кластер minikube из урока 2.

  1. Проверьте, что образ действительно есть локально:
    docker images | grep hello-fastapi
    Если пусто — вернитесь в папку с Dockerfile из урока 1 и соберите его: docker build -t hello-fastapi:0.1 .
  2. minikube по умолчанию не видит образы вашего локального Docker — у него свой собственный. Загрузите образ внутрь кластера явно:
    minikube image load hello-fastapi:0.1
    Это разовая операция для каждой новой версии образа — реальный registry (Docker Hub и подобные) появится в курсе позже и снимет это неудобство.
  3. Создайте файл deployment.yaml:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-fastapi
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: hello-fastapi
      template:
        metadata:
          labels:
            app: hello-fastapi
        spec:
          containers:
            - name: hello-fastapi
              image: hello-fastapi:0.1
              ports:
                - containerPort: 8000

    selector.matchLabels и template.metadata.labels должны совпадать буквально — этой парой ярлыков ReplicaSet находит «свои» Pod'ы среди всех остальных в кластере.

  4. Примените манифест:
    kubectl apply -f deployment.yaml
  5. Проверьте, что получилось на каждом уровне схемы выше:
    kubectl get deployments
    kubectl get pods
    В STATUS у Pod'ов должно быть Running, а в READY у Deployment — 2/2.
  6. Пробросьте порт одного из Pod'ов на свою машину и откройте знакомую страницу:
    kubectl port-forward deployment/hello-fastapi 8000:8000
    Откройте localhost:8000/docs — тот же интерфейс, что в уроке 1, но теперь за ним стоит кластер, а не одиночный docker run. Остановите проброс сочетанием Ctrl+C, когда закончите.
Проверьте самовосстановление Откройте вывод kubectl get pods, скопируйте имя любого Pod'а и удалите его:
kubectl delete pod <имя-pod>
Сразу выполните kubectl get pods ещё раз — вы увидите, что удалённый Pod пропал, но тут же появился новый с другим именем, а общее число снова стало равно 2. Это и есть работа ReplicaSet из схемы выше: он не спрашивает, почему Pod исчез, — просто восстанавливает заявленное число.
Лайфхак Даже если вам нужна ровно одна копия сервиса, не создавайте голый Pod — оберните его в Deployment с replicas: 1. Он почти ничего не стоит по ресурсам, зато при падении узла или самого Pod'а кластер восстановит его автоматически. Голый Pod в такой ситуации просто исчезнет навсегда.

Проверьте себя

Вы вручную удалили один из двух Pod'ов, созданных Deployment'ом. Что произойдёт дальше?

Напишите команду, которая применит манифест deployment.yaml к кластеру:

Напишите команду, которая покажет список Pod'ов и их статус: