Как ты считаешь, правильно ли в одном workflow создавать сборку тестирование и выкладку имиджа куда-то в хранилище артефактов и плюс там же добавлять шаги для деплоя в какие-то среды
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Отличный и очень практичный вопрос, который касается самой сути философии CI/CD и организации конвейеров. Короткий ответ: нет, это не лучшая практика. Объединять сборку, тестирование, публикацию артефакта и деплой в среду в одном воркфлоу (job/pipeline) — это антипаттерн, который нарушает ключевые принципы современной DevOps.
Давайте разберем, почему это проблема и как должно выглядеть правильное решение.
Проблемы монолитного воркфлоу "от кода до продакшена"
1. Нарушение принципа единой ответственности (Single Responsibility Principle)
Один воркфлоу пытается делать всё: CI (Continuous Integration) и CD (Continuous Delivery/Deployment). Это усложняет его понимание, отладку и поддержку. Если падает деплой в staging, это блокирует возможность сборки нового артефакта для других разработчиков.
2. Слабая изоляция и безопасность
В таком воркфлоу для сборки артефакта (требующего доступ к коду, репозиторию) используются те же учетные данные (credentials, secrets), что и для деплоя в среды (требующим доступ к кластерам Kubernetes, облачным аккаунтам). Это небезопасно. Утечка секретов на этапе сборки автоматически открывает доступ к инфраструктуре.
3. Отсутствие контроля промоушена артефакта
Имидж (Docker image) или другой артефакт, созданный в таком конвейере, сразу же "улетает" в какую-то среду. У вас нет возможности:
- Протестировать один и тот же, неизменный бинарный артефакт в разных средах (dev -> staging -> prod).
- Остановить промоушен для ручного подтверждения (approval) или дополнительных проверок.
- Откатиться к предыдущей версии артефакта, просто развернув его из хранилища.
Это противоречит идее "Build once, deploy everywhere".
4. Проблемы с триггерами и параллелизацией
Воркфлоу, запускаемый при каждом пулл-реквесте или коммите в main, будет пытаться деплоить в среду при каждом изменении. Это создает хаос. Деплой в прод (production) должен быть отдельным, осознанным событием, а не побочным эффектом от мерджа кода.
Рекомендуемая архитектура: Разделение CI и CD Pipelines
Правильный подход — разделить процесс на два (или более) логически независимых конвейера.
Конвейер CI (Continuous Integration)
Цель: Проверить код, собрать артефакт и опубликовать его в реестр артефактов (Artifact Registry).
Триггер: Пулл-реквест (PR) или коммит в основную ветку (например, main/master).
Что делает:
- Линтинг кода и проверка формата.
- Сборка (build) и модульное тестирование (unit tests).
- Создание Docker-образа, подписанного тегом (например,
commit-hashилиbranch-name). - Запуск интеграционных тестов (если возможно).
- Публикация образа в реестр (Harbor, ECR, GCR, Docker Hub, Nexus).
- НИКАКОГО ДЕПЛОЯ. Артефакт готов и ждет в хранилище.
Пример фрагмента такого воркфлоу в GitHub Actions:
name: CI Build and Push
on: [push, pull_request]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker image
run: |
docker build -t my-app:${{ github.sha }} .
- name: Run unit tests
run: |
docker run my-app:${{ github.sha }} npm test
- name: Push to Artifact Registry
run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
docker push my-app:${{ github.sha }}
Конвейер CD (Continuous Delivery/Deployment)
Цель: Взять конкретный, уже существующий артефакт из реестра и развернуть его в целевой среде. Триггер: Отдельное событие. Это может быть:
- Запуск вручную с указанием тега нужного образа.
- Создание Git-тега (release).
- Запуск по расписанию.
- Успешное завершение CI-NIGHTLY пайплайна.
- Нажатие кнопки "Promote to Staging/Prod" в инструменте (например, ArgoCD UI). Что делает:
- Вытягивает (pull) готовый образ из реестра по заданному тегу (например,
v1.2.3). - Настраивает параметры для конкретной среды (config maps, secrets).
- Выполняет деплой в среду (например, обновляет Deployment в Kubernetes).
- Запускает smoke-тесты или health-checks после деплоя.
Пример фрагмента для деплоя в staging в GitLab CI (использующий образ, собранный ранее):
deploy-to-staging:
stage: deploy
environment: staging
only:
- tags # Запускается только при создании тега
script:
- echo "Deploying image $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG to staging"
# Используем готовый образ, а не собираем заново!
- kubectl set image deployment/my-app my-app=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG -n staging
- kubectl rollout status deployment/my-app -n staging
Продвинутый паттерн: GitOps
Современным стандартом де-факто становится GitOps. В этой модели:
- CI-Master Pipeline только собирает артефакт и пушит его в реестр. Его последним шагом является обновление конфигурационного репозитория (Config Repo). Например, он изменяет
kustomization.yamlили Helmvalues.yaml, указывая на новый тег образа (app.version: v1.2.3) и создает Pull Request. - Отдельный GitOps-Pipeline или Оператор (например, ArgoCD, Flux) мониторит этот конфигурационный репозиторий. Как только изменения мерджатся в его основную ветку, оператор автоматически и независимо синхронизирует состояние кластера Kubernetes с желаемым, описанным в Git. Деплой становится следствием изменения "источника истины" (Git), а не прямого выполнения
kubectlиз CI воркфлоу.
Итог: Разделение сборки и деплоя — это не просто "так модно". Это фундаментальное улучшение, которое дает безопасность, стабильность, контроль над процессом и возможность реализовать сложные стратегии развертывания (blue-green, canary). Ваш воркфлоу должен производить артефакт, а деплоить его должна отдельная, управляемая процессом, система.