Version : 1.0.0 Dernière mise à jour : 21/01/2026 Auteur : Claude + Gouroubleu
Smart-Deploy est un système de déploiement hybride combinant GitLab CI/CD avec des scripts bash modulaires. Il supporte plusieurs stratégies de déploiement (Docker, Files, Remote) avec health check obligatoire et rollback automatique.
┌─────────────────────────────────────────────────────────────────┐
│ SMART-DEPLOY SYSTEM │
├─────────────────────────────────────────────────────────────────┤
│ │
│ git push → GitLab CI → Runner → smart-deploy.sh │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ ▼ │
│ [docker.sh] [files.sh] [remote.sh] │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ prod-portainer nginx/pve o2switch │
│ │ │ │ │
│ └──────────────────┼──────────────────┘ │
│ ▼ │
│ [health check] │
│ │ │
│ ┌────────┴────────┐ │
│ ▼ ▼ │
│ [SUCCESS] [ROLLBACK] │
│ │ │ │
│ ▼ ▼ │
│ [notify] [notify] │
│ │
└─────────────────────────────────────────────────────────────────┘
/stock_8to/33800-stack/scripts/deploy/
├── smart-deploy.sh # Script principal (appelé par CI/CD)
├── rollback.sh # Script rollback manuel
├── machines-registry.json # Registre des machines cibles
├── README.md # Documentation utilisateur
│
├── lib/ # Modules partagés
│ ├── common.sh # Fonctions utilitaires (log_*, require_*)
│ ├── parse-yaml.sh # Parser YAML pour conf.gouroubleu.yml
│ ├── targets.sh # Résolution des targets
│ ├── services.sh # Injection variables de services
│ ├── dns.sh # Gestion DNS O2switch
│ ├── nginx.sh # Génération config Nginx
│ ├── notifications.sh # Notifications push (ntfy)
│ ├── registry.sh # Registre des services déployés
│ └── health.sh # Health check enrichi
│
├── strategies/ # Stratégies de déploiement
│ ├── docker.sh # Docker (build, push, compose)
│ ├── files.sh # Files (releases + symlinks)
│ └── remote.sh # Remote (rsync/git vers o2switch)
│
└── templates/ # Templates
├── Dockerfile.node
├── Dockerfile.bun
├── Dockerfile.python
├── Dockerfile.rust
├── Dockerfile.static
└── nginx-*.conf.template
| Phase | Description | Status |
|---|---|---|
| 1 | Infrastructure de base (scripts, registry) | ✅ |
| 2 | Stratégie Docker (templates, build, push) | ✅ |
| 3 | Services & Variables (injection auto) | ✅ |
| 4 | DNS & Nginx (auto-génération) | ✅ |
| 5 | Stratégies Files & Remote | ✅ |
| 6 | Notifications & Registre | ✅ |
| 7 | Health Check & Documentation | ✅ |
name: "mon-api"
target: "prod-portainer" # Machine cible
type: "node" # node, bun, python, rust, static
port: 3000 # Port d'écoute
domain: "api.33800.nowhere84.com"
# Services à injecter (variables auto)
services:
- supabase # DATABASE_URL, SUPABASE_URL, SUPABASE_ANON_KEY
- redis # REDIS_URL
- ntfy # NTFY_URL, NTFY_TOPIC
# Nginx (auto-généré si enabled)
nginx:
enabled: true
ssl: true
websocket: false
# Health check (obligatoire)
health: "/health"
# Logs Loki
logs: true
# Pour stratégie files
storage:
shared: "logs data uploads"
keep_releases: 5
# Pour stratégie remote
deploy:
method: rsync # rsync ou git
dest: "mon-app"
backup: true
pre_deploy: "npm install"
post_deploy: "pm2 restart"
| Champ | Obligatoire | Description |
|---|---|---|
| name | Oui | Nom unique du service |
| target | Oui | Machine cible (prod-portainer, nginx, o2switch...) |
| type | Non | Type de projet (auto-détecté si absent) |
| port | Non | Port d'écoute (requis pour health check) |
| domain | Non | Domaine public |
| health | Non | Endpoint health check (défaut: /health) |
| services | Non | Liste des services à injecter |
| nginx | Non | Configuration Nginx |
| storage | Non | Configuration stockage (stratégie files) |
| deploy | Non | Configuration déploiement (stratégie remote) |
| Target | Type | IP | Usage |
|---|---|---|---|
| prod-portainer | docker | 192.168.1.12 | Containers PROD |
| dev-portainer | docker | 192.168.1.51 | Containers DEV |
| nginx | files | 192.168.1.104 | Sites statiques, apps Node |
| pve | files | 192.168.1.4 | Scripts, services locaux |
| o2switch | remote | yellow.o2switch.net | Dashboard, sites externes |
| win11 | files | 192.168.1.30 | Apps Windows |
| gitlab | files | 192.168.1.196 | Services GitLab |
docker compose up -dStructure Capistrano-like :
/opt/33800-services/mon-app/
├── releases/
│ ├── 2026-01-21_12-00-00-abc1234/
│ └── 2026-01-21_13-00-00-def5678/
├── shared/
│ ├── logs/
│ ├── data/
│ └── config/
└── current -> releases/2026-01-21_13-00-00-def5678
Le service doit exposer un endpoint /health (configurable) retournant :
{
"status": "healthy",
"version": "1.2.3",
"uptime": {
"seconds": 3600,
"human": "1h 0m 0s"
},
"timestamp": "2026-01-21T12:00:00Z",
"system": {
"hostname": "container-id",
"platform": "linux",
"nodeVersion": "v20.20.0",
"memory": {
"used": 128,
"total": 512,
"unit": "MB"
},
"cpu": "1.23"
},
"scheduledJobs": [
{
"name": "cleanup",
"cron": "0 0 * * *",
"description": "Daily cleanup",
"enabled": true
}
],
"dependencies": [
{
"name": "database",
"status": "healthy",
"url": "postgres://***:***@host:5432/db"
}
],
"metrics": {
"requestsTotal": 1234,
"errorsTotal": 5
}
}
| Condition | Action |
|---|---|
| HTTP 200 + status="healthy" | Déploiement réussi |
| HTTP 200 + status!="healthy" | Retry (max 10 fois) |
| HTTP 503 | Rollback immédiat |
| Timeout (30s) | Retry puis rollback |
| Connexion impossible | Retry puis rollback |
HEALTH_CHECK_TIMEOUT=30 # Timeout par requête (secondes)
HEALTH_CHECK_RETRIES=10 # Nombre de tentatives
HEALTH_CHECK_INTERVAL=3 # Secondes entre tentatives
Déclenché si :
# Rollback 1 version en arrière
/stock_8to/33800-stack/scripts/deploy/rollback.sh conf.prod.gouroubleu.yml 1
# Rollback 2 versions
/stock_8to/33800-stack/scripts/deploy/rollback.sh conf.prod.gouroubleu.yml 2
Envoyées via ntfy (https://ntfy.33800.nowhere84.com/deploy)
| Événement | Priorité | Tags |
|---|---|---|
| Deploy Start | low | 🚀 |
| Deploy Success | default | ✅ |
| Deploy Failure | high | ❌⚠️ |
| Health Check Failed | urgent | 🚑🚨 |
| Rollback | high | ⏪⚠️ |
/stock_8to/33800-stack/monitoring/services-registry.json
{
"services": {
"mon-service": {
"target": "prod-portainer",
"strategy": "docker",
"last_deploy": "2026-01-21T12:00:00Z",
"commit": "abc1234",
"version": "1.2.3",
"domain": "mon-service.33800.nowhere84.com",
"port": 3000,
"status": "running",
"branch": "main",
"env": "prod"
}
},
"last_updated": "2026-01-21T12:00:00Z"
}
https://dashboard.nowhere84.com/services.html
stages:
- deploy
deploy-prod:
stage: deploy
tags:
- prod-runner
image: docker:27
before_script:
- apk add --no-cache bash curl jq openssh-client rsync
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
script:
- bash /mnt/stock_8to/33800-stack/scripts/deploy/smart-deploy.sh
rules:
- if: $CI_COMMIT_BRANCH == "main"
variables:
DEPLOY_ENV: "prod"
DEPLOY_CONFIG: "conf.prod.gouroubleu.yml"
CI_REGISTRY: "registry.33800.nowhere84.com"
CI_REGISTRY_USER: "gouroubleu"
CI_REGISTRY_PASSWORD: "glpat-yaowLwWBJhXfzJEC8UBC"
main → Deploy PRODdevelop → Deploy DEV (si configuré)mkdir mon-api && cd mon-api
npm init -y
npm install express
// index.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
const startTime = Date.now();
const pkg = require('./package.json');
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
version: pkg.version,
uptime: {
seconds: Math.floor((Date.now() - startTime) / 1000),
human: formatUptime(Math.floor((Date.now() - startTime) / 1000))
},
timestamp: new Date().toISOString()
});
});
app.listen(PORT, () => console.log(`Running on ${PORT}`));
# conf.prod.gouroubleu.yml
name: "mon-api"
target: "prod-portainer"
type: "node"
port: 3000
domain: "mon-api.33800.nowhere84.com"
health: "/health"
Copier le template .gitlab-ci.yml ci-dessus.
git init
git remote add origin git@gitlab.33800.nowhere84.com:gouroubleu/mon-api.git
git add .
git commit -m "Initial commit"
git push -u origin main
Le fichier conf.prod.gouroubleu.yml n'existe pas à la racine du projet.
/healthexport HEALTH_CHECK_TIMEOUT=60
export HEALTH_CHECK_RETRIES=20
:previous existe dans le registryreleases/curl https://ntfy.33800.nowhere84.com/healthNTFY_ENABLED=trueLe fichier a été créé par root. Corriger :
sudo chown gouroubleu:gouroubleu /stock_8to/33800-stack/monitoring/services-registry.json
Les releases sont automatiquement nettoyées selon keep_releases (défaut: 5).
docker image prune -a --filter "until=168h"
cat /stock_8to/33800-stack/monitoring/services-registry.json | jq '.services | to_entries[] | {name: .key, status: .value.status}'
| Date | Version | Changements |
|---|---|---|
| 20/01/2026 | 0.1 | Phase 1-6 : Infrastructure, Docker, Files, Remote, Notifications |
| 21/01/2026 | 1.0 | Phase 7 : Health check enrichi, documentation, dashboard services |