Aller au contenu

Conventions des stacks

Emplacements

Quoi Où
Fichier Compose canonique /opt/docker/<stack>/docker-compose.yml sur l'hôte
Documentation du stack 10-stacks/<stack>/README.md dans le vault
Journal des décisions 10-stacks/<stack>/decisions.md dans le vault
Secrets chiffrés 00-infra/secrets/<hôte>/<stack>.enc.env dans le vault

10-stacks/<stack>/compose.yml est un lien symbolique mort

Dans le vault, ce fichier pointe vers /opt/docker/<stack>/docker-compose.yml — un chemin qui n'existe que sur l'hôte. Il ne se lit pas depuis vm-claude.

Conséquence utile : modifier le fichier par SSH suffit, le vault est déjà à jour puisqu'il ne contient qu'un lien. Il n'y a rien à synchroniser.

Le contrôle qui distingue les deux cas :

ls -la 10-stacks/<stack>/compose.yml
# une flèche `->`  : lien symbolique, rien à faire
# pas de flèche    : vrai fichier, à synchroniser par scp

Squelette d'un service

services:
  monservice:                          # (1)!
    image: monimage:1.4.2@sha256:...   # (2)!
    container_name: monservice
    restart: on-failure:5              # (3)!
    cpus: 0.5
    mem_limit: 256m                    # (4)!
    security_opt:
      - no-new-privileges:true
    networks:
      - infrastructure_network         # (5)!
    labels:
      - dockhand.update=false          # (6)!
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:8080/healthz"]
      interval: 30s
      timeout: 5s
      retries: 3
    logging:
      driver: json-file
      options:
        max-size: 50m
        max-file: "3"                  # (7)!

networks:
  infrastructure_network:
    external: true
  1. Le nom du service est celui que Caddy utilisera comme nom d'hôte : reverse_proxy monservice:8080.
  2. Jamais latest. Un tag de version et son empreinte : le tag dit ce qu'on a voulu, l'empreinte dit ce qu'on a eu.
  3. on-failure:5 sur vm-docker et vm-compute-01, always ailleurs — voir Cycle de vie.
  4. Règle de dimensionnement : trois fois la consommation observée au repos.
  5. infrastructure_network pour tout ce que Caddy doit joindre ; authentik_backend_network en plus si le service parle à Authentik.
  6. Dockhand met à jour les images en opt-out. Sans ce label, une image construite localement serait remplacée par du vide.
  7. Sans ces deux lignes, un conteneur bavard remplit le disque de l'hôte.

Ce qu'un fichier Compose ne doit jamais contenir

  • Aucun secret en clair. Les valeurs vivent dans .env sur l'hôte, chiffrées dans le vault avec SOPS + age. Les noms de variables restent lisibles : un git diff montre quel secret a changé, jamais sa valeur.
  • Aucun .env lu ni copié dans le vault. Ils sont exclus, délibérément.
  • Aucun port publié dont personne n'a besoin. Si Caddy est sur le même réseau, il joint le conteneur par son nom : ports: n'apporte qu'une surface de plus.

La forme du parc pour une variable obligatoire, qui échoue bruyamment plutôt que de démarrer à moitié :

environment:
  - API_TOKEN=${API_TOKEN:?rendu SOPS absent - voir 00-infra/secrets/README.md}

Avant tout up -d

docker compose -f /opt/docker/<stack>/docker-compose.yml config

config interpole les variables et valide le schéma. Une variable manquante y apparaît immédiatement, au lieu de produire un conteneur qui démarre et ne sert à rien.

Dernière vérification de cette page : 2026-08-29