26. Деплой на сервер
Деплой Docker-контейнеров в production отличается от разработки: необходимы стабильность, возможность отката, мониторинг и минимальный downtime. Рассмотрим основные стратегии и инструменты.
docker run в Production
Заголовок раздела «docker run в Production»В простейшем случае production деплой — это запуск контейнера с явными параметрами:
docker run -d \ --name myapp \ --restart=always \ # автоперезапуск при падении -p 80:3000 \ -e NODE_ENV=production \ -e DATABASE_URL=postgres://... \ --memory=512m \ --cpus=1 \ --log-driver=json-file \ --log-opt max-size=10m \ --log-opt max-file=3 \ myapp:v1.2.3Политики перезапуска:
no— не перезапускать (по умолчанию)always— всегда перезапускатьon-failure[:N]— при ненулевом коде, максимум N разunless-stopped— какalways, но не послеdocker stop
Для production рекомендуется unless-stopped: контейнер стартует с демоном Docker, но вы можете его остановить вручную.
Docker Compose в Production
Заголовок раздела «Docker Compose в Production»Для приложений с несколькими сервисами используйте Compose:
services: app: image: myapp:${APP_VERSION} # версия из переменной окружения restart: unless-stopped ports: - "127.0.0.1:3000:3000" # только localhost, не наружу environment: - NODE_ENV=production env_file: - .env.production deploy: resources: limits: memory: 512M cpus: '1' healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s timeout: 10s retries: 3Деплой:
# Обновить образ и перезапуститьAPP_VERSION=v1.2.3 docker compose -f docker-compose.prod.yml up -d --pull always
# Только пересоздать изменившиеся сервисыdocker compose up -d --no-deps appEnvironment-specific Конфиги
Заголовок раздела «Environment-specific Конфиги»Разделяйте конфигурацию по средам с помощью множественных Compose-файлов:
docker-compose.yml # базовая конфигурацияdocker-compose.dev.yml # переопределения для разработкиdocker-compose.prod.yml # переопределения для productiondocker-compose.test.yml # для тестирования# Разработкаdocker compose -f docker-compose.yml -f docker-compose.dev.yml up
# Productiondocker compose -f docker-compose.yml -f docker-compose.prod.yml up -dПример базовой и dev-конфигурации:
# docker-compose.yml (базовая)services: app: build: . environment: - NODE_ENV=development
# docker-compose.prod.yml (переопределение)services: app: image: registry.example.com/myapp:${VERSION} environment: - NODE_ENV=production restart: unless-stoppedBlue-Green Деплой
Заголовок раздела «Blue-Green Деплой»Blue-green деплой исключает downtime: поднимаете новую версию (green) рядом со старой (blue), затем переключаете трафик.
# Текущая версия (blue) работает на порту 3000docker run -d --name app-blue -p 3000:3000 myapp:v1.0.0
# Поднимаем новую версию (green) на порту 3001docker run -d --name app-green -p 3001:3000 myapp:v1.1.0
# Проверяем greencurl http://localhost:3001/health
# Переключаем Nginx# В nginx.conf: proxy_pass http://localhost:3001;nginx -s reload
# Убираем старую версиюdocker stop app-blue && docker rm app-blueС Docker Compose и Nginx upstream можно автоматизировать переключение без изменения конфига.
Rolling Updates
Заголовок раздела «Rolling Updates»Rolling update обновляет контейнеры по одному, не останавливая весь сервис:
# Скачать новый образdocker pull myapp:v1.1.0
# Обновить и пересоздать только сервис appdocker compose up -d --no-deps --build app
# Docker Swarm: встроенные rolling updatesdocker service update \ --image myapp:v1.1.0 \ --update-parallelism 1 \ --update-delay 30s \ --update-failure-action rollback \ myapp-serviceОткат на предыдущую версию
Заголовок раздела «Откат на предыдущую версию»# Тегируйте образы конкретными версиями!docker pull myapp:v1.0.0
# С ComposeAPP_VERSION=v1.0.0 docker compose up -d
# Docker Swarmdocker service rollback myapp-serviceHealth Check и Graceful Shutdown
Заголовок раздела «Health Check и Graceful Shutdown»HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1Для graceful shutdown обрабатывайте SIGTERM в вашем приложении:
process.on('SIGTERM', async () => { console.log('Shutting down gracefully...'); await server.close(); await db.disconnect(); process.exit(0);});# Остановка с таймаутом (по умолчанию 10 секунд)docker stop --time=30 myapp