CI/CD & déploiement Docker
Chaîne test → containerize → deploy sous GitLab CI, alignée sur le modèle
maison (CRM staff_and_companiesms) : registre GitLab Container Registry,
déploiement Ansible sur un hôte Docker, exposition via Traefik. Pour les
builds locaux, voir Déploiement.
Vue d'ensemble
push / MR ─► test:api ─► package:image:{api,web,docs} ─► GitLab Registry ─► deploy:int:ansible
| Image | Source | Contenu | Port |
|---|---|---|---|
api | Dockerfile.api | NestJS + Prisma (Debian) | 3000 (interne) |
web | Dockerfile.web | nginx : 4 SPA origine unique + proxy /api, /uploads | 80 |
docs | Dockerfile.docs | Docusaurus statique | 80 |
Images : $CI_REGISTRY_IMAGE/{api,web,docs}:<tag> (GitLab Container Registry) où
le tag vaut $CI_COMMIT_TAG sinon $CI_COMMIT_REF_SLUG (ex. develop). Les SPA
sont buildées avec VITE_API_URL=/api/v1 (relatif) → bundle portable.
Dépendances / prérequis
Sur le serveur cible (intégration : jenkins@192.168.17.71:9257)
- Docker Engine ≥ 24 + Docker Compose v2, accès au GitLab Container Registry.
- Utilisateur SSH
jenkins(clé publique installée),~/.profilechargeant le PATH Docker. - Réseau Docker externe
ingress(Traefik) déjà présent :docker network create ingresssi absent. - Traefik en frontal terminant le TLS (certresolver
id2realnet). - Un PostgreSQL externe accessible (la stack ne contient pas de service Postgres).
- Répertoire de déploiement
/docker-apps/e-learning(créé par le playbook).
Runtime des images
api: Node 20 (Debian), client Prisma + engine + CLI inclus. Volume./uploads.web/docs:nginx:alpine, statique.
Variables CI/CD à créer
Dans Settings → CI/CD → Variables du projet GitLab :
| Variable | Type | Usage |
|---|---|---|
SSHKEY_CI | File | clé privée SSH du compte de déploiement jenkins |
INTEGRATION_ENV | File | contenu du .env d'intégration (secrets : DATABASE_URL, JWT_SECRET…). Voir ansible/environments/integration_env.example pour les clés attendues. |
Le registre utilise les variables GitLab intégrées (CI_REGISTRY,
CI_REGISTRY_USER, CI_JOB_TOKEN, CI_REGISTRY_IMAGE) — rien à créer.
L'hôte, le port (9257), l'utilisateur et le compose_dir sont définis dans
ansible/inventory.yaml (pas en variables CI).
Pull côté serveur
- Déploiement CI : le playbook fait un
docker loginsur l'hôte cible avec les variables CI (CI_REGISTRY/CI_REGISTRY_USER/CI_JOB_TOKEN, valide pendant le job) avantdocker compose pull. Aucun deploy token persistant requis.- Intervention manuelle :
CI_JOB_TOKENétant absent, la tâche de login est sautée (when: reg_token | length > 0) — c'est à l'opérateur de faire son propredocker loginau registre avant de lancer le playbook oudocker compose.
Structure de déploiement (Ansible)
ansible/
├── inventory.yaml # hôtes par environnement (integration)
├── deployment_playbook.yaml # down → copie compose+.env → pull → up -d
├── docker-compose.integration.yaml # stack déployée (api+web+docs, Traefik, réseau ingress)
└── environments/
└── integration_env.example # modèle des clés ; le vrai fichier vient de la variable File INTEGRATION_ENV
Le job deploy:int:ansible matérialise d'abord environments/integration_env
à partir de la variable File INTEGRATION_ENV (hors dépôt). Le playbook dépose
ensuite docker-compose.integration.yaml → compose.yaml et
environments/integration_env → .env dans /docker-apps/e-learning, puis
docker compose pull && up -d --force-recreate. Les images sont interpolées
depuis le .env : image: ${REGISTRY_IMAGE}/<svc>:${TAG}. Le job
deploy:int:ansible y injecte REGISTRY_IMAGE=$CI_REGISTRY_IMAGE
et TAG=${CI_COMMIT_TAG:-CI_COMMIT_REF_SLUG} avant qu'Ansible ne copie le fichier.
Déclencheurs par branche
| Branche / événement | test | containerize | deploy |
|---|---|---|---|
| Merge request | ✅ | — | — |
develop | ✅ | ✅ | intégration (auto) |
master | ✅ | ✅ | — (images buildées, pas de cible prod définie) |
| tag git | ✅ | ✅ | — |
Première mise en place
- Variable
SSHKEY_CI(File) : clé privée SSHjenkins(le registre utilise les variables GitLab intégrées). - Variable
INTEGRATION_ENV(File) : coller le contenu du.envd'intégration (clés deintegration_env.example), avec leDATABASE_URLréel (Postgres externe) et unJWT_SECRETunique :openssl rand -base64 48 - Domaines Traefik : ajuster les
Host(...)dansdocker-compose.integration.yaml(e-learn-st.id2real.netpour le web,docs.e-learn-st.id2real.netpour la doc). - Réseau ingress présent sur l'hôte (
docker network ls). - Pousser sur
develop→ le pipeline build les 3 images puisdeploy:int:ansibledéploie. Les migrations Prisma s'appliquent au boot (RUN_MIGRATIONS=true→prisma migrate deploy).
Rollback
Le playbook sauvegarde l'ancien compose (compose.yaml.backup). Pour revenir à
une image précédente, déployer un tag connu-bon (re-pousser le commit, ou figer
un tag d'image dans le compose) puis relancer le pipeline / docker compose up -d.
Voir aussi
- Déploiement — builds, variables d'environnement, reverse-proxy
- Base de données — migrations, backup, restauration