Запустить один контейнер через podman run или docker run вы уже умеете. Но реальная задача администратора другая: поднять десяток связанных сервисов (приложение, база, кеш, очередь), дать им общую сеть, постоянное хранилище, настроить рестарт при падении, а потом размазать это по нескольким хостам так, чтобы выживала смерть узла. Этим занимается оркестратор. В этом уроке разберём четыре уровня: Docker Compose для одного хоста, Docker Swarm для небольшого кластера, Kubernetes для большого, и Helm как пакетный менеджер поверх Kubernetes. Главная мысль урока - понимать, какой инструмент под какую задачу, а не тащить Kubernetes туда, где хватает compose-файла.

Как это работает
Оркестрация - это переход от императива к декларативу. Вы не пишете последовательность команд "создай сеть, запусти базу, дождись её, запусти приложение". Вы описываете желаемое состояние в YAML, а оркестратор сам приводит систему к нему и удерживает в нём. Это и есть reconciliation loop: процесс постоянно сравнивает "что есть" с "что должно быть" и устраняет разницу.
Docker Compose - самый простой уровень. Это один хост и один файл compose.yaml. Compose читает описание сервисов и за вас создаёт сеть, тома и контейнеры в правильном порядке. По спецификации Compose (актуальная редакция 2026 года) ключ version в начале файла больше не нужен и считается устаревшим. Compose не даёт отказоустойчивости между машинами - умер хост, умерло всё. Это инструмент разработки и небольших одиночных прод-серверов.
Docker Swarm - встроенный в Docker Engine кластерный режим. Несколько узлов объединяются в swarm: менеджеры держат состояние через распределённый Raft-лог, воркеры крутят задачи. Вы запускаете не контейнер, а сервис с желаемым числом реплик, и Swarm раскидывает их по узлам, перезапускает при падении и балансирует через встроенный routing mesh. Порог входа низкий, синтаксис тот же стек compose-файлов. Но проект давно в режиме поддержки без активного развития.
Kubernetes (k8s) - индустриальный стандарт. Минимальная единица запуска - под (pod), один или несколько контейнеров с общим сетевым namespace и томами. Подами вы напрямую не управляете: их создаёт Deployment, который держит нужное число реплик через ReplicaSet и умеет катить обновления без простоя. Доступ к подам даёт Service - стабильный виртуальный IP и DNS-имя поверх меняющихся подов. Namespace - логическая изоляция объектов внутри кластера (dev, prod, команды) с квотами и правами. За всем этим стоит API-сервер, etcd как хранилище состояния и контроллеры, крутящие тот самый reconciliation loop.
Helm - пакетный менеджер Kubernetes. Чарт - это параметризованный набор шаблонов манифестов плюс values.yaml со значениями по умолчанию. Helm рендерит шаблоны и ставит результат как единый release, который можно обновлять и откатывать. Helm 4 (ноябрь 2025) перешёл на server-side apply и новую систему плагинов, при этом чарты Helm 3 работают без переделки.
Команды и примеры
Минимальный compose.yaml с приложением, базой, сетью и томом:
Код: Выделить всё
services:
web:
image: nginx:1.27
ports:
- "8080:80"
networks: [front]
depends_on:
db:
condition: service_healthy
db:
image: postgres:17
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks: [front]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
retries: 5
volumes:
pgdata:
networks:
front:
Код: Выделить всё
docker compose up -d
docker compose ps
docker compose logs -f web
docker compose down -v # -v удалит и тома
Docker Swarm - кластер из узлов и сервис с репликами:
Код: Выделить всё
docker swarm init --advertise-addr 192.168.10.5
docker swarm join-token worker # покажет команду для воркеров
docker node ls
docker service create --name web --replicas 3 -p 80:80 nginx:1.27
docker service scale web=5
docker stack deploy -c compose.yaml app # деплой целого стека
Код: Выделить всё
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: shop
spec:
replicas: 3
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: nginx:1.27
ports: [ { containerPort: 80 } ]
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: shop
spec:
selector: { app: web }
ports:
- port: 80
targetPort: 80
Код: Выделить всё
kubectl create namespace shop
kubectl apply -f web.yaml
kubectl get pods -n shop -o wide
kubectl scale deployment web --replicas=5 -n shop
kubectl rollout status deployment/web -n shop
kubectl rollout undo deployment/web -n shop # откат версии
Код: Выделить всё
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install shop bitnami/nginx -n shop --create-namespace \
--set replicaCount=3
helm upgrade shop bitnami/nginx -n shop --set replicaCount=5
helm rollback shop 1 -n shop
helm list -n shop
Частые грабли
- depends_on в Compose без condition ждёт только запуска контейнера, а не готовности сервиса. База ещё инициализируется, а приложение уже ломится к ней. Нужен healthcheck плюс service_healthy.
- down -v молча сносит именованные тома вместе с данными. На проде про флаг -v надо помнить отдельно.
- В Swarm ключи build, depends_on и profiles из compose-файла игнорируются - stack deploy умеет не всё, что docker compose up.
- Чётное число менеджеров в Swarm не повышает отказоустойчивость Raft, а иногда вредит кворуму. Держите 3 или 5 менеджеров, не 2 и не 4.
- Service в Kubernetes не видит поды, если labels в селекторе не совпали с labels в шаблоне пода буква в букву. Трафик молча уходит в никуда.
- latest как тег образа - источник невоспроизводимых деплоев. В манифестах и чартах всегда фиксируйте версию.
- helm install при упавшем релизе оставляет его в статусе failed, и повторная установка спотыкается. Чистите helm uninstall или используйте upgrade --install.
- На одном хосте напишите compose.yaml из примера, поднимите docker compose up -d, убедитесь через docker compose ps, что web стартовал только после healthy базы.
- Проверьте сохранность данных: создайте таблицу в postgres, сделайте docker compose down без -v, поднимите заново и убедитесь, что данные на месте.
- Инициализируйте Swarm на этом же хосте (swarm init), сконвертируйте стек через docker stack deploy и масштабируйте web до 4 реплик.
- Поднимите учебный кластер Kubernetes: kind или minikube. Примените Deployment и Service из урока в namespace shop.
- Сломайте под намеренно (kubectl delete pod) и понаблюдайте kubectl get pods -w, как Deployment поднимает замену.
- Установите тот же nginx через Helm, переопределив replicaCount, затем сделайте upgrade и rollback, сверяя helm history.
- Чем под Kubernetes отличается от контейнера и зачем в одном поде держать несколько контейнеров?
- Какая цепочка объектов обеспечивает заданное число реплик и плавное обновление: Deployment, ReplicaSet, под - кто кого создаёт?
- Как Service находит свои поды и что произойдёт при несовпадении labels селектора?
- Почему рекомендуют нечётное число узлов-менеджеров в Swarm и как это связано с Raft?
- Что именно делает Helm с чартом при install и чем release отличается от чарта?
- В каких сценариях Docker Compose достаточно, а где обоснован переход на Kubernetes?