1. База: структура .gitlab-ci.yml
Эта тема закрывает базовые пробелы: как устроен .gitlab-ci.yml, что такое stages/jobs/tags, как правильно использовать variables, cache и artifacts, почему rules лучше чем only/except, и как собирать граф зависимостей через needs и dependencies. Везде — production‑ориентированные комментарии и короткие примеры кода.
Определения (термины GitLab CI/CD)
| Термин | Определение |
|---|---|
| Pipeline | Граф/набор job’ов, который запускается по событию (push/MR/schedule). |
| Stage | Шаг пайплайна; job’ы внутри stage стартуют параллельно, стадии идут по порядку. |
| Job | Единица работы в .gitlab-ci.yml (скрипт, зависимости, окружение, артефакты). |
| Runner | Исполнитель job’ов (сервер/агент), который выполняет .gitlab-ci.yml в вашей инфраструктуре. |
| Shared runner / Specific runner | Общий runner (shared) vs выделенный runner под конкретную команду/проект. |
| Tag | Метки runner’а. Job может требовать runner по tags:. |
| Variables | Параметры пайплайна (global/job-level/secret vars). |
| cache | Кэш для повторного использования между пайплайнами/задачами (ускоряет сборку). |
| artifacts | Результаты job’а для последующих стадий/скачиваний (например, build outputs, test reports). |
| rules | Условия запуска job’а (лучший способ, чем only/except). |
| needs | Зависимости “раньше по графу”: позволяет стартовать job до завершения всей стадии. |
| dependencies | Какие artifacts из прошлых job’ов нужно скачать в текущий job. |
Продакшн‑скелет пайплайна: lint → build → test → deploy
Ниже — пример, который обычно хорошо проходит в review и в эксплуатации.
# .gitlab-ci.yml
stages:
- lint
- build
- test
- deploy
variables:
# В production избегайте hardcode паролей — используйте GitLab CI/CD Variables (masked/protected).
DOCKER_TLS_CERTDIR: "/certs"
lint:
stage: lint
image: python:3.12-slim
script:
- pip install -r requirements.txt
- ruff check .
rules:
# Запускаем на merge requests и на main.
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
build:
stage: build
image: docker:27
services:
- name: docker:27-dind
command: ["--mtu=1460"] # пример настройки; подстройте под вашу сеть при необходимости
variables:
DOCKER_HOST: "tcp://docker:2375"
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
script:
# Детерминированный тег образа.
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
cache:
# Кэш для зависимостей (пример).
key: "pip-cache"
paths:
- .cache/pip
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
artifacts:
when: on_success
expire_in: 1 week
paths:
- build-manifest.json
test:
stage: test
image: python:3.12-slim
needs:
# Ускорение: тесты стартуют сразу после build, без ожидания всей стадии.
- job: build
artifacts: true
script:
- pip install -r requirements.txt
- pytest -q
artifacts:
when: always
expire_in: 2 weeks
reports:
junit: report.xml
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
deploy:
stage: deploy
image: bitnami/kubectl:1.30
needs:
- job: test
artifacts: false
script:
- kubectl apply -f k8s/
- kubectl -n production rollout status deployment/myapp --timeout=180s
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: on_success
Production‑дисциплина:
- Детерминированные теги образов:
:$CI_COMMIT_SHA. - rules вместо
only/exceptдают читабельную логику. - needs ускоряет пайплайн.
- artifacts — только то, что реально нужно дальше.
rules: управление запуском job’ов
Пример “must-have” шаблона:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: on_success
- if: '$CI_COMMIT_BRANCH == "main"'
- when: never
Best practice:
- добавляйте
when: neverкак страховку.
cache vs artifacts
cache— ускорение повторных запусков.artifacts— перенос результатов (test reports, build outputs) в последующие job’ы.
Антипаттерн:
- хранить большие артефакты в cache (растёт время и нестабильность).
needs и dependencies
test:
stage: test
needs:
- job: build
artifacts: true
dependencies:
- build
Best practice:
- используйте
needsдля скорости, - используйте
dependencies/artifacts: trueдля контроля “что скачать”.
Runners и tags
build:
tags:
- docker
- linux
Best practice:
- договориться о тегаx внутри команды,
- использовать выделенные runner’ы для привилегированных задач.
Variables и секреты
Best practice:
- секреты — только в GitLab UI (masked/protected),
- не выводить их в логи.
Пример job-level переменной:
test:
variables:
PYTHONWARNINGS: "error"
script:
- pytest -q
Production checklist
- Разделяйте job’ы по смыслам (lint/test/deploy).
- Начинайте с быстрых проверок (lint) и тестов.
- Минимизируйте артефакты и держите их срок жизни разумным.
- Используйте
rulesи детерминированные теги. - Держите runner’ы и лимиты под контролем.
Дополнительные материалы
1. База: структура .gitlab-ci.yml
Эта тема закрывает базовые пробелы: как устроен .gitlab-ci.yml, что такое stages/jobs/tags, как правильно использовать variables, cache и artifacts, почему rules лучше чем only/except, и как собирать граф зависимостей через needs и dependencies. Везде — production‑ориентированные комментарии и короткие примеры кода.
Определения (термины GitLab CI/CD)
| Термин | Определение |
|---|---|
| Pipeline | Граф/набор job’ов, который запускается по событию (push/MR/schedule). |
| Stage | Шаг пайплайна; job’ы внутри stage стартуют параллельно, стадии идут по порядку. |
| Job | Единица работы в .gitlab-ci.yml (скрипт, зависимости, окружение, артефакты). |
| Runner | Исполнитель job’ов (сервер/агент), который выполняет .gitlab-ci.yml в вашей инфраструктуре. |
| Shared runner / Specific runner | Общий runner (shared) vs выделенный runner под конкретную команду/проект. |
| Tag | Метки runner’а. Job может требовать runner по tags:. |
| Variables | Параметры пайплайна (global/job-level/secret vars). |
| cache | Кэш для повторного использования между пайплайнами/задачами (ускоряет сборку). |
| artifacts | Результаты job’а для последующих стадий/скачиваний (например, build outputs, test reports). |
| rules | Условия запуска job’а (лучший способ, чем only/except). |
| needs | Зависимости “раньше по графу”: позволяет стартовать job до завершения всей стадии. |
| dependencies | Какие artifacts из прошлых job’ов нужно скачать в текущий job. |
Продакшн‑скелет пайплайна: lint → build → test → deploy
Ниже — пример, который обычно хорошо проходит в review и в эксплуатации.
# .gitlab-ci.yml
stages:
- lint
- build
- test
- deploy
variables:
# В production избегайте hardcode паролей — используйте GitLab CI/CD Variables (masked/protected).
DOCKER_TLS_CERTDIR: "/certs"
lint:
stage: lint
image: python:3.12-slim
script:
- pip install -r requirements.txt
- ruff check .
rules:
# Запускаем на merge requests и на main.
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
build:
stage: build
image: docker:27
services:
- name: docker:27-dind
command: ["--mtu=1460"] # пример настройки; подстройте под вашу сеть при необходимости
variables:
# Docker in Docker требует прав; на production обычно настраивают безопаснее (kaniko/buildkit).
DOCKER_HOST: "tcp://docker:2375"
before_script:
# Пример: логин в registry через переменные окружения GitLab.
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
script:
# Используем tag по commit sha — детерминированный build.
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
cache:
# Кэш для зависимостей (пример). Подходит, если у вас есть локальные директории, которые можно кэшировать.
key: "pip-cache"
paths:
- .cache/pip
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
artifacts:
# Для build в виде кэша обычно не надо artifacts,
# но можно сохранять metadata/manifest.
when: on_success
expire_in: 1 week
paths:
- build-manifest.json
test:
stage: test
image: python:3.12-slim
needs:
# Production best practice: стартовать тесты как только готов build (не ждать end of stage).
- job: build
artifacts: true
script:
- pip install -r requirements.txt
- pytest -q
artifacts:
# test reports полезны для CI/CD и анализа качества.
when: always
expire_in: 2 weeks
reports:
junit: report.xml
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
deploy:
stage: deploy
image: bitnami/kubectl:1.30
needs:
- job: test
artifacts: false
script:
# Пример: деплой по sha. Конкретика зависит от вашего процесса (Helm/Kustomize/Argo).
- kubectl apply -f k8s/
- kubectl -n production rollout status deployment/myapp --timeout=180s
rules:
# Обычно deploy только на main и только когда pipeline защитила ветку (protected variables).
- if: '$CI_COMMIT_BRANCH == "main"'
when: on_success
Комментарий к production‑дисциплине:
- Детерминированные теги образов:
:$CI_COMMIT_SHA. - rules вместо
only/exceptдают читабельную логику. - needs ускоряет пайплайн.
- artifacts — только то, что реально нужно дальше (меньше шума и быстрее загрузки).
rules: лучший способ управлять запуском job’ов
Основные паттерны:
rules:
# 1) Merge requests
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: on_success
# 2) Только main
- if: '$CI_COMMIT_BRANCH == "main"'
# 3) Остальное — не запускать
- when: never
Best practice:
- Прописывайте явно
when: neverкак “страховку”, чтобы не запускать job случайно.
cache vs artifacts: не перепутайте
cache— ускорение (повторное использование между job’ами/пайплайнами).artifacts— перенос результата из job’а в job (например, test reports, build outputs).
Типовой антипаттерн:
- пытаться хранить большие артефакты в cache (получите slow downloads и нестабильность)
needs и dependencies: граф и где брать данные
Если ваш job зависит от артефактов:
test:
stage: test
needs:
- job: build
artifacts: true
dependencies:
# Если вы используете artifacts upload в build, перечисляйте, от кого качать.
- build
Best practice:
- использовать
needsдля ускорения запуска, - использовать
dependencies(илиartifacts: trueвneeds) чтобы контролировать “что именно скачать”.
Runners и tags
Как подключать job к нужному runner’у:
build:
tags:
- docker
- linux
Production best practice:
- не разбрасывать теги без соглашения,
- использовать специфичные runner’ы для “опасных” задач (dind/privileged),
- документировать, какой runner что делает.
Variables: где хранить секреты
Best practice:
- секреты — только в GitLab UI (masked/protected),
- не пушить в репозиторий (и не выводить в лог).
Мини‑пример job-level переменной:
test:
variables:
PYTHONWARNINGS: "error"
script:
- pytest -q
Производственный checklist
- Избегайте “сложной магии” в
.gitlab-ci.yml: один смысл на job. - Пишите быстрые “lint” и “test” job’ы в начале.
- Теги runner’ов и ресурсы (CPU/RAM) держите под контролем.
- Сводите артефакты к необходимому минимуму.
- Обязательно используйте
rulesи “умные” условия запуска. - Делайте теги образов детерминированными (sha/tag) и откатывайте через git sha.