Skip to Content
L’échange d’apprentissage de HIC débute le 13 Juillet 2026. Voir le programme
AtelierÉlément 4 sur 22 · 2 h

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 4Aperçu · Atelier 1 : Provisionner et configurer · Exploitation et dépannage

Ce que vous apprendrez
  • 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
Avant de commencer

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
Vos valeurs de labo

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 déployer. Elles remplacent des valeurs autrefois codées en dur.

  1. Ouvrez le dépôt sur GitHub → Settings → Secrets and variables → Actions → Variables.
  2. Cliquez sur New repository variable pour chacune : DEPLOY_HOST, DEPLOY_USER, DEPLOY_PORT, DEPLOY_PATH.
  3. Saisissez le nom et la valeur, puis Add variable.
Point de contrôleVariables de cible de déploiement définies
Vous devriez voir :
$ 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 now
Vous ne voyez pas cela ?
  • Une variable manque dans la liste — la commande gh variable set correspondante a échoué silencieusement sur un problème d’authentification ; lancez gh auth status puis relancez la commande set manquante.
  • 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
Point de contrôleClé de déploiement autorisée et secret téléversé
Vous devriez voir :
$ 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__/mnchtest
Vous ne voyez pas cela ?
  • ssh-copy-id affiche Number of key(s) added: 0 — la clé est déjà autorisée, ou vous avez ciblé le mauvais DEPLOY_PORT/DEPLOY_USER ; vérifiez avec ssh -i ./deploy_key -p __DEPLOY_PORT__ __DEPLOY_USER__@__DEPLOY_HOST__.
  • gh secret set reste bloqué ou échoue sur l’authentification — lancez gh 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_TOKEN ne 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>' :

SecretClé .envNotes
DB_HOSTDB_HOSTHôte Postgres externe de l’entrepôt
DB_PORTDB_PORTGénéralement 5432
DB_USERDB_USERUtilisateur de la base entrepôt
DB_PASSWORDDB_PASSWORDÀ faire tourner — voir la Phase 6
PREFECT_DB_NAMEPREFECT_DB_NAMEprefect_db
SUPERSET_DB_NAMESUPERSET_DB_NAMEsuperset_db
DAGSTER_DB_NAMEDAGSTER_DB_NAMEdagster_db
SUPERSET_SECRET_KEYSUPERSET_SECRET_KEYSigne les sessions — à garder stable
SUPERSET_ADMIN_PASSWORDSUPERSET_ADMIN_PASSWORDIdentifiant admin de Superset
EBUZIMA_API_KEY / EBUZIMA_API_SECRET / EBUZIMA_BASE_URLidentiquesAPI source eBuzima
HMIS_USERNAME / HMIS_PASSWORD / HMIS_BASE_URLidentiquesAPI source HMIS/DHIS2
CONNECTION_STRINGconnection_stringLu 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.example du 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/health jusqu’à disponibilité → créer le work-pool de processus defaultdeploy --all → démarrer le worker (au premier plan).
  • Dagster — exécute dagster-webserver (UI, port 3000) + dagster-daemon (planifications/capteurs). Il charge le projet dbt/ comme assets Dagster et les matérialise (dbt build) selon la dbt_daily_schedule (0 9 * * * Africa/Kigali, après la fenêtre d’ingestion nocturne). Cette planification est définie avec default_status=RUNNINGcritique, car les planifications Dagster démarrent arrêtées par défaut. Le projet dbt/ est intégré à l’image au moment du build, donc une modification de .sql part automatiquement au prochain build CI — aucun dbt run manuel 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 de admin (ignorée après le premier run) → superset initsuperset run sur 8088. Nécessite le montage de volume ./.superset:/app/pythonpath pour superset_config.py, sans quoi il se rabat silencieusement sur un stockage de métadonnées SQLite.

Carte des ports

ServicePort hôtePort conteneurNotes
Prefect142004200Aucune authentification configurée par défaut
Superset180888088Connexion admin / SUPERSET_ADMIN_PASSWORD
Dagster130003000Aucune 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 :

  1. git pull origin main (rafraîchir le code des flows/dbt/config sur la VM),
  2. régénérer le .env à partir des secrets GitHub (Étape 3.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 :

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 :

Ouvrez l’onglet Actions du dépôt et cliquez sur le workflow en cours pour suivre les logs en direct.

Point de contrôleRun CI/CD terminé sans erreur
Vous devriez voir :
$ 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_KEY ne correspond pas à la clé publique autorisée sur la VM, ou DEPLOY_HOST/DEPLOY_PORT/DEPLOY_USER sont 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 .env a 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
Point de contrôleLa stack locale se construit et démarre
Vous devriez voir :
$ docker compose up -d --build [+] Running 3/3 ✔ Container mnchtest-prefect-1 Started ✔ Container mnchtest-dagster-1 Started ✔ Container mnchtest-superset-1 Started
Vous ne voyez pas cela ?
  • docker compose config échoue avec « variable is not set » — le .env n’a pas été rempli à partir de .env.example, ou un nom de variable dans .env ne correspond pas à ce qu’attend docker-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, 18088 ou 13000 ; arrêtez-le ou remappez le port hôte dans docker-compose.yml.

Accéder aux services en fonctionnement

ServiceURLConnexion
Supersethttp://__DEPLOY_HOST__:18088admin / SUPERSET_ADMIN_PASSWORD
Prefecthttp://__DEPLOY_HOST__:14200aucune configurée
Dagsterhttp://__DEPLOY_HOST__:13000aucune configurée

Les secrets GitHub Actions sont en écriture seule — il n’existe aucune commande gh pour les relire. Pour retrouver le mot de passe Superset actuel, connectez-vous en SSH à la VM et faites cat .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 test

Ou dans l’UI Dagster (port 13000) : Assets → sélectionner les assets dbt → Materialize.

Déployer les flows Prefect manuellement

cd .prefect prefect deploy --all

Nettoyage

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é une

La 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.