Описание структуры CI/CD шаблона и принципов его работы
Что уже есть и как это работает
Есть общий набор файлов в проекте generic/common-ci — туда вынесены общие jobs (build, deploy, linter, security-scan и т.д.).
В каждом репозитории с сервисом вы подключаете (с помощью include) нужные файлы из generic/common-ci. Локально в .gitlab-ci.yml можно переопределять/добавлять джобы.
Шаблон управляет поведением по веткам:
stage— автоматическийdeployв stage-namespacemaster— деплой в preprod-namespace, чаще вручную- теги
vX.Y.Z—deployв prod-namespace
Пайплайн использует переменные (CI/CD Variables) для передачи настроек: RELEASE_NAME, NAMESPACE, CHART_VERSION, DOCKERFILE_PATH и т.д.
Структура common-ci
Шаблоны CI/CD разбиты на модульные файлы:
| Файл | Назначение |
|---|---|
base.yaml |
Глобальные переменные и стадии |
docker.yaml |
Сборка Docker-образов |
helm.yaml |
Сборка Helm-чартов и деплой |
universal-pipeline.yaml |
Оркестратор пайплайна (объединяет всё) |
common-security-scan.yaml |
SAST, Secret-Detection, Trivy |
base.yaml — глобальные переменные
variables:
CR: cr.yandex/crp3ccidau046kdj8g9q
HELM_REGISTRY: oci://cr.yandex/crp3ccidau046kdj8g9q/charts
DOCKER_HOST: "tcp://docker:2375"
DOCKERFILE_PATH: "Dockerfile"
HELM_PATH: ".helm"
BUILD_ARGS: ""
HELM_SET_ARGS: ""
K8S_HUSTLER_BRANCH: ""
CI_TRIGGER_SOURCE: ""
ENABLE_BUILD_IMAGE: "true"
ENABLE_BUILD_CHART: "true"
ENABLE_DEPLOY: "true"
ENABLE_STATE_UPDATE: "false"
stages:
- lint
- test
- prebuild-secscan
- security
- build
- state-update
- deploy
docker.yaml — сборка образов
.base_docker:
image: docker:24.0.5
stage: build
before_script:
- echo ${SAREX_REGISTRY_KEY} | base64 -d | docker login --username json_key --password-stdin cr.yandex
- export DOCKER_BUILDKIT=1
script:
- docker build -f ${DOCKERFILE_PATH} ${BUILD_ARGS} -t ${IMAGE_NAME} .
- docker push ${IMAGE_NAME}
tags:
- build
helm.yaml — сборка чартов и деплой
.base_helm_build:
image: alpine/helm:3.17.0
stage: build
script:
- helm dependency update ${HELM_PATH}
- helm package ${HELM_PATH} --version ${CHART_VERSION} -d ./dist
- helm push dist/*.tgz ${HELM_REGISTRY}
.base_deploy:
image: alpine/helm:3.17.0
stage: deploy
variables:
IMAGE_NAME: ${CR}/${RELEASE_NAME}:${STAND}_${CI_COMMIT_SHORT_SHA}
script:
- helm dependency update ${HELM_PATH}
- helm template "${RELEASE_NAME}" ${HELM_PATH} -n "${NAMESPACE}" -f ${HELM_PATH}/values.yaml ${HELM_SET_ARGS}
- helm upgrade -i "${RELEASE_NAME}" ${HELM_PATH} --create-namespace --atomic -n "${NAMESPACE}" -f ${HELM_PATH}/values.yaml ${HELM_SET_ARGS}
Общая сборка pipeline (порядок событий)
- GitLab загружает
.gitlab-ci.ymlи разрешаетinclude - Все подключённые файлы мёрджатся в один итоговый YAML
- Выполняется
workflow.rules— задаются переменные для конкретной ветки/тега - Собирается список job'ов и запускается пайплайн
Стадии — порядок выполнения
lint → test → prebuild-secscan → security → build → state-update → deploy
Jobs проходят в этом порядке, если rules для них сработали.
Описание джоб
build
build:
extends: .base_docker
variables:
IMAGE_NAME: ${CR}/${RELEASE_NAME}:${STAND}_${CI_COMMIT_SHORT_SHA}
rules:
- if: '$ENABLE_BUILD_IMAGE == "false"'
when: never
- if: '$CI_COMMIT_BRANCH == "stage"'
- if: '$CI_COMMIT_BRANCH == "master"'
when: manual
- if: '$CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+/'
when: manual
Цель: собрать и запушить Docker-образ в registry.
build_chart
build_chart:
extends: .base_helm_build
rules:
- if: '$ENABLE_BUILD_CHART == "false"'
when: never
- if: '$CI_COMMIT_BRANCH == "stage"'
- if: '$CI_COMMIT_BRANCH == "master"'
when: manual
Цель: собрать и опубликовать Helm chart в HELM_REGISTRY.
deploy_stage / deploy_preprod / deploy_prod
deploy_stage:
extends: .base_deploy
needs:
- job: build
optional: true
- job: build_chart
optional: true
rules:
- if: '$CI_COMMIT_BRANCH == "stage" && $ENABLE_DEPLOY == "true"'
tags:
- stage
Цель: задеплоить чарт в нужный namespace через helm upgrade -i.
update_k8s_hustler_config
update_k8s_hustler_config:
stage: state-update
trigger:
project: "infra/k8s-hustler"
branch: "${K8S_HUSTLER_BRANCH}"
strategy: depend
rules:
- if: '$ENABLE_STATE_UPDATE != "true"'
when: never
Цель: автоматически обновлять state/конфигурацию инфраструктуры (отключено по умолчанию).
Как имя образа прокидывается в Helm
workflow.rulesзадаётSTAND,RELEASE_NAME,NAMESPACEиHELM_SET_ARGSbuildjob собираетIMAGE_NAME = ${CR}/${RELEASE_NAME}:${STAND}_${CI_COMMIT_SHORT_SHA}deployjob используетHELM_SET_ARGSдля передачи образа в чарт:--set universal-chart.services.main.image.name.stage=${IMAGE_NAME}- Helm применяет чарт с новым образом
Как и когда что запускается
Push в ветку stage
workflow.rulesсрабатывает на веткуstage- Устанавливаются переменные:
STAND=stage,NAMESPACE=... - Pipeline:
build→build_chart→deploy_stage
Merge в master
workflow.rulesсрабатывает на веткуmaster- Устанавливаются переменные:
STAND=preprod,NAMESPACE=... - Pipeline:
build→build_chart→deploy_preprod(manual)
Создание тега vX.Y.Z
workflow.rulesсрабатывает на тег- Устанавливаются переменные:
STAND=production,NAMESPACE=... - Pipeline:
build→build_chart→deploy_prod(manual)
Security scan
Файл common-security-scan.yaml включает SAST, Secret-Detection, semgrep, trivy.
trivy_repo_scanning:
stage: prebuild-secscan
image: aquasec/trivy
script:
- trivy fs .
rules:
- if: $TRIVY_REPO_SCAN_ENABLED
allow_failure: true
Сканы не ломают пайплайн по умолчанию (allow_failure: true). Запускаются только на merge_requests.