Atelier 2 : CI/CD, stack entrepôt et mise en production
Dans cet atelier, vous branchez le pipeline GitHub Actions sur la VM, vous comprenez l’application d’entrepôt à trois conteneurs, et vous la livrez — en déploiement continu comme en releases versionnées.
Partie 3 sur 4 — Aperçu · Atelier 1 : Provisionner et configurer · Exploitation et dépannage
- Connecter les variables et secrets de déploiement GitHub Actions (clé SSH, identifiants DB) sur la VM
- Comprendre la stack entrepôt à trois conteneurs (Prefect, Dagster, Superset) et son Postgres externe
- Déclencher des déploiements continus par push sur main et des releases versionnées via GitHub Releases
- Vérifier la stack Docker Compose localement avant de pousser
- Exécuter dbt et les flows Prefect manuellement pour le développement
Depuis l’Atelier 1 :
- Une VM provisionnée, joignable, avec Docker installé (Atelier 1)
Pour cet atelier :
- Le GitHub CLI (
gh), authentifié (gh auth login) avec un accès en écriture/admin sur le dépôt - Le matériel de clé SSH pour l’utilisateur de déploiement de la VM (ou la possibilité d’en créer un à l’Étape 3.2)
- Les identifiants du serveur PostgreSQL externe et des API sources eBuzima / HMIS/DHIS2
- (Optionnel) Docker + Docker Compose installés localement, pour vérifier la stack avant de pousser
Renseignez-les une fois et chaque commande de cette page se met à jour. Les valeurs restent uniquement dans votre navigateur.
Remarque sur les valeurs de ce guide. Les valeurs à personnaliser pour cet atelier —
DEPLOY_HOST, DEPLOY_USER, DEPLOY_PORT, DEPLOY_PATH, GH_OWNER — apparaissent comme des
jetons de type __NOM__ et sont remplies automatiquement dès que vous les saisissez
dans le panneau Vos valeurs de labo ci-dessus. Les autres valeurs (p. ex. <DB_USER>) ne sont
pas suivies par ce panneau — remplacez-les vous-même par les vraies valeurs de votre environnement.
Conservez les vraies valeurs dans votre coffre de secrets / gestionnaire de mots de passe, pas dans
ces pages.
Phase 3 — Connecter les secrets CI/CD et la cible de déploiement
S’exécute depuis votre machine de contrôle avec gh.
L’entrepôt n’est pas déployé à la main. GitHub Actions (.github/workflows/deploy.yml)
construit les images de conteneurs, les pousse vers GHCR, puis se connecte en SSH à la VM pour
les récupérer et les redémarrer. Vous devez d’abord donner au pipeline sa cible et ses secrets.
Étape 3.1 — Variables de dépôt (cible de déploiement non secrète)
Elles indiquent au workflow où déployer. Elles remplacent des valeurs autrefois codées en dur.
Interface GitHub
- Ouvrez le dépôt sur GitHub → Settings → Secrets and variables → Actions → Variables.
- Cliquez sur New repository variable pour chacune :
DEPLOY_HOST,DEPLOY_USER,DEPLOY_PORT,DEPLOY_PATH. - Saisissez le nom et la valeur, puis Add variable.
$ gh variable list
NAME VALUE UPDATED AT
DEPLOY_HOST __DEPLOY_HOST__ just now
DEPLOY_USER __DEPLOY_USER__ just now
DEPLOY_PORT __DEPLOY_PORT__ just now
DEPLOY_PATH __DEPLOY_PATH__ just nowVous ne voyez pas cela ?
- Une variable manque dans la liste — la commande
gh variable setcorrespondante a échoué silencieusement sur un problème d’authentification ; lancezgh auth statuspuis relancez la commandesetmanquante. - Les valeurs affichent encore un jeton littéral de type
__NOM__— vous avez copié une commande sans remplir vos valeurs dans le panneau Vos valeurs de labo ci-dessus.
Étape 3.2 — Le secret de la clé SSH de déploiement
Générez une clé dédiée, autorisez-la sur la VM, téléversez la moitié privée comme secret :
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ./deploy_key -N ""
# Authorize the public key on the VM (match your DEPLOY_* values)
ssh-copy-id -i ./deploy_key.pub -p __DEPLOY_PORT__ __DEPLOY_USER__@__DEPLOY_HOST__
# Upload the private key, then destroy the local copies
gh secret set SSH_PRIVATE_KEY < ./deploy_key
rm ./deploy_key ./deploy_key.pub$ ssh-copy-id -i ./deploy_key.pub -p __DEPLOY_PORT__ __DEPLOY_USER__@__DEPLOY_HOST__
Number of key(s) added: 1
$ gh secret set SSH_PRIVATE_KEY < ./deploy_key
✓ Set Actions secret SSH_PRIVATE_KEY for __GH_OWNER__/mnchtestVous ne voyez pas cela ?
ssh-copy-idafficheNumber of key(s) added: 0— la clé est déjà autorisée, ou vous avez ciblé le mauvaisDEPLOY_PORT/DEPLOY_USER; vérifiez avecssh -i ./deploy_key -p __DEPLOY_PORT__ __DEPLOY_USER__@__DEPLOY_HOST__.gh secret setreste bloqué ou échoue sur l’authentification — lancezgh auth status; il faut un accès en écriture/admin sur le dépôt pour définir des secrets Actions.- Vous avez oublié
rm ./deploy_key ./deploy_key.pub— la clé privée traîne encore en clair sur votre machine de contrôle ; supprimez les deux fichiers maintenant qu’elle est téléversée.
GITHUB_TOKENne nécessite aucune configuration — GitHub Actions le fournit à chaque run et l’utilise pour pousser/récupérer les images depuis GHCR (ghcr.io).
Étape 3.3 — Secrets applicatifs et de base de données
Le job de déploiement régénère le .env de la VM à chaque exécution à partir de ces secrets
du dépôt (cat > .env <<EOF … EOF via SSH). Le .env de la VM est un état généré jetable — ne
l’éditez jamais à la main. Définissez chacun avec gh secret set <NAME> --body '<value>' :
| Secret | Clé .env | Notes |
|---|---|---|
DB_HOST | DB_HOST | Hôte Postgres externe de l’entrepôt |
DB_PORT | DB_PORT | Généralement 5432 |
DB_USER | DB_USER | Utilisateur de la base entrepôt |
DB_PASSWORD | DB_PASSWORD | À faire tourner — voir la Phase 6 |
PREFECT_DB_NAME | PREFECT_DB_NAME | prefect_db |
SUPERSET_DB_NAME | SUPERSET_DB_NAME | superset_db |
DAGSTER_DB_NAME | DAGSTER_DB_NAME | dagster_db |
SUPERSET_SECRET_KEY | SUPERSET_SECRET_KEY | Signe les sessions — à garder stable |
SUPERSET_ADMIN_PASSWORD | SUPERSET_ADMIN_PASSWORD | Identifiant admin de Superset |
EBUZIMA_API_KEY / EBUZIMA_API_SECRET / EBUZIMA_BASE_URL | identiques | API source eBuzima |
HMIS_USERNAME / HMIS_PASSWORD / HMIS_BASE_URL | identiques | API source HMIS/DHIS2 |
CONNECTION_STRING | connection_string | Lu tel quel par les flows Prefect |
WAREHOUSE_DB_NAME (optionnel) | — | Lu par dbt/profiles.yml ; mnch_main_db par défaut |
Les tags d’images (
PREFECT_IMAGE/SUPERSET_IMAGE/DAGSTER_IMAGE) sont exportés en ligne par le job de déploiement à chaque run — vous ne les définissez nulle part. Le.env.exampledu dépôt applicatif sert uniquement au développement local, pas à la VM.
Étape 3.4 — Visibilité des packages GHCR (première livraison uniquement)
Le premier run crée trois packages : ghcr.io/__GH_OWNER__/mnchtest/{prefect,superset,dagster}. Ils
héritent de la visibilité du dépôt, donc GITHUB_TOKEN devrait pousser/récupérer sans problème.
Si le pull du job de déploiement rencontre un 401/403, ouvrez Settings → Manage Actions
access de chaque package et donnez au dépôt au moins l’accès Write.
Phase 4 — L’application entrepôt
C’est ce qui tourne réellement sur la VM.
Trois conteneurs Docker tournent sur la VM via docker-compose.yml, tous connectés au serveur
PostgreSQL externe de la Phase 3.
Topologie d’exécution
Ce que fait chaque conteneur :
- Prefect — exécute le serveur Prefect (API + UI) et un worker dans un même conteneur. Le
worker exécute environ 60 déploiements d’ingestion (depuis
.prefect/prefect.yaml) selon des planifications cron, en écrivant dans le schéma landing de l’entrepôt. Commande de démarrage, dans l’ordre : démarrer le serveur → interroger/api/healthjusqu’à disponibilité → créer le work-pool de processusdefault→deploy --all→ démarrer le worker (au premier plan). - Dagster — exécute
dagster-webserver(UI, port 3000) +dagster-daemon(planifications/capteurs). Il charge le projetdbt/comme assets Dagster et les matérialise (dbt build) selon ladbt_daily_schedule(0 9 * * *Africa/Kigali, après la fenêtre d’ingestion nocturne). Cette planification est définie avecdefault_status=RUNNING— critique, car les planifications Dagster démarrent arrêtées par défaut. Le projetdbt/est intégré à l’image au moment du build, donc une modification de.sqlpart automatiquement au prochain build CI — aucundbt runmanuel en production. Démarrage :dbt parse(nécessite les identifiants de base au runtime, d’où son exécution au démarrage du conteneur) →dagster-daemon(en arrière-plan) →dagster-webserver(au premier plan). - Superset — lit les marts construits par dbt pour restituer les tableaux de bord ; stocke
son propre état dans
superset_db. Démarrage :superset db upgrade→ création deadmin(ignorée après le premier run) →superset init→superset runsur 8088. Nécessite le montage de volume./.superset:/app/pythonpathpoursuperset_config.py, sans quoi il se rabat silencieusement sur un stockage de métadonnées SQLite.
Carte des ports
| Service | Port hôte | Port conteneur | Notes |
|---|---|---|---|
| Prefect | 14200 | 4200 | Aucune authentification configurée par défaut |
| Superset | 18088 | 8088 | Connexion admin / SUPERSET_ADMIN_PASSWORD |
| Dagster | 13000 | 3000 | Aucune authentification configurée par défaut |
Ce sont les ports vers lesquels votre reverse proxy (Étape 1.5 / playbook 02) transfère.
Modèle de données dbt
La qualité des données est mesurée selon six dimensions : exactitude, complétude, cohérence, actualité, unicité, validité.
Sources de données :
- eBuzima (EMR basé sur ERPNext) — dossiers individuels ANC/maternité/nouveau-né, ingérés quotidiennement.
- HMIS/DHIS2 — agrégats mensuels au niveau des établissements, ingérés le 20 de chaque mois.
Phase 5 — Déployer et livrer
Avec les Phases 1–2 et la Phase 3 terminées, le déploiement se déclenche depuis GitHub — aucun build n’a jamais lieu sur la VM.
Déploiement continu (push sur main)
Un simple push sur main construit les images :latest, les pousse vers GHCR, puis se connecte
en SSH à la VM pour :
git pull origin main(rafraîchir le code des flows/dbt/config sur la VM),- régénérer le
.envà partir des secrets GitHub (Étape 3.3), docker compose pull && docker compose up -d --remove-orphans.
Publier une release versionnée
Les releases sont déclenchées par la publication d’une GitHub Release, pas par le push direct d’un tag :
Interface GitHub
Releases → Draft a new release, saisissez un nouveau tag (p. ex. v1.0.0), ajoutez des notes,
Publish release.
Cela construit et pousse ghcr.io/__GH_OWNER__/mnchtest/{prefect,superset,dagster}:v1.0.0 (et met à
jour :latest), puis déploie cette version épinglée sur la VM.
Suivez la progression :
Interface GitHub
Ouvrez l’onglet Actions du dépôt et cliquez sur le workflow en cours pour suivre les logs en direct.
$ gh run watch
✓ deploy in 1m42s (ID 123456789)Vous ne voyez pas cela ?
- Le run échoue à l’étape de push vers GHCR — la visibilité des packages GHCR n’est pas encore réglée sur au moins Write pour le dépôt (Étape 3.4) ; vérifiez Settings → Manage Actions access de chaque package.
- Le run échoue à l’étape SSH —
SSH_PRIVATE_KEYne correspond pas à la clé publique autorisée sur la VM, ouDEPLOY_HOST/DEPLOY_PORT/DEPLOY_USERsont incorrects ; revérifiez les Étapes 3.1 et 3.2. - Le run réussit mais les conteneurs ne changent pas — connectez-vous en SSH à la VM et vérifiez
docker compose ps/docker compose logs; la régénération du.enva pu échouer parce qu’un secret de l’Étape 3.3 manque ou est mal nommé.
Vérification locale avant de pousser
cp .env.example .env # fill in real values (local dev only)
docker compose config # confirms env-var interpolation resolves
docker compose up -d --build$ docker compose up -d --build
[+] Running 3/3
✔ Container mnchtest-prefect-1 Started
✔ Container mnchtest-dagster-1 Started
✔ Container mnchtest-superset-1 StartedVous ne voyez pas cela ?
docker compose configéchoue avec « variable is not set » — le.envn’a pas été rempli à partir de.env.example, ou un nom de variable dans.envne correspond pas à ce qu’attenddocker-compose.yml.- Un conteneur s’arrête immédiatement après le démarrage — vérifiez
docker compose logs <service>; Superset a besoin du montage./.superset:/app/pythonpath, sinon il se rabat silencieusement sur SQLite. - Un port ne parvient pas à se lier — un autre processus sur votre machine occupe déjà
14200,18088ou13000; arrêtez-le ou remappez le port hôte dansdocker-compose.yml.
Accéder aux services en fonctionnement
| Service | URL | Connexion |
|---|---|---|
| Superset | http://__DEPLOY_HOST__:18088 | admin / SUPERSET_ADMIN_PASSWORD |
| Prefect | http://__DEPLOY_HOST__:14200 | aucune configurée |
| Dagster | http://__DEPLOY_HOST__:13000 | aucune configurée |
Les secrets GitHub Actions sont en écriture seule — il n’existe aucune commande
ghpour les relire. Pour retrouver le mot de passe Superset actuel, connectez-vous en SSH à la VM et faitescat .env, ou consultez le registre de secrets de votre équipe.
Exécuter dbt manuellement (développement)
En production, dbt s’exécute automatiquement via la planification quotidienne de Dagster. Pour l’exécuter manuellement pendant le développement :
cd dbt
dbt run
dbt testOu dans l’UI Dagster (port 13000) : Assets → sélectionner les assets dbt → Materialize.
Déployer les flows Prefect manuellement
cd .prefect
prefect deploy --allNettoyage
Sautez toute cette section si vous poursuivez avec Exploitation et dépannage — cette leçon s’appuie sur la stack, les secrets et les images que vous venez de déployer. Revenez ici seulement une fois le parcours entièrement terminé.
Démontage complet de tout ce que cet atelier a déployé :
# arrêter et supprimer les conteneurs en cours d’exécution sur la VM
ssh __DEPLOY_USER__@__DEPLOY_HOST__ -p __DEPLOY_PORT__ "cd __DEPLOY_PATH__ && docker compose down"
# supprimer les packages GHCR si les images ne sont plus nécessaires
gh api -X DELETE /orgs/__GH_OWNER__/packages/container/mnchtest%2Fprefect
gh api -X DELETE /orgs/__GH_OWNER__/packages/container/mnchtest%2Fsuperset
gh api -X DELETE /orgs/__GH_OWNER__/packages/container/mnchtest%2Fdagster
# effacer les secrets et variables du dépôt définis en Phase 3
gh secret list | awk '{print $1}' | xargs -n1 gh secret delete
gh variable list | awk '{print $1}' | xargs -n1 gh variable delete
docker compose down # arrêter la stack de vérification locale, si vous en avez démarré uneLa suite
La stack est en service. Terminez avec Exploitation, dépannage et glossaire pour les tâches du deuxième jour — rotation des identifiants, renouvellement TLS, snapshots — et la table de dépannage transversale aux couches.