← все статьи
28 апреля 2026· 11 мин чтения· #cicd · #gitlab

CI/CD на GitLab: от коммита до продакшена

Как выглядит путь Java/Spring-сервиса от git push до прода — и почему ручные релизы мы вынесли из процесса полностью.

Хороший пайплайн незаметен: разработчик делает git push, а через несколько минут изменение уже в проде — проверенное, протестированное и откатываемое одной командой. Расскажу, как мы выстроили этот путь на GitLab CI/CD для Java/Spring-сервисов в банковской среде, где цена ошибки высока.

Этапы пайплайна

Мы держим единый шаблон .gitlab-ci.yml с четырьмя смысловыми стадиями:

stages:
  - build      # компиляция и unit-тесты
  - verify     # статанализ, проверки безопасности
  - package    # сборка образа и push в Harbor
  - deploy     # helm upgrade в нужное окружение

Build: быстро и с кэшем

Java-сборка медленная, если не кэшировать зависимости. Локальный репозиторий Maven кэшируется между запусками, а артефакты подтягиваются из внутреннего Nexus — это и быстрее, и не зависит от внешних реестров.

build:
  stage: build
  image: maven:3.9-eclipse-temurin-21
  cache:
    key: "$CI_PROJECT_NAME"
    paths: [ .m2/repository ]
  script:
    - mvn -s ci/settings.xml -B clean test package
  artifacts:
    paths: [ target/*.jar ]
    expire_in: 1 day

Verify: качество и безопасность как gate

На этой стадии — статический анализ, проверка зависимостей на известные уязвимости и сканирование кода. Принцип простой: если gate красный, дальше пайплайн не идёт. Безопасность не должна быть отдельным ручным этапом «когда-нибудь потом» — она встроена в DevSecOps-конвейер.

Package: образ в Harbor

Образ собираем многослойно (multi-stage Dockerfile), тегируем по SHA коммита и пушим в приватный реестр Harbor, где включено сканирование образов на уязвимости. Тег по SHA даёт иммутабельность: один коммит — один образ, никаких «latest, который вчера был другим».

package:
  stage: package
  script:
    - docker build -t $HARBOR/$APP:$CI_COMMIT_SHORT_SHA .
    - docker push $HARBOR/$APP:$CI_COMMIT_SHORT_SHA
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

Деплой через Helm — и почему без ручных рук

Деплой — это helm upgrade с values для конкретного окружения. В стейдж выкатываемся автоматически на каждый коммит в main; в прод — той же командой, но с ручным подтверждением (when: manual) и обязательным ревью.

deploy:prod:
  stage: deploy
  script:
    - helm upgrade --install $APP ./charts/$APP
        --namespace prod
        --set image.tag=$CI_COMMIT_SHORT_SHA
        --atomic --timeout 5m
  environment: { name: production }
  when: manual
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

Флаг --atomic здесь ключевой: если выкатка не прошла health-check за таймаут, Helm автоматически откатывается на предыдущий релиз. Откат — это не аварийная процедура, а штатная часть процесса.

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

Git Flow и управление релизами

Ветвление — это тоже часть CI/CD. Мы используем понятную модель: feature-ветки → MR с обязательным ревью и зелёным пайплайном → main. Релизы тегируются семантически, а changelog генерируется из истории коммитов. Это даёт прозрачность: по любому тегу видно, что именно поехало в прод.

Что это дало на практике

Итог

Хороший CI/CD — это не про «модно автоматизировать». Это про то, чтобы убрать человека из рутинных и опасных шагов, оставив ему ревью и принятие решений. Чем скучнее проходит релиз — тем лучше работает пайплайн.

GitLab CI/CDMavenHarbor HelmKubernetesDevSecOps