Из Docker Compose в Kubernetes: когда это оправдано
Если стек уже год-два крутится в docker-compose на одном сервере и всё работает — переход на Kubernetes выглядит как решение проблемы, которой пока нет. Но иногда проблема уже есть, просто она не называется «нам нужен Kubernetes», она называется «сайт лёг в пятницу вечером и поднялся только когда кто-то зашёл руками» или «мы третий месяц не можем добавить мощность под пиковую нагрузку без простоя». Разберём три конкретных признака, что compose реально стал тесен, и дадим пошаговый план миграции — без разового скачка через пропасть.
Содержание
- Три признака, что docker-compose реально стал тесен
- Когда compose ещё справляется — честно
- Шаг 0: готово ли само приложение к горизонтальному масштабированию
- Managed Kubernetes или свой control plane
- Поэтапный план миграции: не весь стек одним прыжком
- Что реально меняется в эксплуатации — и это не бесплатно
Три признака, что docker-compose реально стал тесен
Признаков «не хватает Kubernetes» на самом деле немного, и они конкретные — не «все так делают» и не «это современно».
1. Нужно горизонтальное масштабирование под переменную нагрузку, а сервер физически упёрся в потолок. Docker Compose управляет контейнерами на одном хосте. Если нагрузка выросла — вы вертикально апгрейдите сервер (больше CPU/RAM) или добавляете реплики контейнера на том же хосте через deploy.replicas в compose-файле (это работает только в режиме docker stack deploy, а не с обычным docker compose up, и всё равно ограничено ресурсами одной машины). Когда один сервер, даже самый мощный из доступных у провайдера, не тянет пиковую нагрузку — единственный выход это несколько физических серверов, между которыми нужно распределять контейнеры динамически. Это ровно то, что compose не делает и не должен делать: он про один хост.
2. Нужна автоматическая отказоустойчивость на уровне нескольких серверов, а не просто перезапуск контейнера. У restart: always в compose ограниченная зона ответственности: он перезапускает упавший контейнер на том же сервере. Он ничего не делает, если упал сам сервер — контейнер просто останется недоступен, пока кто-то не заметит и не поднимет всё руками на другой машине. Если ваш SLA требует, чтобы падение узла лечилось само — Kubernetes решает это через Deployment/ReplicaSet: control plane видит, что узел перестал отвечать (по умолчанию узел помечается NotReady примерно через 40 секунд отсутствия heartbeat, это управляется --node-monitor-grace-period и в разных кластерах настроено по-разному, не воспринимайте как гарантированную цифру), и после таймаута перепланирует поды на живые узлы — без участия человека, при условии что на других узлах есть свободные ресурсы.
3. Команда выросла, и вокруг compose расползся зоопарк ad-hoc-скриптов. Один разработчик — один docker-compose.yml, все всё помнят. Три команды, десять проектов — и у каждой свой способ деплоя: где-то через docker compose up -d по ssh, где-то через самописный bash-скрипт с rsync, где-то вообще руками. Kubernetes здесь ценен не оркестрацией, а тем, что даёт единый паттерн деплоя (манифесты, namespace на команду/проект, единый CI/CD пайплайн) — то, что можно стандартизировать и передать новому человеку за один онбординг, а не объяснять «а вот тут у нас исторически по-другому».
Если ни один из трёх пунктов не про вас — вероятно, вы попали под миф о том, что Kubernetes нужен любому проекту, и compose ещё долго прослужит.
Когда compose ещё справляется — честно
Прежде чем переходить, стоит убедиться, что вы не решаете надуманную проблему. Compose отлично справляется, если: нагрузка предсказуема и укладывается в один-два сервера с запасом; отказоустойчивость на уровне «упал сервер — подняли из бэкапа за 20-40 минут» устраивает бизнес (не любому проекту нужен automatic failover за секунды); команда — это 1-5 человек, которые и так синхронизируются в чате. Переход на Kubernetes ради «а вдруг понадобится» добавляет операционную сложность уже сейчас ради гипотетической выгоды потом — это тот же антипаттерн, что и преждевременный переход с монолита на микросервисы: архитектура должна догонять реальную проблему, а не бежать впереди неё.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверШаг 0: готово ли само приложение к горизонтальному масштабированию
Это шаг, который пропускают чаще всего — и потом удивляются, почему Kubernetes «не помог». Оркестратор умеет размножать и перезапускать поды, но если приложение не спроектировано под горизонтальное масштабирование, лишние реплики просто сломают состояние.
Проверьте по чек-листу, прежде чем трогать манифесты:
- Приложение stateless. Сессии пользователей не хранятся в памяти процесса или на локальном диске контейнера — они в Redis, Memcached или базе. Если у вас
express-sessionсMemoryStoreили Laravel-сессии в файлах контейнера — при масштабировании до нескольких подов пользователь будет случайно попадать то на под с его сессией, то без неё. - Конфигурация через переменные окружения, а не через файлы, которые кто-то один раз руками положил на сервер. В compose это
.env-файл — принцип тот же, просто в Kubernetes он становитсяConfigMap/Secret, монтируемым как переменные окружения или файл. - Состояние вынесено наружу. Загруженные пользователем файлы — в S3-совместимое хранилище, а не в volume контейнера приложения. Локальные volume в Kubernetes без
StatefulSetи сетевого хранилища не гарантируют, что новый под окажется на том же узле с теми же данными. - Логи идут в stdout/stderr, а не пишутся в локальный файл на диске контейнера — иначе при пересоздании пода вы теряете историю.
Если по чек-листу нашлись минусы — почините их ещё в docker-compose, до миграции. Это дешевле: вы проверяете идею на знакомой инфраструктуре, а не одновременно учите Kubernetes и переписываете хранение сессий.
Managed Kubernetes или свой control plane
Здесь чаще всего команды спотыкаются вторично: разворачивают Kubernetes «с нуля» — свой etcd, свой control plane, свои сертификаты — и обнаруживают, что теперь у них две системы, требующие поддержки: приложение и сам кластер.
| Что нужно поддерживать | Свой control plane | Managed Kubernetes |
|---|---|---|
etcd (хранилище состояния кластера) | Вы: бэкапы, отказоустойчивость, апгрейды | Провайдер |
| API server, scheduler, controller-manager | Вы | Провайдер |
| Сертификаты и их ротация | Вы | Провайдер (в основном) |
| Апгрейд версии Kubernetes | Вы, вручную, с риском простоя | Провайдер, обычно с окном обслуживания |
| Worker-узлы (сами серверы под нагрузку) | Вы | Вы — это ваша часть в любом случае |
Managed-вариант отдаёт провайдеру самую рискованную и наименее выгодную для вас часть — управление control plane — а worker-узлы (серверы, на которых реально крутятся ваши поды) вы всё равно арендуете и настраиваете сами, подключая их к кластеру как обычные ноды. Для старта это существенно меньше поверхности отказа: вы не чините etcd в 3 часа ночи, вы чините своё приложение. Самостоятельный control plane имеет смысл обсуждать отдельно — обычно когда у вас уже есть команда, которая умеет с этим жить, или специфические требования по расположению данных, которые managed-предложения не закрывают.
Лёгкие дистрибутивы вроде k3s — компромисс: control plane всё равно ваш, но его установка и поддержка кратно проще полного kubeadm-кластера. Это разумный средний вариант, если managed-предложение недоступно в нужном регионе, а полноценный kubeadm кажется избыточным для старта.
Поэтапный план миграции: не весь стек одним прыжком
Резкий переход «в пятницу выключили compose, в понедельник включили Kubernetes» — почти гарантированный способ получить внеплановый инцидент. План ниже растягивает миграцию на несколько недель осознанно.
Этап 1. Подготовка приложения. Закройте пункты из чек-листа выше (stateless, конфиг через env, состояние наружу). Без этого дальше двигаться бессмысленно.
Этап 2. Выбор платформы и подготовка инфраструктуры. Определитесь с managed Kubernetes или k3s-кластером, арендуйте серверы под worker-узлы с запасом по ресурсам (миграция временно требует держать и старый compose-стек, и новый кластер одновременно). Подключите узлы, проверьте базовую связность:
kubectl get nodes
NAME STATUS ROLES AGE VERSION
worker-01 Ready <none> 2m v1.30.x
worker-02 Ready <none> 2m v1.30.x
Этап 3. Выберите пилотный сервис — не главный. Возьмите наименее критичный сервис из стека: фоновый воркер, обработчик очереди, внутреннюю админку — что-то, чей простой на 10 минут не разбудит никого ночью. Не мигрируйте сразу основной пользовательский сервис.
Переведите его compose-описание в манифесты вручную (автоматические конвертеры вроде kompose convert дают черновик, но его обязательно нужно перечитать и поправить — особенно секции с volume и сетью, они конвертируются не один в один):
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker-pilot
spec:
replicas: 2
selector:
matchLabels:
app: worker-pilot
template:
metadata:
labels:
app: worker-pilot
spec:
containers:
- name: worker
image: registry.example.com/worker:latest
envFrom:
- configMapRef:
name: worker-config
readinessProbe:
exec:
command: ["/bin/sh", "-c", "pgrep worker"]
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 15
Обратите внимание на readinessProbe/livenessProbe — это прямой аналог healthcheck в compose, но именно от них зависит, будет ли Kubernetes реально считать под живым и направлять на него трафик.
Этап 4. Параллельная эксплуатация. Дайте пилоту пожить 2-4 недели рядом со старым compose-стеком, под реальной нагрузкой, прежде чем выключать старую версию сервиса. Это время, за которое команда набивает руку на kubectl, читает логи через kubectl logs, разбирается с kubectl describe pod при проблемах — на сервисе, где ошибка не стоит инцидента.
Этап 5. Расширяйте по одному сервису. После стабилизации пилота — следующий сервис, потом следующий. Стек декомпозируется постепенно, а не одним движением. Docker Compose при этом можно и нужно оставить для локальной разработки — большинство команд так и делают, даже полностью переехав в Kubernetes на проде: локально быстрее поднять docker compose up, чем локальный кластер.
Что реально меняется в эксплуатации — и это не бесплатно
Честно: Kubernetes не «тот же docker-compose, но лучше». Он добавляет реальную операционную сложность, и это стоит признать заранее, а не после того как команда обожглась.
- RBAC. В compose у вас обычно один SSH-доступ на сервер, и точка. В Kubernetes нужно осознанно настраивать
Role/RoleBinding/ClusterRoleBinding— кто может смотреть логи, кто может деплоить, кто может трогать secrets. Это правильно с точки зрения безопасности при росте команды, но требует времени на настройку и понимания модели. - Сетевые политики. По умолчанию поды в кластере видят друг друга без ограничений — это ближе к докеровской bridge-сети, чем кажется, но масштаб другой: у вас не 5 контейнеров, а десятки подов из разных команд. Реальная изоляция требует
NetworkPolicy, а её отладка — отдельный навык, которого в compose-мире просто не существовало. - Секреты — по-другому. В compose секреты обычно живут либо в
.env-файле рядом с проектом, либо в docker secrets. В KubernetesSecretпо умолчанию хранится вetcdв base64 — это кодирование, а не шифрование, и без дополнительной настройки шифрования etcd at rest секрет читаем любым, у кого есть доступ к API с нужными правами. Если у вас уже был выстроен процесс вокруг управления паролями в docker secrets, в Kubernetes его придётся пересобирать — многие команды на этом этапе подключают внешний секрет-менеджер вместо встроенных Secrets. - Кривая обучения — это время, а не опция. Заложите недели, не дни, на то, чтобы команда освоилась с
kubectl, манифестами, отладкой падающих подов черезkubectl describeиkubectl logs --previous. Разумная практика — сначала обучить одного-двух человек на пилотном сервисе, и только потом переводить остальную команду, а не бросать всех в Kubernetes одновременно с первого дня.
Стоимость этой сложности стоит сверять с тем, что вы реально получаете — если сопоставить это с ценой масштабирования вверх или вширь, для части нагрузок вертикальный апгрейд одного сервера ещё долго будет дешевле, чем содержание Kubernetes-кластера и команды, которая умеет с ним работать.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Обязательно ли использовать managed Kubernetes, а не поднимать control plane самому?
Не обязательно, но для первого перехода managed-вариант почти всегда рациональнее: вы концентрируетесь на приложении, а не на поддержке etcd и апгрейдах control plane. Свой control plane имеет смысл рассматривать отдельно, когда у команды уже есть опыт эксплуатации Kubernetes.
Можно ли держать docker-compose и Kubernetes одновременно во время миграции?
Да, и это рекомендуемый путь, а не костыль — параллельная работа старого стека и пилотного сервиса в кластере несколько недель снижает риск и даёт команде время освоиться до того, как на кластер ляжет весь трафик.
Сколько времени в среднем занимает такой переход?
Точные сроки сильно зависят от размера стека и готовности приложения к масштабированию, поэтому ориентировочных цифр здесь давать не будем — но план из шести этапов выше рассчитан на постепенное движение месяцами, а не на выходные.
Что делать, если приложение изначально не проектировалось под горизонтальное масштабирование?
Начните с этапа 0 — переносите сессии в Redis, файлы в объектное хранилище, конфигурацию в переменные окружения — ещё в docker-compose, до перехода на Kubernetes. Так вы проверяете архитектурные изменения на знакомой инфраструктуре, не совмещая два источника риска одновременно.
Нужен ли Kubernetes, если у нас всего один сервис и один сервер?
Почти наверняка нет — ни один из трёх признаков готовности из первого раздела статьи в этом случае обычно не выполняется, и compose продолжит справляться.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →