← Назад к вопросам

Как разделял элементы CI/CD в Jenkins

2.3 Middle🔥 202 комментариев
#CI/CD и автоматизация

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Отличный вопрос, который напрямую касается философии построения надежных и эффективных конвейеров в Jenkins. Разделение CI (Continuous Integration) и CD (Continuous Delivery/Deployment) — это ключевая практика, которая повышает стабильность, безопасность и управляемость процесса. В Jenkins я реализовывал это разделение несколькими фундаментальными способами, комбинируя их в зависимости от зрелости команды и требований проекта.

1. Основной принцип: Разделение на стадии (Stages) внутри одного Pipeline (Jenkinsfile)

Это самый распространенный и базовый подход. Мы явно разделяем этапы CI и CD в декларативном или скриптовом Pipeline с помощью директив stage. CI-стадии выполняются автоматически, CD-стадии — часто с мануальным одобрением.

pipeline {
    agent any
    stages {
        // ========== CI БЛОК ==========
        stage('Checkout') {
            steps { git '...' }
        }
        stage('Build & Unit Test') {
            steps { sh 'mvn clean package' }
        }
        stage('Static Analysis (SonarQube)') {
            steps { sh 'mvn sonar:sonar' }
        }
        stage('Build Docker Image') {
            steps { sh 'docker build -t myapp:${BUILD_NUMBER} .' }
        }
        stage('Push to Registry') {
            steps { sh 'docker push myapp:${BUILD_NUMBER}' }
        }

        // ========== ТОЧКА РАЗДЕЛЕНИЯ CI/CD ==========
        // Часто здесь артефакт (образ, пакет) уже сохранен в реестре.

        // ========== CD БЛОК ==========
        // Эта стадия требует ручного подтверждения (input).
        stage('Deploy to Staging') {
            input {
                message "Развернуть билд ${BUILD_NUMBER} в Staging?"
            }
            steps {
                sh "kubectl set image deployment/myapp myapp=myapp:${BUILD_NUMBER} -n staging"
            }
        }
        stage('Integration Tests (on Staging)') {
            steps { sh 'run-integration-tests.sh' }
        }
        stage('Deploy to Production') {
            input {
                message "Все тесты пройдены. Развернуть в Production?"
            }
            steps {
                sh "kubectl set image deployment/myapp myapp=myapp:${BUILD_NUMBER} -n production"
                // Или использовать Helm, Ansible, Terraform
            }
        }
    }
}

Ключевой момент: Здесь разделение логическое и организационное. Все выполняется в рамках одного задания Jenkins, но ручной input выступает четким барьером между интеграцией и доставкой.

2. Архитектурное разделение: Триггеринг отдельного CD-Pipeline

Более продвинутый и чистый подход. CI-Pipeline заканчивается созданием и публикацией неизменяемого артефакта (например, Docker-образа с тегом) и его промоутом (отметкой как готового к развертыванию). Затем он триггерит или создает задание для отдельного CD-Pipeline.

Как это работает:

  • CI-задание (Jenkinsfile.ci): Собирает, тестирует, создает образ myapp:1.2.3-b123, запускает уязвимости. В конце, если все успешно, он помечает этот конкретный образ как "релизный" (например, делает docker tag myapp:1.2.3-b123 myapp:1.2.3-stable и пушит) или записывает метаданные в средство управления артефактами (Nexus) или просто триггерит CD-задание, передавая ему точный тег образа.
  • CD-задание (Jenkinsfile.cd): Это отдельный Pipeline. Он получает на вход только тег стабильного образа. Его единственная ответственность — развертывание этого конкретного артефакта в различные среды. Он не содержит шагов сборки или тестирования.

Преимущества:

  • Повторяемость: Можно запускать развертывание одного и того же артефакта многократно (например, для отката).
  • Безопасность: CD-заданию могут быть выданы отдельные, более широкие учетные данные для доступа к production-средам, в то время как CI-задание работает с минимальными привилегиями.
  • Гибкость: Можно настроить различные CD-конвейеры для разных сред или типов развертывания (canary, blue-green), все из одной точки входа — стабильного артефакта.

3. Использование "Промоута" или "Релизных" шагов с внешними системами

Иногда само развертывание выносится за пределы Jenkins (в специализированные инструменты вроде Spinnaker, ArgoCD, Flux). Тогда роль Jenkins сводится к CI и промоуту артефакта в цепочке поставок.

  • Jenkins создает образ и помещает его в реестр как myapp:1.2.3-candidate.
  • После прохождения всех этапов CI Jenkins обновляет конфигурацию для инструмента CD (например, меняет образ в манифесте Kubernetes в Git-репозитории "гитопс" с ...-candidate на ...-stable или создает Pull Request).
  • Инструмент GitOps (ArgoCD) автоматически обнаруживает изменение в репозитории и выполняет синхронизацию, разворачивая новый образ в кластере.

В этом случае разделение абсолютное: Jenkins — это CI-движок, а CD осуществляется другим, более подходящим для этой задачи инструментом. Jenkins лишь "проталкивает" артефакт по конвейеру.

4. Организация через Folders и Shared Libraries

Для управления множеством проектов я разделял CI и CD на уровне организации Jenkins:

  • Папка ci-pipelines: Содержит задания, отвечающие только за сборку, тестирование и создание артефактов.
  • Папка cd-pipelines: Содержит задания, отвечающие только за развертывание. Они используют Shared Libraries — общие библиотеки кода на Groovy, где вынесена вся логика развертывания (вызовы kubectl, Terraform, взаимодействие с облачными API).
  • Shared Library становится единой точкой истины для CD-логики, что обеспечивает согласованность и упрощает обновления.

Резюме и лучшие практики

На практике я чаще всего комбинировал подходы 1 и 2. Основные правила, которые я применял для четкого разделения:

  1. CI-фаза должна создавать один единственный, неизменяемый, промотируемый артефакт. Если вы разворачиваете что-то иное, чем было протестировано, процесс нарушен.
  2. Точка перехода от CI к CD — это "релизный артефакт". Его идентификатор (тег, хэш, номер сборки) должен явно передаваться в CD-процесс.
  3. CD-процесс должен быть идемпотентным и безопасным. Его запуск на одном и том же артефакте должен давать предсказуемый результат, а доступ к production-средам должен быть строго контролируемым (через input, механизмы одобрения или отдельные учетные данные).
  4. Информация о среде (config) отделяется от артефакта. Образ приложения не содержит паролей или endpoint'ов для конкретного кластера. Они инжектируются во время CD-фазы через ConfigMaps, Secrets или переменные окружения.

Таким образом, разделение в Jenkins — это не просто "этапы в одном файле", а прежде всего архитектурное решение, направленное на создание надежного, управляемого и безопасного конвейера доставки программного обеспечения.