Si vous avez déjà copié un bloc YAML d'un endroit à un autre dans un fichier, vous avez déjà rencontré le problème que les ancres et les alias résolvent. Les grandes configurations Kubernetes, les fichiers Docker Compose multi-environnements, et les pipelines CI complexes ont tendance à répéter les mêmes blocs — limites de ressources, variables d'environnement, montages de volumes — encore et encore. YAML a une réponse native à ce problème, et la plupart des développeurs ne savent pas qu'elle existe.

Les ancres (&) et les alias (*) sont le mécanisme de YAML pour définir une valeur une seule fois et la référencer n'importe où ailleurs dans le même fichier. Pensez à une ancre comme à la déclaration d'une variable et à un alias comme à son utilisation. La clé de fusion (<<) étend cela à la fusion d'objets — similaire à l'opérateur de décomposition de JavaScript. Ces deux fonctionnalités sont définies dans la section sur les ancres de nœuds de la spécification YAML 1.2.

Syntaxe de base des ancres et alias

La syntaxe est minimale. Préfixez une valeur avec &nom pour créer une ancre, puis utilisez *nom n'importe où dans le document pour la référencer :

yaml
# Define the anchor once
default_timeout: &timeout 30

# Reference it multiple times
services:
  api:
    timeout: *timeout      # → 30
  worker:
    timeout: *timeout      # → 30
  scheduler:
    timeout: *timeout      # → 30

Quand un parseur YAML lit ceci, chaque alias se résout à la même valeur exacte que l'ancre. Changez l'ancre et tous les alias se mettent à jour. Pas besoin de rechercher-remplacer.

Fusion d'objets avec la clé <<

La réutilisation de scalaires est utile, mais la vraie puissance vient de la fusion de blocs de mapping entiers. La clé de fusion << absorbe toutes les paires clé-valeur de l'ancre référencée dans le mapping courant :

yaml
# 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"]

Les clés définies directement dans le mapping surchargent les clés de l'ancre fusionnée. Donc si base définit restart: unless-stopped et que le service définit aussi restart: no, c'est la valeur au niveau du service qui prévaut.

Avant et après : Docker Compose dans le monde réel

Voici à quoi ressemble un fichier Docker Compose multi-service typique sans ancres — plein de répétitions :

yaml
# 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:
      - postgres

Maintenant avec les ancres et la clé de fusion — chaque bloc répété est défini exactement une fois :

yaml
# 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"]
Conseil pro : Le préfixe x- sur les champs d'extension (comme x-common) est une convention Docker Compose qui empêche Compose d'essayer d'analyser le bloc comme une définition de service. Il est ignoré par le moteur Compose mais entièrement utilisable comme ancre YAML.

GitHub Actions : stratégie matrix avec des ancres

La configuration CI est un autre endroit où les ancres sont payantes. Voici un workflow GitHub Actions qui réutilise la configuration commune des étapes sur plusieurs jobs :

yaml
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 build

Remarque : le parseur YAML de GitHub Actions supporte bien les ancres et les alias. Cependant, certains systèmes CI (notamment CircleCI avant la version 2.1) avaient leur propre syntaxe d'extension similaire aux ancres. Vérifiez toujours la documentation de votre outil spécifique.

Kubernetes : réutiliser les limites de ressources

Dans les manifestes Kubernetes, les limites de ressources et les variables d'environnement sont des candidats idéaux pour les ancres. Voici un schéma que j'utilise régulièrement :

yaml
# 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 profile

Fusions multiples et priorité de surcharge

Vous pouvez fusionner depuis plusieurs ancres dans un seul mapping. Fournissez-les sous forme de liste sous <<. Les entrées antérieures dans la liste ont la priorité sur les entrées ultérieures pour les clés en double :

yaml
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=widget

Limitations à connaître

  • Fichier unique uniquement. Les ancres et alias ne fonctionnent que dans un seul flux de document YAML. Vous ne pouvez pas référencer une ancre depuis un fichier différent. Pour la réutilisation entre fichiers, vous avez besoin du mécanisme propre à votre outil (par exemple, templates Helm, Kustomize, ou des processeurs YAML comme ytt).
  • Pas de valeurs calculées. Les alias se résolvent en copies exactes de la valeur de l'ancre. Il n'y a pas d'interpolation ou de logique de template — c'est pour des outils comme Helm ou Jinja2.
  • La clé de fusion est une extension YAML. La clé de fusion << est définie dans une extension YAML 1.1, pas dans la spécification principale. La plupart des parseurs la supportent, mais les parseurs YAML 1.2 strictement conformes à la spécification peuvent ne pas la supporter.
  • Les références circulaires cassent les parseurs. N'essayez pas d'ancrer un nœud et de le référencer depuis l'intérieur de lui-même. C'est techniquement invalide.
  • Les alias copient, ne référencent pas. Modifier la valeur d'un alias résolu dans votre code ne change pas l'ancre ni les autres alias. Ce sont des valeurs indépendantes après l'analyse.

Conclusion

Les ancres et les alias YAML sont l'une des fonctionnalités les plus sous-utilisées du format. Dans tout fichier YAML de plus d'environ 50 lignes où le même bloc de configuration apparaît plus de deux fois, les ancres y ont presque certainement leur place. La différence avant/après en termes de maintenabilité est dramatique — changer un profil de limite de ressource ou une variable d'environnement partagée plutôt que de les chercher dans tout le fichier. Utilisez le Formateur YAML pour garder vos fichiers avec ancres bien ordonnés, et le Validateur YAML pour confirmer que vos références d'ancre se résolvent correctement.