Si vous avez déjà géré un cluster Kubernetes, configuré un workflow GitHub Actions, ou écrit un fichier Docker Compose, vous avez déjà écrit du YAML — probablement beaucoup. YAML est le format de configuration qui propulse la majeure partie des outils DevOps modernes. Mais malgré son omniprésence, c'est un format qui surprend constamment. J'ai débogué plus que ma part d'erreurs d'indentation YAML à 23h avec un déploiement bloqué. Faisons en sorte que vous n'ayez pas à vivre ça.

YAML signifie YAML Ain't Markup Language — oui, c'est un acronyme récursif. Il s'appelait à l'origine « Yet Another Markup Language » mais a été renommé pour souligner que c'est un format de sérialisation de données, pas un langage de balisage de documents. La spécification YAML 1.2 est le standard actuel, bien que de nombreux outils implémentent encore YAML 1.1, qui présente des différences véritablement dangereuses que nous aborderons ci-dessous.

Les bases : la syntaxe YAML en un coup d'œil

YAML utilise l'indentation (espaces uniquement — jamais de tabulations) pour exprimer la structure. Un document YAML est un mapping (paires clé-valeur), une séquence (une liste), ou un scalaire (une valeur unique). Voici une véritable configuration de style Kubernetes qui couvre tous les essentiels :

yaml
# This is a comment — YAML supports them, JSON does not
app:
  name: payment-service
  version: "2.1.0"         # quoted to keep it a string
  port: 8080
  debug: false
  timeout: 30.5
  tags:
    - payments
    - backend
    - critical
  database:
    host: postgres.internal
    port: 5432
    ssl: true
    password: null          # explicitly no value

Pas d'accolades, pas de guillemets sur la plupart des chaînes, pas de virgules. Pour un fichier que les humains éditent chaque jour, cette clarté s'accumule vite. Mais YAML paie cette lisibilité par la complexité — il se passe beaucoup de choses sous le capot.

Types scalaires : chaînes, nombres, booléens, null

YAML infère les types à partir de l'apparence de la valeur. C'est pratique la plupart du temps et silencieusement catastrophique dans quelques cas précis.

yaml
# Strings — quotes are optional unless value is ambiguous
name: Alice
greeting: "Hello, world"
message: 'single quotes work too'
path: /usr/local/bin           # unquoted — still a string

# Numbers
integer: 42
negative: -7
float: 3.14159
scientific: 6.022e23

# Booleans
ssl_enabled: true
verbose: false

# Null
api_key: null
legacy_field: ~               # tilde is also null in YAML
Le problème Norvège : En YAML 1.1 (utilisé par PyYAML et de nombreux outils anciens), les valeurs non quotées yes, no, on, off, true, false, y, n, Y, N — et leurs variantes en majuscules — sont toutes interprétées comme des booléens. Cela signifie que le code pays ISO NO (Norvège) devient le booléen false. YAML 1.2 a corrigé cela. Mettez toujours entre guillemets les chaînes qui ressemblent à des booléens. Consultez l' article Wikipedia sur le problème Norvège pour toute l'histoire.
yaml
# YAML 1.1 implicit type coercion — these silently become booleans:
country: NO       # → false  (Norway Problem!)
enabled: yes      # → true
toggle: on        # → true

# The fix: always quote when there's any ambiguity
country: "NO"
enabled: "yes"
version: "1.0"    # also quote version numbers — 1.0 would be a float

Séquences : les listes en YAML

Les listes utilisent un préfixe tiret-espace. Chaque élément peut être un scalaire, un mapping ou une autre séquence :

yaml
# Simple list
languages:
  - Python
  - Go
  - TypeScript

# List of objects (common in Kubernetes)
containers:
  - name: api
    image: my-api:latest
    port: 8080
  - name: sidecar
    image: envoy:v1.28
    port: 9901

# Inline flow style (valid YAML, less readable)
tags: [payments, backend, v2]

Chaînes multi-lignes : bloc littéral vs bloc plié

C'est là que YAML surpasse JSON pour les fichiers de configuration. Deux opérateurs spéciaux gèrent élégamment les chaînes multi-lignes :

yaml
# Literal block scalar (|) — preserves newlines exactly
startup_script: |
  #!/bin/bash
  set -e
  echo "Starting service..."
  npm start

# Folded scalar (>) — folds newlines into spaces (good for long descriptions)
description: >
  This service handles payment processing
  for all regions. It connects to Stripe
  and falls back to PayPal.
# Result: "This service handles payment processing for all regions. It connects to Stripe and falls back to PayPal."

# Chomp modifiers
keep_trailing: |+
  line one
  line two

strip_trailing: |-
  line one
  line two

L'opérateur | est ce qui rend les scripts run: multi-lignes de GitHub Actions lisibles. Le mémo yaml-multiline.info est le moyen le plus rapide de se souvenir quel modificateur de troncature fait quoi. Sans ces blocs scalaires, vous seriez contraint d'écrire des sauts de ligne échappés dans une seule chaîne — ce que JSON vous force à faire.

Tabulations vs espaces — la règle cardinale

YAML interdit les tabulations pour l'indentation. Complètement. Si votre éditeur insère un caractère de tabulation n'importe où dans l'indentation d'un fichier YAML, le fichier échouera à l'analyse ou — pire — sera analysé incorrectement. Configurez votre éditeur pour utiliser des espaces pour les fichiers .yml et .yaml. Deux espaces est la convention quasi universelle.

C'est la cause n°1 des erreurs YAML cryptiques. Une tabulation est identique à des espaces dans la plupart des éditeurs. Activez « afficher les caractères d'espacement » dans votre éditeur lors du débogage de YAML, ou collez votre fichier dans le Validateur YAML pour obtenir un message d'erreur clair pointant vers la ligne exacte.

Exemple réel : workflow GitHub Actions

Voici un vrai extrait de workflow GitHub Actions. Remarquez comment le bloc run: multi-ligne utilise le bloc scalaire littéral, et comment l'indentation détermine la structure :

yaml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: |
          npm run lint
          npm run test -- --coverage
          npm run build

Exemple réel : manifeste de déploiement Kubernetes

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-api
  namespace: production
  labels:
    app: payment-api
    version: "2.1.0"
spec:
  replicas: 3
  selector:
    matchLabels:
      app: payment-api
  template:
    metadata:
      labels:
        app: payment-api
    spec:
      containers:
        - name: api
          image: payment-api:2.1.0
          ports:
            - containerPort: 8080
          env:
            - name: NODE_ENV
              value: production
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: password
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"

Analyser le YAML en Python et JavaScript

En Python, la bibliothèque PyYAML est le choix standard. Utilisez toujours safe_load(), pas load() — la version non sécurisée peut exécuter du code Python arbitraire depuis un fichier YAML :

python
import yaml

# Reading a YAML config file
with open('config.yaml', 'r') as f:
    config = yaml.safe_load(f)

print(config['app']['name'])        # payment-service
print(config['app']['port'])        # 8080 (integer, not string)
print(config['app']['tags'])        # ['payments', 'backend', 'critical']

# Writing Python data to YAML
data = {
    'service': 'auth-api',
    'replicas': 2,
    'endpoints': ['/login', '/logout', '/refresh']
}
with open('output.yaml', 'w') as f:
    yaml.dump(data, f, default_flow_style=False)

En JavaScript/Node.js, js-yaml est la bibliothèque la plus utilisée :

js
import yaml from 'js-yaml';
import fs from 'fs';

// Parse YAML string
const raw = fs.readFileSync('config.yaml', 'utf8');
const config = yaml.load(raw);

console.log(config.app.name);     // payment-service
console.log(config.app.tags);     // ['payments', 'backend', 'critical']

// Dump an object to YAML string
const output = yaml.dump({
  name: 'my-service',
  port: 3000,
  tags: ['api', 'public']
});
console.log(output);

Conclusion

La syntaxe basée sur l'indentation de YAML, le support des commentaires et les chaînes multi-lignes lisibles en font le bon choix pour les fichiers de configuration que les humains écrivent et maintiennent. Mais il comporte de vrais pièges : le problème Norvège, la confusion tabulations/espaces, et la coercition implicite de types des parseurs YAML 1.1. Connaissez les règles, mettez entre guillemets tout ce qui est ambigu, configurez votre éditeur pour afficher les espaces blancs, et utilisez un Formateur YAML pour garder les fichiers cohérents. YAML est un outil puissant une fois que vous comprenez où il mord.