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).