1. Principe Fondamental : Deux Niveaux
Le système repose sur une séparation claire entre l’orchestration et les applications :
-
sever-admin(ce repo) — le chef d’orchestre : playbooks Ansible + stack d’infrastructure partagée (broker, monitoring, admin UIs) -
Les repos applicatifs — chaque application vit dans son propre repo avec son propre
docker-compose.yml; Ansible les clone/pull et pilote leur cycle de vie
Poste de dev (make deploy/backup/restore)
│ Ansible over SSH
▼
┌──────────────────────────────────────────────────────────┐
│ AWS Lightsail — Debian — 18.158.207.98 │
│ user: admin — tous les repos dans /home/admin/app │
│ │
│ /home/admin/app/ │
│ ├── sever-admin/ ← ce repo (orchestration + │
│ │ stack infra partagée) │
│ ├── clarajob_sa/ ← repo appli ClaraJob │
│ │ └── docker-compose.yml (à la racine) │
│ ├── marketisia/ ← repo appli PredictX │
│ │ └── docker/docker-compose.yml │
│ ├── auth-server/ ← repo Keycloak + sa DB │
│ │ └── docker-compose.yml │
│ └── main-server-proxy/ ← repo Traefik │
│ └── docker-compose.yml │
│ │
│ Tous les containers partagent le réseau Docker externe │
│ ───────────── proxy_server_network ───────────────── │
└──────────────────────────────────────────────────────────┘
2. Les 5 Repos Git
| Repo | URL Git | Compose | Chemin serveur |
|---|---|---|---|
sever-admin |
|
|
|
clarajob_sa |
|
|
|
marketisia (PredictX) |
|
|
|
auth-server |
|
|
|
main-server-proxy |
|
|
|
3. Stack sever-admin (infrastructure partagée)
Le docker-compose.yml racine de sever-admin ne définit aucun service directement — il fusionne 7 fichiers via la directive include: (un seul projet Compose, donc docker compose up -d <service> marche pour n’importe quel service) :
| Fichier | Services (nom container) | Rôle |
|---|---|---|
|
|
Cache Redis 7 partagé (AOF, mot de passe requis, maxmemory 32mb LRU) |
|
|
Source de vérité unique de la stack messaging — consommée par hostname par les services applicatifs, jamais redéployée par eux |
|
|
UIs d’administration des bases de données |
|
|
Documentation statique Nginx (sert |
|
|
UIs web pour exécuter les playbooks Ansible (Semaphore : BoltDB ; Rundeck : H2, ~1 Go RAM) |
|
|
Logs Docker temps réel (Dozzle), métriques système (Beszel), UI Redis |
|
|
Logs centralisés : Promtail lit les logs des containers → Loki les stocke → Grafana les affiche |
# Depuis /home/admin/app/sever-admin :
docker compose up -d # tout le stack infra
docker compose up -d grafana # un seul service
docker compose -f docker-compose.observability.yml up -d # un seul groupe
4. Stacks Applicatifs
4.1. clarajob_sa (docker-compose.yml à la racine)
Services définis dans le compose du repo clarajob_sa :
-
clarajob-ddl— PostgreSQL (migrations dans le sous-dossierclarajob-ddl/) -
clarajob-mongo— MongoDB -
clarajob-mongoku— UI web MongoDB (Mongoku) -
clarajob-redis— Redis applicatif ClaraJob -
minio-service— Object storage S3 (MinIO) -
minio-backup— sidecarmc mirrorqui sauvegarde MinIO versclarajob_sa/backups/minio/ -
clarajob-front-api— API Spring Boot (image GitLab Registry) -
clarajob-front-gui— Frontend Vue.js servi par Nginx (le compose monteclarajob-front-gui/dist) -
swagger-ui,redoc,rapidoc— documentation API -
Cible Ansible supplémentaire :
clarajob-embedding(FastAPI, image GitLab)
4.2. marketisia / PredictX (docker/docker-compose.yml)
-
marketisia-ddl— PostgreSQL -
marketisia-redis— Redis -
marketisia-front-api— API Spring Boot (image GitLab) -
marketisia-front-gui— Frontend Vue.js (image GitLab) -
Consomme Kafka/RabbitMQ du broker partagé sever-admin par hostname (
marketisia-kafka:29092)
4.3. auth-server
-
auth_server_db— PostgreSQL pour Keycloak -
keycloak— IAM (authentification ClaraJob & co)
4.4. documentation
-
documentation— site statique AsciiDoc servi parnginx:latest(le compose montebuild/generatedSite, pré-généré en local pargradle asciidoctoret versionné dans le repo — aucune image Docker custom, aucun build au deploy). Accessible viadocumentation.clarajob.com/.marketisia.com/.pretydate.com(un seul router Traefikdocumentation, 3 hosts dans la rule)
4.5. main-server-proxy
-
traefik-service— reverse proxy Traefik : point d’entrée HTTPS de tous les domaines (adminer.clarajob.com,beszel.marketisia.com, etc. via labels Traefik sur les containers)
5. Couche Orchestration (Ansible)
sever-admin/
├── Makefile # 6 cibles : help, ping, backup, restore, deploy, setup-cron
├── Jenkinsfile # Pipeline CI/CD (backup pre-deploy + deploy)
├── .vault_password # (racine, non versionné en clair) — copié sur le serveur par setup-cron
└── ansible/
├── ansible.cfg # inventory, vault_password_file=~/.vault_sever_admin,
│ # roles_path=roles, host_key_checking=False, pipelining
├── inventory/
│ ├── hosts.yml # production: vps-main (18.158.207.98, user admin)
│ │ # local: localhost (ansible_connection: local)
│ └── group_vars/
│ ├── all/
│ │ ├── vars.yml # variables publiques (chemins, services, URLs git)
│ │ └── vault.yml # 🔐 secrets chiffrés (credentials DB, token registry)
│ └── local/
│ └── vars.yml # surcharges pour ENV=local
├── playbooks/
│ ├── deploy.yml # 19 cibles — validation + backups pre-deploy + déploiement
│ ├── backup.yml # 4 bases + all
│ ├── restore.yml # 4 bases + minio-service
│ └── setup-cron.yml # crons de backup sur le serveur
└── roles/
├── deploy/ # git pull → stop → docker login → pull(si TAG) → up -d
│ # → pause 10s → vérif container → rescue/rollback
├── deploy_frontend/ # git pull → build dans un container jetable (build_image/
│ # build_command, défaut npm ci && npm run build sur node)
│ # OU pull image si TAG → restart nginx → vérif → rollback
├── backup/ # pg_dump / mongodump / mysqldump dans le container
│ # → vérif dump non vide → fichier description
├── restore/ # psql / mongorestore --drop / mysql depuis le dump
└── restore_minio/ # mc mirror backup → volume, avec arrêt/redémarrage MinIO
6. Flux Réels
6.1. Flux 1 : Déploiement d’un stack complet (make deploy APP=clarajob-sa)
make deploy APP=clarajob-sa [TAG=v1.2.0] [BRANCH=develop]
│
▼ ansible-playbook playbooks/deploy.yml (vault auto via ansible.cfg)
│
├─ pre_tasks
│ ├─ assert : APP ∈ liste des 19 cibles
│ ├─ si container clarajob-ddl tourne → backup pre-deploy PostgreSQL ("pre-deploy")
│ └─ si container clarajob-mongo tourne → backup pre-deploy MongoDB ("pre-deploy")
│
├─ block (déploiement)
│ ├─ git clone (si absent) ou clean -fd + pull (branche main par défaut)
│ │ clé SSH serveur : /home/admin/.ssh/id_ed25519
│ ├─ docker login registry.gitlab.com (deploy token vault)
│ ├─ IMAGE_TAG=<tag> docker compose pull clarajob-ddl clarajob-front-api
│ │ clarajob-front-gui clarajob-embedding
│ ├─ IMAGE_TAG=<tag> docker compose up -d (tout le stack)
│ ├─ pause 15s
│ └─ docker ps → liste des containers actifs affichée
│
└─ rescue (si échec)
├─ docker compose up -d (rollback : relance le stack)
└─ fail avec message explicite
6.2. Flux 2 : Backup automatique quotidien (cron installé par make setup-cron)
03:00 backup-marketisia-sa-daily → pg_dump marketisia-ddl
04:00 backup-clarajob-ddl-daily → pg_dump clarajob-ddl
05:00 backup-clarajob-mongo-daily → mongodump clarajob-mongo
│
│ (exécutés PAR le serveur lui-même : ansible-playbook local,
│ vault: /opt/.vault_password, logs: /var/log/ansible-backup.log)
▼
/home/admin/app/sever-admin/db-config/dump/<service>/<service>-YYYY-MM-DD_HHMMSS.{sql|archive}
/home/admin/app/sever-admin/db-config/dump_description/<service>/..._auto-backup.txt
6.3. Flux 3 : Restauration (make restore APP=clarajob-mongo DUMP=…)
make restore APP=clarajob-mongo DUMP=clarajob-mongo-2026-07-26_050000.archive
│
├─ vérifie que le container tourne
├─ vérifie que db-config/dump/clarajob-mongo/<DUMP> existe (échec sinon)
└─ docker exec -i clarajob-mongo mongorestore --drop --archive < dump
(--drop : écrase les collections existantes)
6.4. Flux 4 : CI/CD Jenkins
Jenkins (déclenchement manuel ou webhook GitLab)
│ paramètres : TARGET_APP ∈ {clarajob-sa, marketisia-sa}, SKIP_BACKUP (bool)
├─ stage Checkout
├─ stage Backup pre-deploy (sauf si SKIP_BACKUP)
│ → ansible-playbook playbooks/backup.yml -e target_app=$TARGET_APP
└─ stage Deploy
→ ansible-playbook playbooks/deploy.yml -e target_app=$TARGET_APP
(credential Jenkins "VAULT_PASSWORD_FILE" = fichier secret vault)
7. Modèle de Sécurité
Poste de dev
├─ ~/.ssh/serverAdminSSHKeypair.pem → SSH vers admin@18.158.207.98
└─ ~/.vault_sever_admin → déchiffre inventory/group_vars/all/vault.yml
Serveur
├─ /home/admin/.ssh/id_ed25519 → le serveur pull les repos GitLab (deploy Ansible)
├─ /opt/.vault_password → utilisé par les crons de backup (root, 600)
└─ Secrets injectés aux containers via variables d'environnement compose
Vault (vault.yml) contient :
vault_marketisia_sa_db_{name,user,pass}
vault_clarajob_ddl_db_{name,user,pass}
vault_clarajob_mongo_db_{name,user,pass}
vault_auth_server_db_{name,user,pass}
vault_gitlab_registry_token (deploy token read-only registry.gitlab.com)
Registry : registry.gitlab.com, utilisateur group_registry_deploy_token.
8. Ports Exposés (réels)
8.1. Infrastructure sever-admin
| Service | Container | Port hôte → container | Variable |
|---|---|---|---|
Documentation |
|
|
|
Adminer |
|
|
— |
pgAdmin |
|
|
|
Semaphore |
|
|
|
Rundeck |
|
|
|
Dozzle |
|
|
|
Beszel Hub |
|
|
— |
Beszel Agent |
|
host network (45876) |
|
Grafana |
|
|
|
Loki |
|
interne (3100) |
— |
Promtail |
|
interne |
— |
Redis |
|
|
|
RedisInsight |
|
|
— |
8.2. Broker messaging partagé
| Service | Container | Port hôte → container | Variable |
|---|---|---|---|
Kafka |
|
|
|
Zookeeper |
|
interne (2181) |
— |
Schema Registry |
|
|
|
RabbitMQ (AMQP) |
|
|
|
RabbitMQ Management |
|
|
|
Kafka UI |
|
|
|
|
Le port |
9. Points Clés à Retenir
-
sever-admin n’héberge pas les applications — il les orchestre. Chaque appli a son compose dans son repo.
-
Le réseau
proxy_server_network(externe) relie tout : les applis consomment Kafka, Redis, les DBs par hostname de container. -
Le broker (Kafka/RabbitMQ) appartient à sever-admin — les applis ne le redéploient jamais.
-
Chaque déploiement de DB fait un backup pre-deploy automatique si le container tourne.
-
Tous les déploiements ont un rollback automatique (block/rescue Ansible) : en cas d’échec, le service est relancé et le playbook échoue avec un message explicite.
-
Deux modes d’exécution :
ENV=remote(production) etENV=local(ta machine), même code.