Когда Docker Compose упёрся в потолок
Помню тот день отчётливо. Наш API обрабатывал ~5000 RPS в пиковое время. Docker Compose запускал 8 копий приложения на трёх серверах. Деплой выглядел так: SSH на каждый сервер, git pull, docker-compose up -d --build, молимся, чтобы всё не упало. Обычно падало.
Проблемы нарастали как снежный ком:
- Rolling update? Только руками, по одному серверу. Downtime на каждом — 30-60 секунд.
- Один сервер упал ночью. Load balancer продолжал слать туда трафик — узнали об этом утром от разгневанных клиентов.
- Автоскейлинг? Забудьте. Нагрузка растёт → я вручную запускаю ещё один сервер → через час всё успокоилось → сервер простаивает, я плачу за воздух.
- Health checks были, но примитивные: контейнер живой ≠ приложение работает.
В какой-то момент стало ясно: дальнейшее масштабирование с Compose превращается в ад поддержки. Нужен был оркестратор. Вопрос был — какой?
Docker Compose отлично подходит для локальной разработки и небольших продакшенов (1-3 сервера, до ~500 RPS). Но когда нагрузка растёт и простои стоят денег, нужны инструменты серьёзнее.
Реальные причины перехода на Kubernetes (не hype)
Давайте без маркетинговой лапши. Вот конкретные проблемы, которые решает Kubernetes, и которые Compose не решает или решает костылями.
Причина 1: Zero-downtime deployments из коробки
С Compose:
Вы останавливаете контейнер → собираете новый образ → запускаете. Даже если используете docker-compose up -d --no-deps --build service, там есть gap в несколько секунд. В продакшене это видят пользователи.
С Kubernetes:
Rolling update нативно. Новые поды запускаются → проходят readiness probe → начинают принимать трафик → старые gracefully завершаются. Downtime = 0. Откат (rollback) — одна команда: kubectl rollout undo.
# Деплой новой версии
kubectl set image deployment/myapp myapp=myapp:v2
# Откат, если что-то пошло не так
kubectl rollout undo deployment/myappПричина 2: Автоматическое восстановление (self-healing)
С Compose:
Контейнер умер → restart: unless-stopped перезапустит его. Но если упал весь сервер? Вручную SSH на новый, разворачиваете стек заново.
С Kubernetes: Под упал → scheduler автоматически запускает новый. Нода (сервер) упала → поды мигрируют на живые ноды. Всё автоматически, без вашего участия в 3 ночи.
Причина 3: Декларативная конфигурация и Git Ops
С Compose:
docker-compose.yml есть, но state управляется императивными командами (docker-compose up, docker-compose scale). Что сейчас работает на проде? Нужно SSH и смотреть.
С Kubernetes:
Всё описано в YAML манифестах. Хотите 5 реплик приложения? Пишете replicas: 5, применяете kubectl apply -f deployment.yaml. Kubernetes приведёт состояние кластера к желаемому. Git — единственный источник правды.
GitOps пример:
# Commit изменений в манифестах
git commit -m "Scale app to 10 replicas"
git push
# ArgoCD или Flux автоматически применят изменения
# Rollback? Просто git revert и pushПричина 4: Встроенные health checks и liveness probes
С Compose:
Можете прописать healthcheck в docker-compose.yml, но это примитивно: контейнер отвечает на /health → считается живым. Если база недоступна, а контейнер живой — получите 500 ошибки.
С Kubernetes: Два типа проверок:
- Liveness probe: Приложение живое? Если нет → убить под и запустить новый.
- Readiness probe: Приложение готово принимать трафик? Если нет → не слать запросы на этот под.
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5Результат: поды, которые ещё стартуют или уже тормозят, не получают трафик. Меньше 502, меньше криков клиентов.
Причина 5: Горизонтальное автомасштабирование (HPA)
С Compose:
Автоскейлинга нет. Нагрузка выросла → идёте в SSH, руками запускаете docker-compose scale app=10. Нагрузка упала → руками уменьшаете. Или пишете костыльный скрипт с cron.
С Kubernetes: Horizontal Pod Autoscaler (HPA) из коробки. Настраиваете метрику (CPU, память, custom метрика из Prometheus), и k8s автоматически масштабирует поды.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70CPU выше 70% → автоматически добавляются поды. CPU ниже → убираются. Вы спите спокойно.
Когда Compose достаточно (честно)
Не спешите переписывать всё на Kubernetes. Вот сценарии, когда Compose — правильный выбор:
- Локальная разработка — Compose проще, быстрее, меньше ресурсов.
- Монолит на 1-2 серверах — Если у вас 100-200 RPS и не критично, если раз в месяц будет минута downtime на деплой.
- Прототипы и MVP — Зачем усложнять, если проект может не взлететь?
- Команда без DevOps — Kubernetes требует знаний. Если их нет, Compose или managed решения (Render, Fly.io) — лучше.
Kubernetes — не серебряная пуля. Это сложный инструмент, который решает сложные задачи. Если ваши задачи не сложные, не усложняйте себе жизнь.
Kubernetes изнутри: что это на самом деле
Kubernetes (k8s) — это оркестратор контейнеров. Упрощённо: вы говорите k8s "мне нужно 5 копий приложения, каждая с 2 CPU и 4GB RAM", а он решает, на каких серверах их запустить, следит за их здоровьем, перезапускает при падении.
Ключевые концепции (минимум для старта)
1. Pod — минимальная единица развёртывания. Один или несколько контейнеров, которые всегда работают вместе на одной ноде.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 80802. Deployment — описывает желаемое состояние: сколько реплик пода, какой образ, стратегия обновления.
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v1.0.0
ports:
- containerPort: 80803. Service — сетевая абстракция. Даёт стабильный IP/DNS для набора подов. Типы: ClusterIP (внутри кластера), NodePort (доступ извне), LoadBalancer (облачный балансировщик).
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer4. Ingress — HTTP/HTTPS маршрутизация извне в сервисы. Аналог Nginx reverse proxy, но декларативный.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 805. ConfigMap и Secret — конфигурация и секреты. Вместо переменных в docker-compose.yml, они живут отдельно.
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
data:
DATABASE_URL: "postgresql://user@db:5432/mydb"
LOG_LEVEL: "info"
---
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM= # base64 encodedЧто k8s решает
- Оркестрация: Где запускать поды, как их балансировать
- Масштабирование: Горизонтальное и вертикальное
- Self-healing: Автоматический restart и rescheduling
- Service discovery: Поды находят друг друга по DNS
- Rolling updates и rollbacks
- Secrets management: Хранение и инъекция секретов
Что k8s НЕ решает
- ❌ Управление состоянием приложения — это ваша задача
- ❌ Мониторинг и логирование — нужны Prometheus, Loki, Grafana
- ❌ CI/CD — нужны GitLab CI, ArgoCD, Flux
- ❌ Backup и disaster recovery — нужны Velero и ручное планирование
- ❌ Безопасность — это целая отдельная область (RBAC, Network Policies, Pod Security Standards)
Kubernetes — это платформа, а не решение "под ключ". Это Lego, из которого вы собираете свою инфраструктуру. Нужны дополнительные инструменты и знания.
Helm charts на практике
Helm — это "пакетный менеджер" для Kubernetes. Аналог apt для Ubuntu или npm для Node.js, только для k8s манифестов.
Зачем нужен Helm
Представьте: у вас есть приложение с Deployment, Service, Ingress, ConfigMap, Secret. Это ~200 строк YAML. Теперь хотите развернуть это в 3 окружениях: dev, staging, prod. С разными параметрами: количество реплик, лимиты ресурсов, домены.
Без Helm: Копипаста YAML файлов, Find & Replace значений. Кошмар поддержки.
С Helm: Один шаблон (chart), параметры в values.yaml. Деплой в любое окружение — одна команда.
Структура Helm Chart
myapp/
Chart.yaml # Метаданные: имя, версия
values.yaml # Дефолтные значения переменных
templates/
deployment.yaml # Шаблон Deployment
service.yaml # Шаблон Service
ingress.yaml # Шаблон Ingress
configmap.yaml # Шаблон ConfigMap
Миграция с docker-compose на Helm (практический пример)
Было (docker-compose.yml):
version: "3.8"
services:
app:
image: myapp:latest
ports:
- "8080:8080"
environment:
DATABASE_URL: postgresql://user:pass@db:5432/mydb
REDIS_URL: redis://redis:6379
depends_on:
- db
- redis
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: secretpass
volumes:
- db_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
db_data:Стало (Helm Chart):
values.yaml:
replicaCount: 3
image:
repository: myapp
tag: "v1.0.0"
pullPolicy: IfNotPresent
service:
type: LoadBalancer
port: 80
targetPort: 8080
ingress:
enabled: true
host: myapp.example.com
env:
DATABASE_URL: postgresql://user@postgres:5432/mydb
REDIS_URL: redis://redis:6379
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: { { include "myapp.fullname" . } }
spec:
replicas: { { .Values.replicaCount } }
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: { { .Values.service.targetPort } }
env:
- name: DATABASE_URL
value: { { .Values.env.DATABASE_URL } }
- name: REDIS_URL
value: { { .Values.env.REDIS_URL } }
resources: { { - toYaml .Values.resources | nindent 10 } }
livenessProbe:
httpGet:
path: /health
port: { { .Values.service.targetPort } }
initialDelaySeconds: 30
readinessProbe:
httpGet:
path: /health/ready
port: { { .Values.service.targetPort } }
initialDelaySeconds: 5Деплой:
# Установка chart
helm install myapp ./myapp
# Обновление с новыми параметрами
helm upgrade myapp ./myapp --set image.tag=v1.1.0
# Откат к предыдущей версии
helm rollback myapp
# Удаление
helm uninstall myappРазные окружения:
# Dev (1 реплика, маленькие ресурсы)
helm install myapp-dev ./myapp -f values-dev.yaml
# Staging (3 реплики)
helm install myapp-staging ./myapp -f values-staging.yaml
# Production (10 реплик, HPA)
helm install myapp-prod ./myapp -f values-prod.yamlГотовые Helm Charts
Не нужно писать всё с нуля. Есть огромный репозиторий готовых charts: Artifact Hub.
Популярные charts:
# PostgreSQL
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install postgres bitnami/postgresql
# Redis
helm install redis bitnami/redis
# Nginx Ingress Controller
helm install nginx-ingress ingress-nginx/ingress-nginx
# Prometheus + Grafana (мониторинг)
helm install monitoring prometheus-community/kube-prometheus-stackHelm экономит десятки часов. Вместо написания сотен строк YAML, берёте готовый chart, кастомизируете values.yaml, деплоите. Profit.
Local development с Kubernetes
Перед тем, как запускать k8s в продакшене, нужно научиться работать с ним локально. Проблема: полноценный k8s требует несколько серверов и гигабайты RAM. Решение: локальные k8s дистрибутивы.
kind vs minikube vs k3d — сравнение
| Критерий | kind | minikube | k3d |
|---|---|---|---|
| Основа | Docker контейнеры | VM (VirtualBox/Docker) | k3s в Docker |
| Скорость запуска | ✅ Очень быстро (10-20 сек) | ⚠️ Медленно (1-2 мин) | ✅ Быстро (20-30 сек) |
| RAM | ✅ Мало (~2GB) | ❌ Много (~4-8GB) | ✅ Мало (~1-2GB) |
| Multi-node кластер | ✅ Да | ✅ Да (сложнее) | ✅ Да |
| LoadBalancer support | ⚠️ Через MetalLB | ✅ Из коробки | ✅ Из коробки |
| Близость к prod | ✅ Очень близко | ✅ Близко | ⚠️ k3s != полный k8s |
| Лучше для | CI/CD, тестирование | Обучение, dev | Быстрый dev |
Мой выбор:
- kind — для CI/CD и если хотите максимальной близости к реальному k8s.
- minikube — для обучения и экспериментов, если RAM не проблема.
- k3d — для ежедневной разработки, когда нужна скорость.
Практический setup: kind
Установка (macOS):
brew install kind kubectl
# Или через binary
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-darwin-arm64
chmod +x ./kind
mv ./kind /usr/local/bin/kindСоздание кластера:
# Базовый single-node кластер
kind create cluster --name dev
# Multi-node кластер (1 control-plane + 2 workers)
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOFПроверка:
kubectl cluster-info
kubectl get nodesДеплой приложения:
# Загрузка локального образа в kind
kind load docker-image myapp:latest --name dev
# Деплой
kubectl apply -f deployment.yaml
kubectl get pods
kubectl logs -f <pod-name>
# Проброс порта для доступа
kubectl port-forward deployment/myapp 8080:8080
# Теперь доступно на http://localhost:8080Удаление кластера:
kind delete cluster --name devПрактический setup: k3d
Установка:
brew install k3d
# Или curl
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bashСоздание кластера с LoadBalancer:
# Кластер с 3 worker нодами и LoadBalancer на порту 8080
k3d cluster create dev \
--agents 3 \
--port "8080:80@loadbalancer"Деплой:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# Если Service type: LoadBalancer, доступен на localhost:8080
curl http://localhost:8080Остановка/запуск кластера:
k3d cluster stop dev
k3d cluster start devКак не убить свой лаптоп
Ресурсы:
- Минимум: 8GB RAM, 4 CPU cores
- Рекомендуется: 16GB RAM, 6+ CPU cores
Оптимизация:
- Ограничьте ресурсы Docker Desktop: Settings → Resources → 6GB RAM, 4 CPUs
- Используйте
resource limitsв манифестах:resources: limits: cpu: 200m memory: 256Mi - Не запускайте всё разом. Нужно тестировать API? Запускайте только API + БД, без фронтенда и микросервисов.
- Используйте
kubectl deleteпосле тестов. Остановленные поды всё равно жрут RAM.
Локальный k8s — не игрушка. Он реально потребляет ресурсы. Если лаптоп тормозит, используйте облачный dev кластер (GKE Autopilot, EKS, DigitalOcean Kubernetes). 1-2 worker ноды стоят $10-20/мес.
Мониторинг и debugging в Kubernetes
Kubernetes — чёрный ящик, пока не настроите наблюдаемость. Вот минимальный набор для выживания.
kubectl — ваш главный инструмент
Основные команды:
# Получить список подов
kubectl get pods
# Подробная информация о поде
kubectl describe pod <pod-name>
# Логи пода
kubectl logs <pod-name>
kubectl logs <pod-name> -f # follow (real-time)
kubectl logs <pod-name> --previous # логи предыдущего упавшего контейнера
# Логи всех подов deployment
kubectl logs -l app=myapp --all-containers=true
# Exec в под (как docker exec)
kubectl exec -it <pod-name> -- /bin/bash
# Проброс порта
kubectl port-forward pod/<pod-name> 8080:8080
# События кластера
kubectl get events --sort-by='.lastTimestamp'
# Top (CPU/Memory usage)
kubectl top nodes
kubectl top podsTroubleshooting типичных проблем:
1. Pod в статусе Pending
kubectl describe pod <pod-name>
# Смотрите Events: обычно "Insufficient CPU/Memory" или "No nodes available"Решение: Увеличьте ресурсы кластера или уменьшите requests пода.
2. Pod в статусе CrashLoopBackOff
kubectl logs <pod-name> --previous
# Смотрите, почему упал контейнерРешение: Обычно ошибка в коде, неправильная конфигурация или недоступная зависимость (БД, Redis).
3. Pod Running, но не отвечает
kubectl describe pod <pod-name>
# Смотрите Readiness probeРешение: Под не прошёл readiness probe → не получает трафик. Проверьте /health/ready endpoint.
4. Service недоступен
kubectl get svc
kubectl get endpoints <service-name>
# Endpoints пустой? Поды не прошли readiness probeМониторинг: Prometheus + Grafana
Быстрый setup через Helm:
# Добавляем репозиторий
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# Устанавливаем kube-prometheus-stack (Prometheus + Grafana + Alertmanager)
helm install monitoring prometheus-community/kube-prometheus-stack
# Получаем пароль Grafana
kubectl get secret monitoring-grafana -o jsonpath="{.data.admin-password}" | base64 --decode
# Проброс порта для доступа
kubectl port-forward svc/monitoring-grafana 3000:80
# Grafana доступна на http://localhost:3000 (admin / <password>)Что получите:
- Prometheus с метриками кластера, нод, подов
- Grafana с готовыми дашбордами (Kubernetes Overview, Node Exporter, etc.)
- Alertmanager для алертов
Полезные дашборды (уже встроены):
- Kubernetes / Compute Resources / Cluster
- Kubernetes / Compute Resources / Namespace (Pods)
- Node Exporter / Nodes
Логирование: Loki + Promtail
Setup через Helm:
helm repo add grafana https://grafana.github.io/helm-charts
helm install loki grafana/loki-stack \
--set grafana.enabled=false \
--set promtail.enabled=true
# Добавьте Loki как data source в Grafana
# URL: http://loki:3100Просмотр логов в Grafana:
- Explore → Loki data source
- Query:
{app="myapp"} - Фильтрация:
{app="myapp"} |= "ERROR"
Альтернативы Kubernetes
Kubernetes — не единственный оркестратор. Иногда альтернативы лучше подходят. Честное сравнение.
Nomad — простота и практичность
Что это: Оркестратор от HashiCorp. Умеет управлять контейнерами (Docker), виртуалками, standalone приложениями.
Плюсы:
- ✅ Простота: Конфигурация в разы проще k8s. 100 строк Nomad = 300 строк k8s.
- ✅ Lightweight: Один бинарь, 50MB RAM. k8s — это десятки компонентов.
- ✅ Multi-runtime: Docker, Podman, Java, binaries, VMs.
- ✅ Интеграция с Consul (service mesh) и Vault (secrets).
Минусы:
- ❌ Экосистема меньше: Меньше готовых решений и community charts.
- ❌ Нет встроенного Ingress: Нужен отдельный Nginx/Traefik.
- ❌ Меньше managed опций: AWS/GCP/Azure не предлагают managed Nomad.
Когда выбирать:
- Небольшие команды (до 10 человек), которым нужна простота.
- Если уже используете HashiCorp стек (Consul, Vault, Terraform).
- Хотите управлять не только контейнерами, но и legacy приложениями.
Пример конфига Nomad:
job "myapp" {
datacenters = ["dc1"]
group "app" {
count = 3
task "web" {
driver = "docker"
config {
image = "myapp:v1.0.0"
ports = ["http"]
}
resources {
cpu = 500
memory = 512
}
service {
name = "myapp"
port = "http"
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "2s"
}
}
}
}
}AWS ECS — если уже в AWS
Что это: Managed оркестратор от Amazon. Глубокая интеграция с AWS (ALB, RDS, IAM).
Плюсы:
- ✅ Managed: AWS управляет control plane, вы только деплоите задачи.
- ✅ AWS-native: Интеграция с IAM ролями, секретами, логами, метриками.
- ✅ Fargate: Serverless режим — не управляете серверами вообще.
Минусы:
- ❌ Vendor lock-in: Привязка к AWS, миграция сложна.
- ❌ Дороже, чем самостоятельный k8s (особенно Fargate).
- ❌ Меньше гибкости, чем k8s.
Когда выбирать:
- Вы уже полностью в AWS.
- Не хотите управлять инфраструктурой (Fargate).
- Простота важнее гибкости.
Fly.io — современный подход
Что это: Платформа для деплоя контейнеров ближе к пользователям (edge computing). Под капотом — их собственный оркестратор на базе Nomad.
Плюсы:
- ✅ Простота:
fly deploy— и готово. Как Heroku, но с Docker. - ✅ Global distribution: Автоматически деплоит ваше приложение в дата-центры по всему миру.
- ✅ Бесплатный тир: До 3 VM, достаточно для экспериментов.
- ✅ Managed PostgreSQL, Redis из коробки.
Минусы:
- ❌ Vendor lock-in.
- ❌ Меньше контроля, чем в k8s.
- ❌ Стоимость растёт при масштабировании.
Когда выбирать:
- Стартапы и малые проекты.
- Хотите скорость деплоя без DevOps-команды.
- Global latency важна (пользователи по всему миру).
Пример деплоя:
# Установка CLI
brew install flyctl
# Вход
fly auth login
# Инициализация приложения
fly launch
# Деплой
fly deploy
# Масштабирование
fly scale count 5
fly scale vm shared-cpu-2xDocker Swarm — забытый, но живой
Что это: Встроенный в Docker оркестратор. Упрощённая версия k8s.
Плюсы:
- ✅ Простота: Проще, чем k8s. Если знаете Docker, Swarm освоите за день.
- ✅ Встроен в Docker: Не нужна дополнительная установка.
- ✅ docker-compose.yml совместимость: Можно деплоить существующие compose файлы.
Минусы:
- ❌ Умирающий проект: Docker Inc почти не развивает его.
- ❌ Нет экосистемы: Мало готовых решений.
- ❌ Меньше функций, чем k8s.
Когда выбирать:
- Если Docker Compose уже недостаточно, но k8s — overkill.
- Для небольших продакшенов (3-5 серверов).
Миграция с Compose:
# Инициализация Swarm
docker swarm init
# Деплой compose файла
docker stack deploy -c docker-compose.yml myapp
# Масштабирование
docker service scale myapp_web=5Итоговая таблица выбора
| Критерий | Kubernetes | Nomad | AWS ECS | Fly.io | Docker Swarm |
|---|---|---|---|---|---|
| Сложность | ❌ Высокая | ⚠️ Средняя | ✅ Низкая | ✅ Очень низкая | ✅ Низкая |
| Экосистема | ✅ Огромная | ⚠️ Средняя | ⚠️ AWS-only | ⚠️ Маленькая | ❌ Мёртвая |
| Гибкость | ✅ Максимум | ✅ Высокая | ⚠️ Средняя | ❌ Низкая | ⚠️ Средняя |
| Vendor lock-in | ✅ Нет | ✅ Нет | ❌ AWS | ❌ Fly.io | ✅ Нет |
| Стоимость | ⚠️ DIY дёшево, managed дорого | ✅ DIY дёшево | ❌ Дорого | ⚠️ Растёт | ✅ Дёшево |
| Для кого | Средние/крупные команды | Малые команды, HashiCorp стек | AWS-native проекты | Стартапы | Малые проекты |
Мой совет: начинайте с простого. Если Docker Compose достаточно — оставайтесь на нём. Перерастёте — сначала попробуйте Fly.io или Nomad. Kubernetes — когда реально нужна его мощь и гибкость.
Реальная цена перехода на Kubernetes
Давайте честно: Kubernetes — это инвестиция. Не только в инфраструктуру, но и во время и знания.
Время на изучение
Минимальный уровень (чтобы деплоить): 20-40 часов
- Концепции: Pods, Deployments, Services, Ingress
- kubectl базовые команды
- Helm установка готовых charts
- Troubleshooting: логи, describe, events
Средний уровень (чтобы управлять в продакшене): 100-200 часов
- Сетевая модель k8s, NetworkPolicies
- RBAC и безопасность
- Stateful приложения (StatefulSets, PersistentVolumes)
- Мониторинг и логирование
- CI/CD интеграция
- Disaster recovery
Экспертный уровень (архитектор k8s): 500+ часов
- Multi-cluster setup
- Service mesh (Istio, Linkerd)
- Custom operators
- Performance tuning
- Кастомные schedulers и admission controllers
Сложность эксплуатации
Managed Kubernetes (EKS, GKE, AKS):
- ✅ Control plane управляется провайдером
- ✅ Автоматические обновления
- ⚠️ Вы управляете worker nodes, addons, мониторингом
- 💰 Стоимость: $70-150/мес за control plane + $50-200/мес за worker nodes
Self-hosted Kubernetes:
- ❌ Вы управляете всем: control plane, etcd, сетью, обновлениями
- ❌ Нужен DevOps/SRE в команде
- ❌ Высокий риск, если нет экспертизы
- 💰 Стоимость: $0 за софт, но нужно время команды
Реальные затраты (из моей практики):
Проект на 5 микросервисах, 20-30 подов, ~2000 RPS.
- Managed GKE: $250/мес (control plane + 3 worker ноды e2-standard-4)
- Время DevOps: 10-15 часов/мес на поддержку
- Мониторинг: Prometheus + Grafana self-hosted, $0 доп. затрат
- Обучение команды: 2 недели на онбординг разработчиков
Итого: ~$250/мес + 10-15 часов времени. Окупается, если экономите на ручном масштабировании и downtimes.
Когда НЕ стоит переходить на Kubernetes
- Команда < 3 разработчиков — overhead на k8s съест всё время.
- Монолит на 1 сервере — Docker Compose достаточно.
- Нет DevOps экспертизы — лучше Fly.io, Render, Railway.
- Стартап на MVP стадии — фокусируйтесь на продукте, а не инфраструктуре.
- Budget < $500/мес — managed k8s дорого, self-hosted — риск.
Kubernetes — это не статус и не модный тренд. Это инструмент для решения конкретных проблем. Если этих проблем нет, не создавайте себе новые, внедряя k8s.
Пошаговый переход с Compose на Kubernetes
Если решили, что k8s — это ваш путь, вот план миграции без боли.
Этап 1: Подготовка (1-2 недели)
1. Изучите основы k8s
- Пройдите официальный туториал: kubernetes.io/docs/tutorials
- Поднимите локальный кластер (kind или k3d)
- Деплойте тестовое приложение
2. Аудит текущей инфраструктуры
- Какие сервисы работают?
- Какие зависимости между ними?
- Где хранится состояние (базы, файлы, кеши)?
- Какие переменные окружения и секреты используются?
3. Выберите managed k8s или self-hosted
- Managed (GKE, EKS, AKS) — если бюджет позволяет
- Self-hosted (kubeadm, k3s) — если есть DevOps экспертиза
4. Настройте CI/CD для k8s
- Интегрируйте kubectl/helm в пайплайн
- Настройте image registry (Docker Hub, GCR, ECR)
Этап 2: Миграция stateless сервисов (2-4 недели)
1. Начните с самого простого сервиса
- Выберите stateless сервис без зависимостей
- Создайте Deployment и Service манифесты
- Деплойте в dev namespace
Пример миграции API сервиса:
Было (docker-compose.yml):
api:
image: myapi:latest
ports:
- "8080:8080"
environment:
DATABASE_URL: postgresql://db:5432/mydbСтало (k8s/api-deployment.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: myapi:v1.0.0
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: api-secrets
key: database-url
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: 8080
readinessProbe:
httpGet:
path: /health/ready
port: 8080
---
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api
ports:
- port: 80
targetPort: 80802. Постепенно мигрируйте остальные stateless сервисы
3. Настройте Ingress для HTTP трафика
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 80Этап 3: Миграция stateful сервисов (4-8 недель)
1. Базы данных — НЕ спешите мигрировать
- Managed БД (RDS, Cloud SQL) проще, чем PostgreSQL в k8s
- Если мигрируете — используйте StatefulSets и PersistentVolumes
- Обязательно настройте backup и disaster recovery
Managed БД (рекомендуется):
env:
- name: DATABASE_URL
value: postgresql://user@rds-endpoint:5432/mydbPostgreSQL в k8s (сложно, но возможно):
# Используйте готовый Helm chart
helm install postgres bitnami/postgresql \
--set persistence.size=100Gi \
--set primary.persistence.storageClass=ssd2. Redis/Memcached — можно в k8s
helm install redis bitnami/redis3. Файловое хранилище
- Используйте S3-compatible хранилище (AWS S3, MinIO)
- Или PersistentVolumeClaims с ReadWriteMany (NFS, Ceph)
Этап 4: Настройка мониторинга и логирования (1-2 недели)
# Prometheus + Grafana
helm install monitoring prometheus-community/kube-prometheus-stack
# Loki для логов
helm install loki grafana/loki-stackЭтап 5: Переключение трафика (1 день, но тестируйте неделю)
1. Parallel run
- Запустите новый k8s стек параллельно со старым Compose
- Переключите небольшой процент трафика (10%) на k8s
- Мониторьте метрики и логи
2. Постепенное переключение
- 10% трафика → проверка → 50% → проверка → 100%
3. Откат всегда возможен
- Держите старый Compose стек живым ещё 1-2 недели
- Если что-то пошло не так — откатываете трафик обратно
Post-migration checklist
Выводы
Kubernetes — мощный инструмент, но не панацея. Он решает реальные проблемы масштабирования, отказоустойчивости и автоматизации. Но цена входа — время на обучение и сложность эксплуатации.
Что запомнить:
-
Docker Compose достаточно для малых проектов (1-3 сервера, до 500 RPS). Не усложняйте без необходимости.
-
Переходите на k8s, когда:
- Нужен zero-downtime deployment
- Горизонтальное автомасштабирование критично
- Команда готова инвестировать время в обучение
- Managed k8s доступен и бюджет позволяет
-
Helm charts экономят десятки часов. Не пишите YAML с нуля, используйте готовые charts.
-
Local development: kind для CI/CD, k3d для ежедневной разработки, minikube для обучения.
-
Альтернативы существуют:
- Nomad — простота для HashiCorp стека
- Fly.io — скорость для стартапов
- AWS ECS — если в AWS и хотите managed
- Docker Swarm — если k8s overkill, а Compose мало
-
Мониторинг — не опция. Prometheus + Grafana + Loki — минимальный стек для production k8s.
-
Миграция — постепенная. Начните с stateless сервисов, тестируйте, мониторьте, только потом мигрируйте критичные stateful компоненты.
-
Не мигрируйте базы в k8s без веских причин. Managed БД (RDS, Cloud SQL) проще и надёжнее.
Мой личный вывод:
Я прошёл путь от Compose к k8s в 2021 году. Первые 2 месяца — боль, обучение, грабли. Но когда всё заработало, я получил инфраструктуру, которая масштабируется без моего участия, восстанавливается сама и позволяет деплоить 10 раз в день без простоев.
Kubernetes стоит своих денег и времени, если ваша задача достаточно сложна. Если нет — используйте более простые инструменты и спите спокойно.
P.S. Если у вас вопросы по миграции на k8s или нужна помощь в выборе оркестратора, пишите — помогу разобраться.
См. также:
- Load Balancers — следующий шаг после Docker Compose
- Monitoring Stack 2025 — как настроить Prometheus + Grafana

