Как не сломать прод? Топ 5 самых частых ошибок при деплое
Вы все сделали идеально, нажимаете кнопку Deploy, и наступает тот самый момент, когда сердце замирает. Прод горит, мониторинги упали, команда в ужасе. Что нужно сделать, чтобы такого не было — рассказываем в статье.
969 открытий8К показов

Когда вы деплоите, вы не просто заливаете код. Считайте, что это босс на последнем уровне, а значит — привет, ловушки и подводные камни. Ошибки на этом этапе могут стоить дорого: от недовольства техлида до потери клиентов. Мы собрали топ самых частых (и самых болезненных) багов при выкладке — рассказываем, как их избежать.

Олег Селин
Главный технический руководитель разработки, Центр экспертизы разработки и сопровождения систем Газпромбанка
Неправильная настройка инфраструктуры в CI/CD пайплайне
Это одна из самых коварных и частых ошибок при деплое, особенно в сложных системах, таких как Kubernetes-кластеры, облака или гибридные инфраструктуры. Эта проблема возникает, когда шаги деплоя в пайплайне не учитывают специфику целевого окружения. Все это может вылиться в непредсказуемое поведение приложения и структуры в целом. Разбираемся, как с этим бороться.
Настройте окружение
Разные окружения (dev, staging, prod) часто имеют отличия в конфигурации (например, версии библиотек, лимиты ресурсов, настройки сетей). Например, переменные окружения, заданные для staging, перезаписываются в prod — зависимости ломаются.
- Используйте Infrastructure as Code (IaC) инструменты, такие как Terraform или Pulumi, для создания идентичных окружений.
- Храните конфигурации окружений в репозитории (например, в формате YAML или JSON) и применяйте их через CI/CD.
- Настройте переменные окружения через секреты (например, HashiCorp Vault, AWS Secrets Manager) и убедитесь, что они не перезаписываются случайно.
Разворачивайте по стратегии
В Kubernetes, например, при неверной конфигурации стратегии возможны простои. Pods могут быть удалены до того, как новые успеют стартовать, или новые версии вообще не будут работать.
- В Kubernetes используйте RollingUpdate с настройками maxSurge и maxUnavailable, чтобы новые поды стартовали постепенно, а старые были постоянно доступны.
- Настройте readinessProbe и livenessProbe, чтобы Kubernetes не направлял трафик на неготовые поды.
- Ответственно подходите к настройке стратегии и выбору количества реплик.
- Для Helm-чартов фиксируйте версии (helm dependency update, helm package) и используйте helm upgrade --atomic для автоматического отката при сбое.
Например, в манифесте Deployment можно указать:
Избегайте race conditions
Параллельные процессы в CI/CD (например, одновременная сборка и деплой) могут вызывать состояния гонки.
- Настройте блокировки (locks) в CI/CD, чтобы не было параллельных деплоев в одно окружение (например, через environments в GitLab CI).
- Используйте атомарные операции в Helm и Server Side Apply в kubectl.
Обрабатывайте ошибки
Часто может быть такое, что нет нормальной обработки ошибок (логов, статусов). Например, доступ к сервису пропадает, но пайплайн все равно успешно завершается.
- Регулярно тестируйте пайплайн на staging-окружении, симулируйте реальные сценарии деплоя.
- Проверяйте доступность сервисов после деплоя с помощью health-check скриптов.
Новую проверку можно, например, добавить так:
curl --fail http://any-app.example.com/health
Нет изоляции переменных окружения и секретов
Представьте: в staging-окружении используются тестовые ключи, а в продакшене — боевые. Но из-за ошибки в CI/CD пайплайне или конфигурации staging берет продовые credentials. Как итог — тестовое удаление данных в песочнице стирает боевую базу. Или еще хуже: токены утекают из-за слабых прав доступа к Secret Manager, и вас могут спокойно взломать. Ниже рассказываем, как это пофиксить.
Разделяйте секреты по окружениям
Если переменные окружения или ключи не разделены между dev, staging и prod, они могут быть случайно использованы в неправильном контексте.
- Храните секреты в Secret Manager (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Kubernetes Secrets) с четким разделением по окружениям (например, пути secrets/staging/db, secrets/prod/db).
- Используйте префиксы или теги для идентификации окружения (например,
STAGING_API_KEY
,PROD_API_KEY
). - Настройте права доступа CD так, чтобы пайплайн мог подтягивать только секреты, которые относятся к текущему окружению.
Например, в Vault это настраивается так:
Не храните секреты в коде
Иначе утечка неизбежна.
- Уберите секреты из репозиториев и .env-файлов и используйте Secret Manager.
- Для Kubernetes используйте Secret-объекты или интеграцию с внешними менеджерами (например, External Secrets Operator).
- Проверяйте репозитории на утечки с помощью инструментов типа truffleHog или gitleaks.
Вот пример Kubernetes Secret:
Ограничивайте доступ
Это принцип Scoped Permissions — с помощью него можно снизить риски случайного или намеренного использования секретов.
- Используйте IAM-роли в облаке (например, AWS IAM Roles for Service Accounts) с минимальными правами.
- Ограничивайте доступ разработчиков к продовым секретам через RBAC или Vault-профили.
Вот AWS IAM-политика для staging:
Ротируйте ключи
Это поможет избежать ситуации, когда после инцидента или утечки ключи не обновляются.
- Настройте автоматическую ротацию ключей в Secret Manager (например, AWS Secrets Manager поддерживает ротацию через Lambda).
- После инцидента сразу же ротируйте скомпрометированные ключи и пересоздавайте секреты.
- Логируйте доступ к секретам для аудита (например, через Vault Audit Logs).
Неправильная настройка health-checks в Kubernetes или других оркестраторах
Неправильная настройка readinessProbe и livenessProbe в Kubernetes — это, можно сказать, классика. Вы обновляете сервис, поды запускаются, но сразу же помечаются как unhealthy. Причина — неправильный readinessProbe или livenessProbe. Например, путь /healthz больше не существует, или проверка уходит в таймаут из-за долгой инициализации. В результате: контейнеры бесконечно рестартуются, сервис недоступен, кластер в панике.
Разделяйте назначение проб
readinessProbe проверяет, готов ли под принимать трафик, а livenessProbe — не завис ли он. Если их смешать, можно ждать сбой, например, трафик пойдет на не до конца инициализированный сервис.
- Используйте разные endpoints для проб. Например, /health для readinessProbe (готовность сервиса) и /alive для livenessProbe (проверка зависаний).
- Настройте readinessProbe так, чтобы она возвращала 200 только после полной инициализации (например, подключения к базе).
- Для livenessProbe проверяйте минимальную работоспособность (например, ответ сервера без проверки внешних зависимостей).
Учитывай время инициализации
Сервис может запускаться медленно, и слишком строгие таймауты приведут к сбоям.
- Установите initialDelaySeconds с запасом, чтобы учитывать время прогрева (например, загрузку кэша или подключение к базе).
- Настройте timeoutSeconds и periodSeconds так, чтобы проба не завершалась слишком быстро, но и не крутилась вечно.
- Используйте failureThreshold для нескольких попыток перед пометкой пода как unhealthy.
Вот пример для сервиса с долгим стартом:
Добавьте grace period
Он дает сервису время корректно завершиться перед рестартом.
- Установите terminationGracePeriodSeconds в манифесте Deployment, чтобы под мог завершить запросы перед остановкой.
- Настройте preStop хук, если нужно выполнить действия перед завершением.
Тестируйте на staging
Проблемы с пробами часто всплывают только в проде, если staging не идентичен.
- Убедитесь, что staging-окружение повторяет прод по конфигурации и нагрузке.
- Добавьте автоматические тесты в CI/CD для проверки endpoints (/health, /alive) перед деплоем.
- Симулируйте реальные сценарии (например, медленный старт или сбой зависимостей) на staging.
В CI/CD можно добавить:
Неправильная работа с конфигурациями через Helm или Kustomize
Представьте: обновили Helm-чарт, но в values.yaml остались старые переменные, которые ломают новые настройки. Или Kustomize патчит не тот ресурс, и манифесты применяются с ошибками. В итоге: поды падают, сервисы недоступны, и никто не знает что делать. Рассказываем, что с этим делать.
Валидируйте Helm-чарты перед деплоем
Так можно найти ошибки до применения манифестов.
- Используйте helm template или helm install –dry-run для рендеринга манифестов и их проверки.
- Включите schema validation для values.yaml с помощью JSON Schema (поддерживается Helm v3.6+).
- Проверяйте манифесты через kubeval или kubectl apply –dry-run=server для подтверждения соответствия Kubernetes API.
Тестируйте Kustomize-конфигурации
Kustomize может патчить не то, что вы ожидали, если селекторы или структура неправильные.
- Прогоняйте kustomize build для генерации итоговых манифестов и проверяйте их перед деплоем.
- Используйте kubectl apply –dry-run=server -k . для валидации в кластере.
- Проверяйте селекторы патчей в kustomization.yaml на точность (например, name и namespace).
Управляйте версиями и структурой
Несогласованность версий чартов или манифестов приводит к неожиданным изменениям.
- Фиксируйте версии Helm-чартов в Chart.yaml и используйте точные теги (например, 1.2.3, а не latest).
- Храните values.yaml отдельно для каждого окружения (values-staging.yaml, values-prod.yaml).
- Для Kustomize используйте базовые манифесты и патчи, разделённые по окружениям (например, overlays/staging, overlays/prod).
Документируйте и мониторьте
Без документации сложно понять, что изменилось, а без мониторинга — почему упало.
- Ведите CHANGELOG.md для Helm-чартов и Kustomize патчей, описывая изменения в структуре и значениях.
- Логируйте команды деплоя (helm upgrade –debug, kubectl apply -k .) для отладки.
- Настройте мониторинг статуса подов через Prometheus, чтобы сразу видеть сбои из-за ошибок конфигурации.
Вот пример получения подробного лога helm:
Нет политики управления версиями артефактов
С этой штукой шутить нельзя. Каждый новый билд заливается с тегом latest, и через неделю никто не помнит, какая именно версия работает в проде. А если что-то сломалось, откатиться просто невозможно: старый образ либо затерт в registry, либо его никто не пометил. На выходе — паника и хаос.
Используйте семантическое версионирование (semver) или уникальные теги
Так банально будет однозначность и отслеживаемость версий.
- Присваивайте образам теги по схеме semver (1.2.3), commit hash (abc1234) или временной метке (20250429-1345).
- Избегайте latest в продакшене — это бомба замедленного действия.
- В CI/CD автоматически генерируйте теги на основе версии приложения или Git commit.
Вот пример тег-образа:
docker build -t my-app:1.2.3 -t my-app:$(git rev-parse –short HEAD)
Фиксируйте версии в манифестах и пайплайнах
Immutable теги гарантируют, что деплой всегда использует ожидаемую версию.
- В Kubernetes манифестах указывайте точные теги вместо latest.
- Настройте CI/CD так, чтобы тег образа передавался в Helm или Kustomize как параметр.
- Используйте инструменты вроде helm upgrade с фиксированными версиями чартов.
Настройте retention policy для артефактов
Хранение старых образов позволяет откатиться к стабильной версии.
- В container registry (Docker Hub, AWS ECR, Harbor) настройте правила хранения, чтобы сохранять последние N версий или образы за последние X дней.
- Регулярно очищайте устаревшие артефакты, но сохраняйте критические версии (например, те, что в проде).
- Используйте теги для маркировки стабильных версий (например, prod-1.2.3).
Пример — AWS ECR lifecycle policу:
Автоматизируйте версионирование в CI/CD
- В CI/CD пайплайне генерируйте теги на основе Git тегов, commit hash или переменных окружения.
- Проверяйте, что образ с нужным тегом пушится в registry и используется в деплое.
- Добавьте шаг валидации манифестов, чтобы убедиться, что теги фиксированы.
Ошибки при деплое могут вылиться в серьезные проблемы для проекта. DevOps-инженеры не просто запускают пайплайны, а следят за жизненным циклом продукта — от инфраструктуры до мониторинга. Документируйте ошибки, создавайте чек-листы, автоматизируйте каждый шаг и учитесь на инцидентах. И главное — никогда не деплойте в пятницу вечером.
969 открытий8К показов