← Back to notes

Pod


Pod — минимальная развёртываемая единица в Kubernetes. Kubernetes управляет Pod, а не контейнерами напрямую. Pod — обёртка вокруг одного или нескольких контейнеров с общим сетевым namespace и возможностью разделять volumes.

[source: kubernetes.io/docs/concepts/workloads/pods/]

Single-container и multi-container Pod

Один контейнер в Pod — соотношение 1:1, типичный случай. Несколько контейнеров — когда они тесно связаны и разделяют ресурсы: паттерн sidecar (основной контейнер + вспомогательный для логирования, проксирования или синхронизации данных).

Общие ресурсы внутри Pod

Сеть: все контейнеры в Pod разделяют один сетевой namespace — обращаются друг к другу через localhost. Каждый Pod получает уникальный IP в кластере.

Хранилище: контейнеры могут монтировать общие Volume. Данные в Volume переживают перезапуск контейнера (но не удаление Pod, если Volume типа emptyDir).

Жизненный цикл Pod

[source: kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/]

Pod — эфемерная сущность. При падении Pod не восстанавливается сам. За пересоздание отвечают контроллеры: Deployment, StatefulSet, DaemonSet.

Манифест Pod

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
    environment: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.27
      ports:
        - containerPort: 80
      resources:
        requests:
          cpu: 100m
          memory: 128Mi
        limits:
          cpu: 250m
          memory: 256Mi

Основные команды kubectl для Pod

# Создать Pod императивно
kubectl run nginx --image=nginx:1.27

# Создать из манифеста
kubectl apply -f pod.yaml

# Список Pod
kubectl get pods
kubectl get pods -o wide          # IP, узел, статус
kubectl get pods --show-labels

# Подробности и события
kubectl describe pod nginx-pod

# Логи
kubectl logs nginx-pod
kubectl logs nginx-pod -c sidecar  # конкретный контейнер
kubectl logs nginx-pod -f          # follow

# Выполнение команды внутри контейнера
kubectl exec -ti nginx-pod -- /bin/sh

# Проброс порта на локальную машину
kubectl port-forward nginx-pod 8080:80

# Удаление
kubectl delete pod nginx-pod
kubectl delete -f pod.yaml

Init Containers

Init-контейнеры запускаются до основных контейнеров Pod. Выполняются последовательно — каждый следующий стартует только после успешного завершения предыдущего.

[source: kubernetes.io/docs/concepts/workloads/pods/init-containers/]

Когда использовать:

  • Ожидание готовности внешнего сервиса (БД, API) перед стартом приложения
  • Предварительная подготовка данных или миграции схемы
  • Настройка конфигурационных файлов перед запуском
apiVersion: v1
kind: Pod
metadata:
  name: app-with-init
spec:
  initContainers:
    - name: wait-for-db
      image: busybox:1.36
      command:
        - sh
        - -c
        - |
          until nc -z postgres-service 5432; do
            echo "Waiting for database..."
            sleep 2
          done
    - name: run-migrations
      image: myapp:1.0
      command: ["./migrate", "--up"]
  containers:
    - name: app
      image: myapp:1.0
      ports:
        - containerPort: 8080

Особенности init-контейнеров:

  • Не поддерживают readinessProbe (не принимают трафик)
  • Завершаются до конца — не работают постоянно
  • Если init-контейнер падает, Pod перезапускает его согласно restartPolicy
  • Ресурсы: берётся максимум из всех init-контейнеров (не сумма), плюс ресурсы основных контейнеров

Sidecar Containers (нативные)

KEP-753: alpha 1.28, beta 1.29 (включён по умолчанию), GA 1.33. Init-контейнер с restartPolicy: Always становится sidecar-контейнером: стартует до основных, но живёт всё время жизни Pod.

[source: kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/]

Сравнение типов контейнеров

Пример: Fluent Bit как sidecar

apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  initContainers:
    - name: log-collector
      image: fluent/fluent-bit:3.0
      restartPolicy: Always          # делает этот init-контейнер sidecar
      readinessProbe:
        httpGet:
          path: /api/v1/health
          port: 2020
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
  containers:
    - name: app
      image: myapp:v1
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
  volumes:
    - name: logs
      emptyDir: {}

Порядок lifecycle

  • Запуск: обычные init → sidecar (запускается и остаётся жить) → основные контейнеры
  • Завершение: основные контейнеры останавливаются первыми → sidecar завершается последним

До 1.29 logging agent (Fluent Bit, Filebeat) запускали как обычный контейнер, что создавало гонку при завершении Pod — sidecar мог упасть до того, как основной контейнер успел записать последние логи. Нативные sidecar решают эту проблему.

Типичные ошибки

Запуск Pod без контроллера в production. Pod не поднимается сам при падении узла или перезапуске. Всегда используй Deployment, StatefulSet или DaemonSet.

Образ без явного тега или с latest. Один и тот же манифест может запустить разные версии в разное время. Указывай конкретный тег или digest: nginx:1.27 или nginx@sha256:....

Один большой контейнер вместо нескольких специализированных. Соединять несвязанные задачи в одном образе — сложнее обновлять, больше поверхность атаки.

Не задавать resources.requests и resources.limits. Без requests scheduler не может правильно разместить Pod. Без limits один Pod может монополизировать ресурсы узла. Подробно — в главе 13.

Ожидать, что данные переживут удаление Pod без volume. Файловая система контейнера эфемерна. Всё, что нужно сохранить между перезапусками, должно лежать в volume.

Альтернативы

Deployment — для stateless приложений, нужны реплики и rolling update (глава 05).

StatefulSet — для stateful приложений, где важна стабильная идентичность Pod (глава 11).

Job — для разовых задач (глава 12).

CronJob — для задач по расписанию (глава 12).


01: Архитектура кластера

03: Labels, Selectors, Annotations

Pod | Aleksandr Suprun