Якоря и псевдонимы YAML: паттерны DRY-конфигурации
Повторение одной и той же конфигурации в нескольких разделах YAML-файла нарушает принцип DRY (Don't Repeat Yourself) и создаёт головную боль при поддержке. Якоря и псевдонимы YAML решают эту проблему, позволяя определить значение один раз и ссылаться на него многократно.
Базовый синтаксис
Якорь (&): помечает значение для повторного использования
Псевдоним (*): ссылается на помеченное якорем значение
# Define an anchor
defaults: &default_settings
timeout: 30
retries: 3
log_level: info
# Use aliases to reference it
development:
<<: *default_settings
log_level: debug
production:
<<: *default_settings
retries: 5
Ключ слияния << включает все пары ключ-значение из указанного якоря. Свойства, определённые после слияния, переопределяют значения якоря.
Результат после разрешения:
development:
timeout: 30
retries: 3
log_level: debug # overridden
production:
timeout: 30
retries: 5 # overridden
log_level: info
Типы якорей
Скалярные якоря
Повторное использование одного значения:
max_connections: &max_conn 100
database:
pool_size: *max_conn
cache:
pool_size: *max_conn
Якоря последовательностей
Повторное использование целых списков:
common_ports: &ports
- 80
- 443
web_server:
ports: *ports
load_balancer:
ports: *ports
Якоря отображений
Повторное использование целых объектов (наиболее распространённый паттерн):
logging: &log_config
driver: json-file
options:
max-size: "10m"
max-file: "3"
services:
api:
logging: *log_config
worker:
logging: *log_config
Ключ слияния (<<)
Ключ слияния имеет определённое поведение:
- Он копирует все пары ключ-значение из указанного отображения
- Явно заданные ключи имеют приоритет над объединёнными
- Множественные слияния обрабатываются по порядку (при конфликтах побеждает первое)
# Multiple merges
base: &base
a: 1
b: 2
extra: &extra
b: 3
c: 4
combined:
<<: [*base, *extra]
# Result: a=1, b=2 (base wins), c=4
Примеры из реальной практики
Docker Compose
x-common: &common
restart: unless-stopped
networks:
- app-network
logging:
driver: json-file
options:
max-size: "10m"
services:
api:
<<: *common
image: myapp/api:latest
ports:
- "8080:8080"
environment:
DATABASE_URL: postgres://db:5432/myapp
worker:
<<: *common
image: myapp/worker:latest
environment:
QUEUE_URL: redis://cache:6379
scheduler:
<<: *common
image: myapp/scheduler:latest
Docker Compose использует соглашение с префиксом x- для полей расширения, содержащих якоря. Смотрите наше руководство YAML для Docker Compose для других паттернов.
GitHub Actions
jobs:
test:
runs-on: ubuntu-latest
env: &common_env
NODE_VERSION: '20'
CI: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm test
build:
runs-on: ubuntu-latest
needs: test
env:
<<: *common_env
BUILD_TARGET: production
steps:
- uses: actions/checkout@v4
- run: npm run build
Kubernetes
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
resources: &resources
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
- name: sidecar
resources: *resources # Same resource limits
Ограничения и подводные камни
1. Нет межфайловых ссылок
Якоря работают только в пределах одного YAML-файла. Вы не можете ссылаться на якорь, определённый в другом файле. Для межфайлового переиспользования используйте инструменты шаблонизации: Helm, Jsonnet или Kustomize.
2. Нет частичного переопределения последовательностей
Вы не можете объединить и частично переопределить список — только заменить его целиком:
base_ports: &ports
- 80
- 443
service:
ports: *ports # You get exactly [80, 443]
# Cannot add port 8080 to this list via merge
Обходное решение: определите расширенный список отдельно.
3. Порядок имеет значение
Якоря должны быть определены до того, как на них ссылаются:
# WRONG - alias before anchor
service:
settings: *defaults
defaults: &defaults
timeout: 30
# CORRECT - anchor before alias
defaults: &defaults
timeout: 30
service:
settings: *defaults
4. Не все инструменты поддерживают ключ слияния
Ключ слияния << не является частью основной спецификации YAML — это расширение для конкретного типа. Большинство популярных YAML-парсеров его поддерживают, но некоторые строгие парсеры — нет.
Проверьте использование якорей YAML с помощью нашего YAML Validator.
Часто задаваемые вопросы
Сохраняются ли якоря при конвертации YAML в JSON?
Нет. При разборе YAML якоря и псевдонимы разрешаются в их значения. В результирующем JSON значения будут развёрнуты. Это означает, что конвертация в JSON и обратно приведёт к потере DRY-структуры. Якоря существуют только в исходном формате YAML.
Можно ли использовать якоря со сложным вложенным переопределением?
Ключ слияния (<<) выполняет только поверхностное слияние — он копирует ключи верхнего уровня из помеченного якорем отображения. Вложенные объекты заменяются целиком, а не объединяются глубоко. Для глубокого слияния нужно специфическое для инструмента решение (функция merge в Helm, пользовательские YAML-процессоры).
Связанные ресурсы
- YAML Validator — валидация YAML с якорями и псевдонимами
- Учебник по синтаксису YAML — основы YAML
- YAML для Docker Compose — паттерны для Docker