Migrer depuis un déploiement SSH
Les stacks lancées par un workflow SSH sont inconnues du serveur : /exec et DELETE /stack les refusent avec 403, et leurs bind mounts ne suivent en général pas l'arborescence <key>/<service>/<name>, si bien que /deploy les refuse avec 409. Suivez les étapes dans l'ordre. Les commandes sur l'hôte s'exécutent en root ; les chemins supposent les valeurs par défaut /data/websites et /data/compose.
<key> vaut <CI_PROJECT_PATH_SLUG>-<slug de l'environnement>, par exemple group-app-staging. Voir Clé de stack et arborescence.
Partie 1 : le serveur (une fois)
- Installez le serveur et définissez
ALLOWED_NAMESPACES,ALLOWED_IPS,FORBIDDEN_TRAEFIK_HOSTSetALLOWED_EXTERNAL_NETWORKS. Laissez:8443fermé sur le pare-feu de l'hôte.
Partie 2 : inventaire et propriété (une fois)
-
Listez les anciennes stacks et leurs noms de projet compose :
docker ps -a --format '{{.Label "com.docker.compose.project"}}\t{{.Names}}\t{{.Status}}' | sortLe serveur trouve les conteneurs d'une stack par le label
com.docker.compose.project=<key>ou par un nom commençant par<key>-ou<key>_. Notez toute stack lancée sous un autre nom de projet : vous l'arrêterez à la main à l'étape 6. -
Listez les bind mounts de chaque stack. Toute source qui n'est pas exactement
/data/websites/<key>/<service>/<name>correspond à des données à déplacer à l'étape 7 :for id in $(docker ps -aq --filter label=com.docker.compose.project=<key>); dodocker inspect --format '{{.Name}}{{range .Mounts}}{{if eq .Type "bind"}} {{.Source}} -> {{.Destination}}{{end}}{{end}}' "$id"done -
Importez la propriété de chaque stack, serveur arrêté. Écrivez
./data/legacy.json(./dataest le côté hôte deDATA_DIR) :{"group-app-staging": {"project_id": "42", "project_path": "group/app", "environment": "staging"}}docker compose stop deploy-serverdocker run --rm -e DATA_DIR=/app/data -v "$PWD/data:/app/data" \ghcr.io/loch-sh/deploy:1.0 -import-registry /app/data/legacy.jsondocker compose start deploy-serverLancez ces commandes depuis le dossier du
docker-compose.ymldu serveur. L'import est tout ou rien. Code de sortie0en cas de succès,1en cas d'échec,2si les arguments sont invalides. Format : Clé de stack et arborescence. -
Ouvrez
:8443aux adresses des runners CI et définissezDEPLOY_URLdans les pipelines.
Ne lancez jamais -import-registry pendant que le serveur tourne : il garde le registre en mémoire et écrase l'import à sa prochaine écriture.
Partie 3 : chaque stack (interruption de l'étape 6 à l'étape 9)
-
Adaptez le modèle compose et le pipeline (règles compose, pipeline) : sources de bind
<key>/<service>/<name>, une entrée/directoriespar répertoire,webdéclaréexternal: true, pas debuild:. Désactivez les jobs SSH. Arrêtez ensuite l'ancienne stack avec le job d'arrêt du pipeline (DELETE /stack). Il supprime tous les conteneurs de la stack et efface/data/compose/<key>/: sauvegardez d'abord les anciens fichiers compose et d'environnement. Sidownéchoue sur l'ancien fichier compose, arrêtez la stack sur l'hôte (docker compose -p <key> down --remove-orphansdepuis/data/compose/<key>/, puisdocker rm -fde ce qui reste). Arrêtez à la main les stacks notées à l'étape 2 (docker compose -p <name> down). Vérifiez qu'il ne reste rien :docker ps -a --filter label=com.docker.compose.project=<key>docker ps -a --filter 'name=^/?<key>[-_]' -
Déplacez les données vers l'arborescence
<service>/<name>:cd /data/websites/<key>mkdir -p apimv jwt log storage api/ # anciennement <key>/jwt, <key>/log, <key>/storage -
Remettez les niveaux intermédiaires en
root:root 0755. Cherchez d'abord les liens symboliques :chownles suit.find /data/websites/<key> -maxdepth 2 -type l # ne doit rien afficherchown root:root /data/websites /data/websites/<key> /data/websites/<key>/*/chmod 0755 /data/websites /data/websites/<key> /data/websites/<key>/*/ -
Déployez via le pipeline.
/directoriesappliquemode,useretgroupà chaque répertoire<name>, puis/deployrépond204. Un409signale qu'un ancien conteneur est encore là (retour à l'étape 6) ; un400liste les violations du modèle.
DELETE /stack libère la propriété : enchaînez les étapes 7 à 9 sans attendre, la clé reste libre jusqu'au prochain déploiement réussi.
Vérification
for id in $(docker ps -aq --filter label=com.docker.compose.project=<key>); do
docker inspect --format '{{.Name}}{{range .Mounts}}{{if eq .Type "bind"}} {{.Source}}{{end}}{{end}}' "$id"
done
stat -c '%U:%G %a %n' /data/websites/<key> /data/websites/<key>/*/
grep -A3 '"<key>"' ./data/registry.json
L'entrée d'audit du déploiement ("msg":"audit", "path":"/deploy") a le statut 204 et pas de legacy_mounts.
Procédure source : Migration runbook.