Als je ooit een YAML-blok van de ene naar de andere plek in een bestand hebt gekopieerd, heb je al het probleem gevonden dat anchors en aliases oplossen. Grote Kubernetes-configs, multi-environment Docker Compose-bestanden en complexe CI-pipelines hebben de neiging dezelfde blokken te herhalen — resourcelimieten, omgevingsvariabelen, volume-mounts — keer op keer. YAML heeft hiervoor een ingebouwde oplossing, en de meeste ontwikkelaars weten niet dat die bestaat.
Anchors (&) en aliases (*) zijn het YAML-mechanisme voor het eenmalig definiëren van een waarde en
het er elders in hetzelfde bestand naar verwijzen. Beschouw een anchor als het declareren van een variabele en een alias als het gebruiken ervan.
De merge key (<<) breidt dit uit naar object-merging — vergelijkbaar met JavaScript's spread-operator.
Beide functies zijn gedefinieerd in de YAML 1.2-specificatiesectie over node-anchors.
Basissyntaxis voor anchor en alias
De syntaxis is minimaal. Prefix een waarde met &naam om een anchor te maken,
gebruik dan *naam overal in het document om ernaar te verwijzen:
# Define the anchor once
default_timeout: &timeout 30
# Reference it multiple times
services:
api:
timeout: *timeout # → 30
worker:
timeout: *timeout # → 30
scheduler:
timeout: *timeout # → 30Wanneer een YAML-parser dit leest, wordt elke alias omgezet naar precies dezelfde waarde als de anchor. Wijzig de anchor en alle aliases worden bijgewerkt. Geen zoek-en-vervang nodig.
Objecten samenvoegen met de <<-sleutel
Scalair hergebruik is nuttig, maar de echte kracht komt van het samenvoegen van volledige mapping-blokken.
De merge key << absorbeert alle sleutel-waardeparen van de gerefereerde anchor in de huidige mapping:
# Define a base configuration block
base_service: &base
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
networks:
- app-network
# Merge it into specific services
services:
api:
<<: *base # merge all keys from base_service
image: my-api:latest
ports:
- "8080:8080"
worker:
<<: *base # same base config
image: my-worker:latest
command: ["node", "worker.js"]
scheduler:
<<: *base # and again
image: my-scheduler:latest
command: ["node", "cron.js"]Sleutels die direct in de mapping zijn gedefinieerd overschrijven sleutels van de samengevoegde anchor.
Dus als base restart: unless-stopped instelt en de service ook
restart: no instelt, wint de waarde op serviceniveau.
Voor en na: Docker Compose in de praktijk
Zo ziet een typisch multi-service Docker Compose-bestand eruit zonder anchors — vol herhaling:
# BEFORE — repetitive and hard to maintain
version: "3.9"
services:
api:
restart: unless-stopped
env_file: .env
networks: [app-network]
logging:
driver: json-file
options:
max-size: "10m"
depends_on:
- postgres
worker:
restart: unless-stopped
env_file: .env
networks: [app-network]
logging:
driver: json-file
options:
max-size: "10m"
depends_on:
- postgres
mailer:
restart: unless-stopped
env_file: .env
networks: [app-network]
logging:
driver: json-file
options:
max-size: "10m"
depends_on:
- postgresNu met anchors en de merge key — elk herhaald blok is exact één keer gedefinieerd:
# AFTER — DRY and easy to maintain
version: "3.9"
x-common: &common
restart: unless-stopped
env_file: .env
networks: [app-network]
logging:
driver: json-file
options:
max-size: "10m"
depends_on:
- postgres
services:
api:
<<: *common
image: my-api:2.4.1
ports:
- "8080:8080"
worker:
<<: *common
image: my-worker:2.4.1
command: ["node", "worker.js"]
mailer:
<<: *common
image: my-mailer:2.4.1
command: ["node", "mailer.js"]x--prefix op
extensievelden
(zoals x-common) is een Docker Compose-conventie die voorkomt dat Compose het blok probeert te verwerken als een servicedefinitie.
Het wordt genegeerd door de Compose-engine maar is volledig bruikbaar als YAML-anchor.GitHub Actions: matrix strategy met anchors
CI-configuratie is nog een plek waar anchors renderen. Hier is een GitHub Actions-workflow die gemeenschappelijke stepconfiguratie hergebruikt over meerdere jobs:
name: Build and Test
on: [push, pull_request]
# Shared setup steps
x-setup-steps: &setup-steps
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
- run: npm ci
jobs:
lint:
runs-on: ubuntu-latest
steps:
- *setup-steps
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- *setup-steps
- run: npm test -- --coverage
build:
runs-on: ubuntu-latest
steps:
- *setup-steps
- run: npm run buildLet op: de YAML-parser van GitHub Actions
ondersteunt anchors en aliases. Sommige CI-systemen
(met name CircleCI's config.yml vóór versie 2.1) hadden hun eigen anchor-achtige extensiesyntaxis.
Raadpleeg altijd de documentatie van je specifieke tool.
Kubernetes: resourcelimieten hergebruiken
In Kubernetes-manifesten zijn resourcelimieten en omgevingsvariabelen uitstekende kandidaten voor anchors. Hier is een patroon dat ik regelmatig gebruik:
# Anchors at the top of the file (or in a shared ConfigMap generator)
x-resources:
small: &resources-small
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "200m"
large: &resources-large
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "1000m"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
template:
spec:
containers:
- name: frontend
image: frontend:latest
resources: *resources-small # reuse small profile
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
template:
spec:
containers:
- name: api
image: api:latest
resources: *resources-large # reuse large profileMeerdere merges en overschrijvingsprioriteit
Je kunt samenvoegen vanuit meerdere anchors in één enkele mapping. Geef ze op als een lijst onder <<.
Eerdere vermeldingen in de lijst hebben prioriteit boven latere voor dubbele sleutels:
defaults: &defaults
color: blue
size: medium
weight: light
overrides: &overrides
color: red # will override defaults.color
weight: heavy # will override defaults.weight
result:
<<: [*overrides, *defaults] # overrides takes priority
name: widget
# Result: color=red, size=medium, weight=heavy, name=widgetBeperkingen om te kennen
- Alleen hetzelfde bestand. Anchors en aliases werken alleen binnen één YAML-documentstroom. Je kunt niet verwijzen naar een anchor uit een ander bestand. Voor hergebruik over bestanden heen heb je het eigen mechanisme van je tool nodig (bijv. Helm-templates, Kustomize, of YAML-processors zoals
ytt). - Geen berekende waarden. Aliases worden opgelost tot exacte kopieën van de anchorwaarde. Er is geen interpolatie of templatelogica — daarvoor zijn tools zoals Helm of Jinja2.
- Merge key is een YAML-extensie. De merge key
<<is gedefinieerd in een YAML 1.1-extensie, niet in de kernspecificatie. De meeste parsers ondersteunen het, maar strikt specificatieconforme YAML 1.2-parsers mogelijk niet. - Circulaire verwijzingen breken parsers. Probeer niet een node te verankeren en er dan van binnenuit naar te verwijzen. Het is technisch ongeldig.
- Aliases kopiëren, refereren niet. Het wijzigen van een opgeloste aliaswaarde in je code verandert de anchor of andere aliases niet. Het zijn onafhankelijke waarden na het parsen.
Samenvatting
YAML-anchors en -aliases zijn een van de meest ondergebruikte functies van het formaat. In elk YAML-bestand langer dan ongeveer 50 regels waarbij hetzelfde configuratieblok meer dan twee keer voorkomt, horen anchors er bijna zeker in. Het verschil in onderhoudbaarheid voor en na is dramatisch — één resourcelimietprofiel of één gedeelde omgevingsvariabele wijzigen in plaats van door het hele bestand te zoeken. Gebruik de YAML Formatter om je bestanden met anchors netjes te houden, en de YAML Validator om te bevestigen dat je anchorreferenties correct worden opgelost.