У тебя есть compose.yaml. Один сервер. Ты делаешь
Код: Выделить всё
docker compose up -dА потом приходит реальность. Сервер уходит в перезагрузку посреди ночи - и весь твой прод лежит, пока ты не проснешься. Трафик вырос вдвое - и ты упираешься в потолок CPU одной коробки, а вертикально расти уже некуда или дорого. Тебе нужно выкатить новую версию без даунтайма - а
Код: Выделить всё
docker compose upВот тут и начинается тема docker оркестрации. Это не про новую модную игрушку - это про то, что Compose сознательно решает другую задачу, и в какой-то момент ты вырастаешь из его границ. Давай разберем честно: где проходит граница, что именно Compose не умеет, и какой инструмент берут вместо него - Docker Swarm, Kubernetes или Nomad. И главное - как понять, что тебе вообще пора.

Что Compose решает, а что нет
Compose - это инструмент описания и запуска многоконтейнерного приложения на одном Docker-хосте. Он читает compose.yaml, создает сеть, тома, поднимает контейнеры в нужном порядке (через depends_on и healthcheck), связывает их по именам сервисов через встроенный DNS. В этом он великолепен. Но вся его модель мира заканчивается на границе одной машины.
Разберем по пунктам, что compose в проде не закрывает:
- Отказоустойчивость узла. Упал сервер - упало все. Compose не знает про другие машины, ему некуда переехать. Нет понятия "запасной узел".
- Авто-восстановление сервиса. Тут нюанс: перезапустит контейнер, если процесс внутри умер или хост перезагрузился. Но это тупой рестарт на том же месте. Если упала вся машина целиком - перезапускать некому. И если контейнер "жив, но не отвечает" (завис, healthcheck красный) - сам по себе restart-policy его не пересоздаст, он реагирует на код выхода процесса, а не на здоровье.
Код: Выделить всё
restart: always - Балансировка по узлам. Распределить десять реплик сервиса по трем серверам так, чтобы нагрузка размазалась - Compose этого не делает в принципе. Все реплики живут на одном хосте.
- Горизонтальное docker масштабирование под нагрузку. Да, есть . Но это четыре копии на одной машине, без авто-скейла по метрикам, без переноса на свободные узлы.
Код: Выделить всё
docker compose up --scale api=4 - Rolling-апдейты на кластере. Выкатить новую версию по одной реплике, проверяя healthcheck, и откатиться при сбое - Compose так не умеет. Он гасит и поднимает, точка.
Когда Compose плюс один сервер - это правильный выбор
Сразу убьем вредный миф: "раз есть Kubernetes, Compose в проде - это несерьезно". Чушь. Огромное количество живых продакшенов годами крутятся на Compose и одном-двух серверах, и это осознанное инженерное решение, а не бедность. Более того, по опросам последних лет доля Compose-развертываний среди практикующих разработчиков даже подрастает - люди, которые шипят продукт, а не пилят платформу, не хотят платить налог сложности кубера.
Compose плюс один (или вертикально мощный) сервер - твой выбор, когда:
- Проект небольшой: один-два сервиса, предсказуемая нагрузка, нет пиков в десятки раз.
- Допустим короткий даунтайм. Если падение на 5-10 минут раз в полгода не стоит тебе контракта - не плати за отказоустойчивость кластера.
- dev и staging-окружения - тут Compose почти всегда оптимален, его и не надо ничем заменять.
- Команда маленькая и без выделенного DevOps. Кубер требует, чтобы кто-то его кормил и лечил.
Код: Выделить всё
restart: unless-stoppedТри варианта: Swarm, Kubernetes, Nomad
Когда одного хоста перестает хватать, выбор по сути из трех. Разберем спор docker swarm vs kubernetes и третьего тихого игрока - Nomad.
Docker Swarm - оркестратор, встроенный прямо в Docker Engine. Включается одной командой
Код: Выделить всё
docker swarm initКод: Выделить всё
docker stack deployKubernetes (k8s) - индустриальный стандарт, держит порядка 90% рынка оркестрации. Это не "запускалка контейнеров", а целая платформа: декларативные манифесты, авто-скейл по метрикам (HPA), self-healing, rolling/canary-апдейты, богатейшая экосистема (Helm, операторы, service mesh, Ingress-контроллеры). Цена - сложность. У тебя появляются Pod, Deployment, Service, Ingress, ConfigMap, namespace и десятки других сущностей, control plane, etcd, который надо беречь. Кубер окупается на масштабе, в мульти-облаке, при сотнях сервисов и командах, которым нужна стандартизация. На трех контейнерах это из пушки по воробьям. Кстати, важная деталь 2026 года: сам Kubernetes давно не использует Docker как рантайм - он выкинул прослойку dockershim еще в версии 1.24 и работает напрямую с containerd или CRI-O через интерфейс CRI. Так что "Docker против Kubernetes" - ложная дихотомия: ты собираешь OCI-образ Docker'ом, а запускает его в кластере containerd. Они на разных слоях.
HashiCorp Nomad - легковесный планировщик, который умеет оркестрировать не только контейнеры, но и обычные бинарники, Java-приложения, QEMU-вм. Один компактный бинарь, проще кубера, отлично дружит с Consul и Vault. Ниша - там, где нужен оркестратор, но кубер избыточен, и где в зоопарке не только контейнеры. Сообщество меньше, чем у k8s, но инструмент зрелый.
Грубое правило: Swarm - "мне нужен кластер, но без боли"; Kubernetes - "мне нужен стандарт, масштаб и экосистема, я готов платить сложностью"; Nomad - "мне нужно просто и не только про контейнеры".
Практика: Compose к Swarm и Compose к Kubernetes
Главная ценность твоего compose.yaml - он не выбрасывается при переезде. Покажу оба пути.
Путь 1: Compose к Swarm через секцию deploy. Swarm читает тот же файл, но активирует в нем секцию
Код: Выделить всё
deployКод: Выделить всё
docker composeКод: Выделить всё
services:
api:
image: registry.example.ru/myapp:1.4.2
ports:
- "8080:8080"
deploy:
replicas: 4
update_config:
parallelism: 1
delay: 10s
order: start-first
failure_action: rollback
restart_policy:
condition: on-failure
placement:
constraints:
- node.role == worker
Код: Выделить всё
replicas: 4Код: Выделить всё
parallelism: 1Код: Выделить всё
delay: 10sКод: Выделить всё
order: start-firstКод: Выделить всё
failure_action: rollbackКод: Выделить всё
docker swarm init
docker stack deploy -c compose.yaml myapp
docker stack services myapp
Код: Выделить всё
ID NAME MODE REPLICAS IMAGE PORTS
k3p9x2f1abcd myapp_api replicated 4/4 registry.example.ru/myapp:1.4.2 *:8080->8080/tcp
Код: Выделить всё
4/4Код: Выделить всё
3/4Путь 2: Compose к Kubernetes через kompose. Здесь нельзя просто скормить compose.yaml кластеру - нужны манифесты k8s. Утилита
Код: Выделить всё
komposeКод: Выделить всё
kompose convert -f compose.yaml -o k8s/
Код: Выделить всё
build:Грабли и антипаттерны
- Тащить Kubernetes на три контейнера. Самая частая и дорогая ошибка. Ты платишь сложностью каждый день, а выгоду масштаба не получаешь. Сначала вырасти из Compose по реальным причинам, потом выбирай.
- Думать, что restart: always - это и есть отказоустойчивость. Нет. Это перезапуск процесса на том же хосте. Упала машина - перезапускать некому. Настоящая отказоустойчивость живет только на уровне кластера из нескольких узлов.
- Считать, что compose.yaml = манифесты k8s. Для Swarm файл переиспользуется почти целиком. Для Kubernetes - это совсем другая модель сущностей, kompose лишь стартовая точка.
- Игнорировать stateful-данные при переезде. Базу данных в кластер тащить опаснее всего: тома, привязка к узлу, бэкапы, репликация - отдельная большая тема. Часто БД оставляют как managed-сервис или на выделенной машине, а в кластер выносят stateless-сервисы.
- Забыть про реестр образов. В кластере каждый узел сам тянет образ. Локальной сборки мало - образ должен лежать в доступном всем узлам registry. В RU-реалиях, когда Docker Hub бывает капризен, держи приватный реестр или зеркало (Yandex Container Registry, VK Cloud, Harbor у себя).
Все делается на одной машине с установленным Docker, кластер из одного узла - этого хватит, чтобы увидеть разницу.
- Возьми любой свой compose.yaml с одним web-сервисом. Подними обычным , проверь
Код: Выделить всё
docker compose up -d. Это твоя точка отсчета.Код: Выделить всё
docker compose ps - Добавь в сервис секцию с
Код: Выделить всё
deployиКод: Выделить всё
replicas: 3как в примере выше.Код: Выделить всё
update_config - Выполни , затем
Код: Выделить всё
docker swarm init. ПосмотриКод: Выделить всё
docker stack deploy -c compose.yaml lab- убедись, что REPLICAS показывает 3/3.Код: Выделить всё
docker stack services lab - Грохни один контейнер реплики: . Через пару секунд снова глянь
Код: Выделить всё
docker rm -f <id>- Swarm пересоздал убитую реплику сам. Вот оно, желаемое состояние в действии, чего Compose не делает.Код: Выделить всё
docker stack services lab - Поменяй тег образа на новый и снова - понаблюдай через
Код: Выделить всё
docker stack deploy, как реплики обновляются по одной (rolling).Код: Выделить всё
docker service ps lab_web - Бонус: поставь и сделай
Код: Выделить всё
kompose. Открой сгенерированные файлы и найди глазами, чего там не хватает для прода - проб, лимитов, секретов.Код: Выделить всё
kompose convert -f compose.yaml -o k8s/ - Прибери за собой: и
Код: Выделить всё
docker stack rm lab.Код: Выделить всё
docker swarm leave --force
- Назови минимум три вещи, которые Compose на одном хосте принципиально не решает, и объясни почему - в чем ограничение его модели.
- Чем отличается от настоящей отказоустойчивости на уровне кластера? В каком случае он бесполезен?
Код: Выделить всё
restart: always - Почему compose.yaml почти без правок едет в Swarm, но требует конвертации для Kubernetes? Что именно делает kompose и где его предел?
- Сформулируй критерии, по которым ты в реальном проекте выберешь Swarm, Kubernetes или останешься на Compose плюс один сервер.
Compose - чемпион одного хоста, и для dev, staging и небольшого прода он часто оптимален; не меняй его без реальной причины. Граница наступает, когда тебе нужны отказоустойчивость узлов, авто-восстановление в масштабах кластера, балансировка по машинам и rolling без даунтайма - этого один хост не дает. Тогда выбираешь: Swarm как дешевый по сложности шаг (тот же compose.yaml плюс deploy), Kubernetes как индустриальный стандарт ценой сложности, Nomad как легковесную середину. И помни: Docker и Kubernetes - не конкуренты, а соседние слои; образ ты по-прежнему собираешь Docker'ом, а в кластере его крутит containerd. В следующем большом блоке мы пойдем вглубь именно в Kubernetes - разберем Pod, Deployment, Service и то, как все это удерживает твое желаемое состояние.