Практический гид по миграции: из Docker Compose в Kubernetes на AWS
Перенос приложения из Docker Compose в Kubernetes — это переход от локального запуска контейнеров к промышленному управлению инфраструктурой. Compose прост, но не дает self-healing, rolling updates, лимитов ресурсов и декларативного контроля. Ниже описан опыт переноса 5-сервисного Java-приложения (Tomcat, MySQL, Memcached, RabbitMQ, Nginx) в кластер Kubernetes на AWS, разбор ошибок Compose и пошаговый чек-лист миграции.
Сетевой контракт: сохранение имен хостов
Java-приложение на базе Spring 6 и Tomcat 10 использовало конфигурацию application.properties со следующими хостами зависимостей: базы данных db01:3306, кэша cache01:11211 и брокера mq01:5672. В Docker Compose имена служб выступали хостами в общей сети. В Kubernetes встроенная служба DNS автоматически выдает имена сервисам (Services) внутри пространства имен (Namespace). Создав Service с именами db01, cache01 и mq01, мы сохраняем сетевой контракт без изменения кода приложения.
Тестирование в Minikube и разбор локальных ошибок
При отладке манифестов в Minikube проявились допущения, скрытые Compose:
- Сборка образов. Kubernetes не собирает образы на лету. Все образы должны быть опубликованы в доступном реестре (Registry) — например, Docker Hub или AWS ECR.
- newline в секретах. Команда
echo "password" | base64кодирует символ переноса строки (\n). В результате MySQL получает пароль с невидимым символом и отклоняет авторизацию. Правильно кодировать черезecho -n. - Разрешения базы данных. В Kubernetes поды получают динамические адреса из сети Pod CIDR. В образе MySQL пришлось заменить локальный доступ на
MYSQL_ROOT_HOST: "%". - Конфликт обновления Stateful-подов. При стратегии
RollingUpdateновый под БД пытается смонтировать тот же диск PersistentVolumeClaim (PVC) с доступомReadWriteOnceдо того, как старый под отпустит его. Для одиночной базы необходимо выставить стратегиюtype: Recreate.
Подготовка облачного кластера AWS через kOps
Для развертывания продакшен-окружения использовался kOps (Kubernetes Operations), создающий всю инфраструктуру AWS (VPC, подсети, группы безопасности, серверы EC2) по декларативной модели.
Перед запуском kOps, согласно kOps AWS guide, нужно:
- Настроить DNS: делегировать субдомен (в примере:
prod.wzops.de). - Создать S3-хранилище конфигураций кластера и экспортировать путь:
export KOPS_STATE_STORE=s3://<bucket>.
Параметры кластера в регионе eu-north-1 (Стокгольм) на две зоны доступности:
- CNI Cilium без
kube-proxyдля eBPF-маршрутизации. - Рабочие узлы: 2 инстанса
t3.smallс дисками 12 GiB. - Control plane: инстанс
t3.medium(12 GiB) с резервным копированием etcd на 90 дней и отключенной анонимной авторизацией Kubelet.
Важный нюанс: сборка образов на процессорах Apple Silicon (arm64) приводит к сбою запуска на узлах AWS EC2 (amd64). Сборку необходимо проводить под целевую архитектуру: docker buildx build --platform linux/amd64 -t registry/app:1.0 --push ..
Публикация трафика: Ingress и переход на Gateway API
Для внешнего доступа одного ресурса Ingress недостаточно — требуется контроллер (например, ingress-nginx). Трафик идет по цепочке: Browser -> Cloudflare CNAME -> AWS Load Balancer (NLB/ELB) -> Ingress controller -> Service.
При работе с Cloudflare доступны режимы:
- Flexible SSL: шифрование только до Cloudflare. Трафик внутри AWS идет по HTTP, что упрощает настройку, но снижает безопасность.
- Full (или Full Strict): шифрование до балансировщика AWS, что требует наличия валидного SSL-сертификата на стороне Ingress-контроллера.
В современных стеках Ingress заменяют на Gateway API — стандарт для ролевого управления шлюзами (см. Kubernetes Gateway API).
При миграции на Gateway API выполняют действия:
- Полное удаление старого Ingress-контроллера (
kubectl delete -f <manifest-url>). - Установка манифестов Gateway API CRD.
- Развертывание шлюза NGINX Gateway Fabric v2.x с помощью Helm-чарта.
- Описание ресурсов:
GatewayClass(тип реализации),Gateway(слушатели портов и хосты) иHTTPRoute(связь домена с сервисом). - Обновление DNS у провайдера для привязки домена к новому балансировщику Gateway.
Чек-лист миграции и готовности к продакшену
Ниже приведена пошаговая процедура переноса сервисов:
1. Анализ зависимостей (Локально)
- Разделите сервисы на stateless (приложение) и stateful (MySQL).
- Выпишите внутренние имена хостов и сопоставьте порты.
2. Сборка и публикация контейнеров (CI/CD)
- Создайте multi-stage Dockerfile для уменьшения размера образов.
- Соберите образы под архитектуру
linux/amd64с помощьюdocker buildxи отправьте в реестр.
3. Создание манифестов и запуск (kubectl CLI в Minikube)
- Создайте Deployment для каждого процесса и Service для сетевых имен.
- Запишите секреты (пароли, API-токены) в Kubernetes Secret:
echo -n "my-db-password" | base64 - Для MySQL создайте PVC на 3 GiB и выставьте стратегию
Recreateв Deployment. - Для ожидания зависимостей (базы данных, кэша) в под приложения добавьте
initContainers. Пример скрипта ожидания DNS:Предупреждение: Доступность DNS не гарантирует готовность приложения БД принимать запросы. Настройтеuntil nslookup db01; do echo "waiting for db01"; sleep 2; donereadinessProbesдля портов или повторные попытки подключения в коде Java. - Выставите лимиты ресурсов контейнеров для стабильности:
requests.cpu: 250m,requests.memory: 256Mi,limits.cpu: 500m,limits.memory: 512Mi.
4. Развертывание кластера в AWS (kOps CLI)
- Создайте S3 state store и инициализируйте кластер:
kops create cluster --name=prod.wzops.de --state=s3://kops-state-bucket --zones=eu-north-1a,eu-north-1b --node-count=2 --node-size=t3.small --control-plane-size=t3.medium --dns-zone=prod.wzops.de --yes - Проверьте готовность инфраструктуры:
Безопасность: SSH-ключ используется только для аварийного доступа к узлам; повседневное управление идет через
kops validate cluster --name=prod.wzops.de --state=s3://kops-state-bucket --wait 10mkubectlи API-сервер.
5. Публикация и маршрутизация (Helm и kubectl CLI)
- Примените манифесты приложения, баз данных и секретов в облаке.
- Установите реализацию Gateway API и примените манифесты
GatewayиHTTPRoute. - Проверьте применение маршрутов:
kubectl get httproute -n production - Привяжите домен prod.wzops.de в DNS Cloudflare или Route 53 к хосту внешнего балансировщика, созданного Gateway.
- Проверьте работоспособность curl-запросом к домену.
6. Эксплуатация
- Подключите мониторинг Prometheus/Grafana, настройте сбор логов и алерты на сбои подов или TLS-сертификатов.
- Перейдите на GitOps-доставку манифестов с помощью Argo CD.

