Cycle de vie d'un stack¶
Créer¶
- Créer
10-stacks/<nom>/dans le vault, avecREADME.mdetdecisions.md. - Écrire
/opt/docker/<nom>/docker-compose.ymlsur l'hôte, selon les conventions. - Valider :
docker compose -f /opt/docker/<nom>/docker-compose.yml config. - Démarrer :
docker compose -f /opt/docker/<nom>/docker-compose.yml up -d. - Si le service est exposé sur le web → Publier un nouveau service.
- Sur vm-docker et vm-compute-01, inscrire le stack dans
/opt/docker/scripts/stack-waves.conf— sinon il disparaît au premier redémarrage (voir plus bas). - Committer le vault et pousser sur les deux dépôts distants.
Modifier¶
Toute modification de configuration s'accompagne, dans la foulée, d'une entrée
datée dans 10-stacks/<nom>/decisions.md : ce qui a changé, pourquoi, et comment
revenir en arrière.
Ce n'est pas de la bureaucratie. C'est le seul canal que toutes les sessions de
travail relisent : un message envoyé de vive voix ou une note en mémoire ont
chacun un mode d'échec silencieux, decisions.md n'en a pas.
Démarrage au boot¶
Sur vm-docker et vm-compute-01, les services déclarent
restart: on-failure:5, jamais always.
docker-staggered.service est la seule autorité de démarrage au boot. Il lit
/opt/docker/scripts/stack-waves.conf, monte les projets par vagues et attend
entre chaque.
sequenceDiagram
autonumber
participant S as systemd
participant D as dockerd
participant G as docker-staggered
participant C as conteneurs
S->>D: docker.service
D-->>S: prêt
S->>G: After=docker.service
loop vagues 0 à 5, 15 s d'écart
G->>C: compose up -d (projets de la vague)
end
Note over S,G: à l'arrêt, l'ordre s'inverse :<br/>staggered-stop tourne PENDANT que dockerd est encore debout
Pourquoi cette mécanique existe :
- sur vm-compute-01, le point de contention est le verrou
xtables— chaque mise en place de règles iptables attend 20 à 28 s, et dockerd se bloque plus de dix minutes ; - sur vm-docker, c'est l'attente d'E/S — 80 conteneurs sur un disque virtuel à ~1,4 ms par lecture aléatoire font monter la charge à 85.
stateDiagram-v2
[*] --> running: compose up -d
running --> crash: le processus meurt<br/>(exit ≠ 0)
crash --> running: on-failure:5 relance
crash --> abandonne: 5 échecs d'affilée
running --> arrete: staggered-stop<br/>(exit 0, arrêt PROPRE)
arrete --> running: docker-staggered au boot,<br/>SI le projet est dans stack-waves.conf
arrete --> oublie: sinon, personne ne le rallume
note right of oublie
exited · ExitCode=0 · RestartCount=0
aucune erreur, aucune alerte
et le vhost Caddy répond en 502
end note
on-failure:5 ne couvre que la branche de gauche. La branche de droite n'a aucun
filet automatique : c'est le fichier de vagues, et rien d'autre.
Un stack absent de stack-waves.conf ne se relève pas, et rien ne le signale
C'est la conséquence directe de on-failure:5 : un conteneur arrêté proprement
(code 0) n'est pas redémarré par Docker. Or c'est exactement ce que fait
staggered-stop avant un redémarrage de l'hôte — un arrêt propre.
Si le projet n'est pas dans stack-waves.conf, personne ne le rallume au boot.
Le conteneur reste exited avec ExitCode=0, RestartCount=0, aucune erreur
dans les journaux, aucune alerte : il n'a pas planté, il a été éteint et jamais
rallumé.
Vécu le 2026-08-30 sur homelab-docs, mis en service la veille au soir et
absent du fichier : arrêt propre à 01:45 pendant le redémarrage nocturne de
patching, disparu jusqu'à ce qu'on le cherche. Le vhost Caddy, lui, répondait
toujours — en 502.
Le contrôle, après toute mise en service :
Vérifier qu'un conteneur respecte bien la politique déclarée
docker inspect <conteneur> \
--format '{{.HostConfig.RestartPolicy.Name}}:{{.HostConfig.RestartPolicy.MaximumRetryCount}}'
À comparer au restart: du fichier Compose. Un écart signifie qu'un
up -d --force-recreate a réarmé l'ancienne politique.
Diagnostiquer¶
Ordre de lecture, du moins cher au plus cher :
docker ps— le conteneur tourne-t-il, et depuis quand ?RestartCount— redémarre-t-il en boucle ?docker logs --since 1h— que dit-il de lui-même ?- État de santé — mais voir l'avertissement ci-dessous.
- Réseau, volumes, mémoire.
healthy ne veut pas dire « le service marche »
L'état de santé est ce que l'image a choisi de tester, rien de plus. Des cas
réels rencontrés ici : un port fermé alors que le conteneur est healthy, un
service secondaire mort sans effet sur la sonde, un interval de 15 minutes qui
rend l'état inutile en incident.
Corollaire pour la supervision : échouer sur unhealthy, jamais sur starting.
Une sonde peut mesurer autre chose que le service
Un service mono-processus qui écrit son état sur disque de façon synchrone gèle sa boucle d'événements pendant l'écriture — 20 à 30 s pour un graphe de 45 000 nœuds. La sonde expire, le conteneur n'a pourtant jamais redémarré. La réponse est côté supervision (délai plus long, seuil d'échecs consécutifs), pas côté service.
Mettre hors service¶
- Arrêter et retirer :
docker compose -f /opt/docker/<nom>/docker-compose.yml down. - Retirer le bloc du Caddyfile, des deux Caddy si le service était public.
- Retirer le nom du domaine de la liste d'émission des certificats.
- Retirer l'entrée
stack-waves.confsur les hôtes orchestrés. - Archiver le dossier du vault plutôt que de le supprimer, et clore
decisions.mdpar une entrée datée.
Un nom publié à l'edge avec un certificat valide est une porte qui attend
Laisser le bloc Caddy en place après avoir arrêté le conteneur ne « ne fait rien » : le jour où quelqu'un démarre un conteneur portant le même nom de service, il devient public instantanément, sans repasser par une revue. Des blocs ont été retirés pour cette raison exacte lors de l'audit de surface publique du 2026-07-22.
Dernière vérification de cette page : 2026-08-30