Структурирование YAML-конфигураций, DRY-принципы, читаемость и поддержка.
Правильная организация YAML-конфигураций критична для поддерживаемости CI/CD пайплайнов. Изучите паттерны структурирования, DRY-принципы и читаемость.
# Комментарии начинаются с #
key: value
# Строки могут быть без кавычек
name: My Pipeline
# Или в кавычках для специальных символов
message: "Hello: World"
# Числа и булевы значения
count: 42
enabled: true
# Списки (arrays)
items:
- first
- second
- third
# Или inline синтаксис
items: [first, second, third]
# Объекты (mappings)
config:
key1: value1
key2: value2Literal block (|) — сохраняет переносы:
script: |
npm ci
npm run build
npm test
# Эквивалентно: "npm ci\nnpm run build\nnpm test\n"Folded block (>) — объединяет строки:
description: >
This is a long description
that will be folded into
a single line.
# Эквивалентно: "This is a long description that will be folded into a single line."Для скриптов CI/CD используйте | — сохраняет структуру команд.
Объявление и использование:
# Объявление якоря с &
.base: &base_config
image: node:20-alpine
before_script:
- npm ci
tags:
- docker
# Использование якоря с *
lint:
<<: *base_config
script:
- npm run lint
test:
<<: *base_config
script:
- npm testMerge key <<: объединяет поля якоря с текущим блоком.
.base: &base
image: node:20-alpine
variables:
NODE_ENV: development
LOG_LEVEL: info
script:
- echo "Base"
child:
<<: *base
variables:
NODE_ENV: production # Переопределяет
DEBUG: true # Добавляет новое
script:
- echo "Child" # ПереопределяетВажно: При использовании <<: вложенные объекты (как variables) полностью переопределяются, а не merge.
# Общие настройки для всех jobs
.defaults: &defaults
interruptible: true
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
# Специфичные якоря
.node_defaults: &node_defaults
<<: *defaults
image: node:20-alpine
before_script:
- npm ci
.python_defaults: &python_defaults
<<: *defaults
image: python:3.11-slim
before_script:
- pip install -r requirements.txt
lint:
<<: *node_defaults
script:
- npm run lint
test:
<<: *node_defaults
script:
- npm test
build:
<<: *python_defaults
script:
- python setup.py buildJobs с именами, начинающимися с ., не добавляются в пайплайн:
# Скрытый шаблон — не выполняется
.base_job:
image: node:20-alpine
interruptible: true
retry: 2
tags:
- docker
# Реальный job — выполняется
test:
extends: .base_job
script:
- npm test# Базовый шаблон
.test_template:
image: node:20-alpine
before_script:
- npm ci
script:
- npm test
artifacts:
reports:
junit: junit.xml
# Конкретные тесты
unit:
extends: .test_template
script:
- npm run test:unit
artifacts:
reports:
junit: unit-junit.xml
integration:
extends: .test_template
script:
- npm run test:integration
artifacts:
reports:
junit: integration-junit.xml
e2e:
extends: .test_template
script:
- npm run test:e2e
artifacts:
reports:
junit: e2e-junit.xml.base:
interruptible: true
tags:
- docker
.node:
extends: .base
image: node:20-alpine
before_script:
- npm ci
.test:
extends: .node
script:
- npm test
# Множественное наследование
unit-test:
extends: [.test, .custom_rules]
script:
- npm run test:unitПри конфликтах последний в списке имеет приоритет.
Структура проекта:
.gitlab-ci.yml
.gitlab/
├── templates/
│ ├── base.yml
│ ├── node.yml
│ └── python.yml
├── jobs/
│ ├── build.yml
│ ├── test.yml
│ └── deploy.yml
└── workflows/
├── feature-branch.yml
└── main.yml
Основной файл:
include:
- local: '.gitlab/templates/base.yml'
- local: '.gitlab/templates/node.yml'
- local: '.gitlab/jobs/build.yml'
- local: '.gitlab/jobs/test.yml'
- local: '.gitlab/jobs/deploy.yml'
stages:
- build
- test
- deploy
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCHШаблон .gitlab/templates/node.yml:
.node_base:
image: node:20-alpine
before_script:
- npm ci
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
interruptible: trueJob .gitlab/jobs/build.yml:
include:
- local: '.gitlab/templates/node.yml'
build:
extends: .node_base
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 week# Глобальные переменные (все jobs)
variables:
PROJECT_NAME: "my-app"
NODE_VERSION: "20"
job1:
# Переменные job (переопределяют глобальные)
variables:
NODE_VERSION: "18"
script:
- echo $PROJECT_NAME # my-app
- echo $NODE_VERSION # 18
job2:
script:
- echo $PROJECT_NAME # my-app
- echo $NODE_VERSION # 20variables:
DOCKER_REGISTRY: registry.example.com
deploy_staging:
stage: deploy
variables:
ENVIRONMENT: staging
DEPLOY_URL: https://staging.example.com
script:
- ./deploy.sh $ENVIRONMENT
deploy_production:
stage: deploy
variables:
ENVIRONMENT: production
DEPLOY_URL: https://example.com
script:
- ./deploy.sh $ENVIRONMENTdeploy:
stage: deploy
variables:
ENVIRONMENT: development # Default
script:
- ./deploy.sh $ENVIRONMENT
rules:
- if: $CI_COMMIT_BRANCH == "develop"
variables:
ENVIRONMENT: staging
- if: $CI_COMMIT_BRANCH == "main"
variables:
ENVIRONMENT: productionХорошо:
lint:
script:
- npm run lint
test-unit:
script:
- npm run test:unit
test-integration:
script:
- npm run test:integration
build-frontend:
script:
- npm run build:frontend
deploy-staging:
script:
- ./deploy.sh stagingПлохо:
job1:
script:
- npm run lint
test2:
script:
- npm run test:unit
build_job_final_v2:
script:
- npm run build# === Build Jobs ===
build-frontend:
stage: build
script:
- cd frontend && npm run build
build-backend:
stage: build
script:
- cd backend && npm run build
# === Test Jobs ===
test-frontend:
stage: test
script:
- cd frontend && npm test
test-backend:
stage: test
script:
- cd backend && npm test
# === Deploy Jobs ===
deploy-staging:
stage: deploy
script:
- ./deploy.sh staging
deploy-production:
stage: deploy
script:
- ./deploy.sh production# Pipeline для сборки и деплоя приложения
# Автор: DevOps Team
# Последнее обновление: 2026-03-20
stages:
- build # Сборка артефактов
- test # Запуск тестов
- deploy # Деплой на окружения
# === Build Stage ===
build:
stage: build
# Используем Node.js 20 для совместимости
image: node:20-alpine
script:
- npm ci
- npm run build
artifacts:
# Сохраняем dist для последующих stages
paths:
- dist/
expire_in: 1 week# Глобальный cache для всех jobs
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .npm/
build:
script:
- npm ci # Использует кэш
cache:
policy: pull-push # По умолчанию
test:
script:
- npm test
cache:
policy: pull # Только чтение кэша# Параллельный запуск тестов
test:
stage: test
script:
- npm test
parallel:
matrix:
- NODE_VERSION: [18, 20, 22]
- OS: [ubuntu-latest, windows-latest].defaults:
interruptible: true # Можно прервать новый пайплайн
timeout: 30m # Максимальное время job
long-test:
extends: .defaults
script:
- npm run test:slow# === Templates ===
.base_job: &base_job
interruptible: true
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
tags:
- docker
.node_job: &node_job
<<: *base_job
image: node:20-alpine
before_script:
- npm ci
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
.test_job: &test_job
<<: *node_job
script:
- npm test
artifacts:
reports:
junit: junit.xml
expire_in: 1 week
# === Stages ===
stages:
- lint
- build
- test
- deploy
# === Jobs ===
lint:
<<: *node_job
stage: lint
script:
- npm run lint
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH
build:
<<: *node_job
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 week
rules:
- if: $CI_COMMIT_BRANCH
test-unit:
<<: *test_job
stage: test
script:
- npm run test:unit
artifacts:
reports:
junit: unit-junit.xml
needs:
- build
test-integration:
<<: *test_job
stage: test
script:
- npm run test:integration
artifacts:
reports:
junit: integration-junit.xml
needs:
- build
deploy-staging:
<<: *base_job
stage: deploy
image: alpine:latest
script:
- apk add --no-cache curl
- ./deploy.sh staging
environment:
name: staging
url: https://staging.example.com
needs:
- test-unit
- test-integration
rules:
- if: $CI_COMMIT_BRANCH == "develop"
deploy-production:
<<: *base_job
stage: deploy
image: alpine:latest
script:
- apk add --no-cache curl
- ./deploy.sh production
environment:
name: production
url: https://example.com
needs:
- test-unit
- test-integration
rules:
- if: $CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/
when: manual
# === Workflow Rules ===
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH
- if: $CI_COMMIT_TAG&, *, <<:) для переиспользования блоков.name:) как шаблоны в GitLab CI| для скриптов, > для текстаВопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.