L'essentiel pour ton projet SOSLock
Bootcode KIRI-S04 — Semaine 3
1. Automatiser les tests avec CI
Chaque push = lint + test + build automatique
2. Dockeriser SOSLock
Backend Express/TS + Frontend React/Vite
3. Déployer en production
VPS + Docker Compose + GitHub Actions
4. Gérer les secrets
Jamais dans le code, toujours dans GitHub Secrets
CI/CD : Les concepts essentiels
Intégration continue, livraison continue, déploiement continu
GitHub Actions : Ton premier pipeline CI
Workflows YAML, triggers, jobs, secrets, cache
Dockeriser SOSLock
Dockerfile backend + frontend multi-stage + Compose production
Déployer sur un VPS
GHCR, SSH deploy, variables d'environnement
Pièges courants
Les erreurs qui font perdre des heures
Tu déploies SOSLock à la main ?
1️⃣
SSH sur le serveur
Manuel, erreur de mot de passe
2️⃣
git pull + npm build
Tu oublies npm install ?
3️⃣
Redémarrer le serveur
Et si les tests passent pas ?
Résultat : déploiements lents, erreurs fréquentes, impossible de revenir en arrière
CI — Intégration Continue
Chaque push déclenche automatiquement lint + tests + build
On détecte les erreurs immédiatement, pas en production
CD — Livraison Continue
Le code est prêt à déployer après le CI (artefact = image Docker)
Tu décides QUAND déployer — ce n'est pas automatique
CD — Déploiement Continu
Le code est déployé automatiquement en production après le CI
Risqué pour SOSLock au début — préfère la livraison continue
Automatise tout, directement dans ton repo
Un workflow = un fichier YAML dans .github/workflows/
C'est du code versionné comme le reste de ton projet
name: CI SOSLock
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
on
Quand déclencher
jobs
Groupes d'étapes
steps
Actions unitaires
uses/run
Réutiliser / Exécuter
soslock-api (Express/TS)
jobs:
backend:
runs-on: ubuntu-latest
defaults:
working-directory: ./backend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
soslock-frontend (React/Vite)
jobs:
frontend:
runs-on: ubuntu-latest
defaults:
working-directory: ./frontend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npm run lint
- run: npm run build
Les 2 jobs tournent en parallèle — gain de temps !
❌ JAMAIS ça
env:
DATABASE_URL: "postgres://admin:pass123@db:5432/soslock"
Mot de passe visible dans le code Git !
✅ Toujours ça
env:
DATABASE_URL: ${{{ secrets.DATABASE_URL }}}
GitHub Secrets injecte la valeur automatiquement
Configuration : Settings → Secrets and variables → Actions → New repository secret
Pour SOSLock : DATABASE_URL, JWT_SECRET, SSH_PRIVATE_KEY, VPS_HOST
# Ajoute ça dans chaque job, avant npm ci
- name: Cache npm
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{{ hashFiles('**/package-lock.json') }}}
restore-keys: npm-
Sans cache
~60s
npm ci télécharge tout à chaque run
Avec cache
~5s
Les dépendances sont restaurées depuis le cache
Backend Express/TS + Frontend React/Vite
Pourquoi Docker ?
Même environnement partout : dev = staging = production
Plus de "ça marche chez moi"
# backend/Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["node", "dist/server.js"]
Multi-stage : le builder compile TypeScript, le runner ne contient que le nécessaire pour exécuter
# frontend/Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx sert les fichiers statiques du build Vite — pas besoin de Node.js en production
services:
backend:
image: ghcr.io/you/soslock-api:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
env_file: .env
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
frontend:
image: ghcr.io/you/soslock-frontend:latest
restart: unless-stopped
ports:
- "80:80"
db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U soslock"]
restart: unless-stopped
Redémarre automatiquement si le conteneur crash ou si le serveur reboot
healthcheck
Docker sait si le service est vraiment healthy, pas juste "en cours d'exécution"
depends_on + condition
Le backend attend que PostgreSQL soit prêt avant de démarrer
volumes pour la DB
Les données PostgreSQL survivent au redémarrage des conteneurs
Ton serveur dédié pour SOSLock
1️⃣ Acheter un VPS (Hetzner, OVH, DigitalOcean...)
2️⃣ SSH + installer Docker + Docker Compose
3️⃣ Clé SSH dédiée pour le déploiement automatique
name: Deploy SOSLock
on:
push:
branches: [main]
jobs:
deploy:
needs: [backend, frontend] # attend le CI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 1) Build & push les images Docker
- uses: docker/login-action@v3
with:
registry: ghcr.io
token: ${{{ secrets.GITHUB_TOKEN }}}
- run: docker build -t ghcr.io/you/soslock-api:latest ./backend
- run: docker push ghcr.io/you/soslock-api:latest
- run: docker build -t ghcr.io/you/soslock-frontend:latest ./frontend
- run: docker push ghcr.io/you/soslock-frontend:latest
# 2) SSH deploy sur le VPS
- uses: appleboy/ssh-action@v1
with:
host: ${{{ secrets.VPS_HOST }}}
key: ${{{ secrets.SSH_PRIVATE_KEY }}}
script: |
cd /opt/soslock
docker compose pull
docker compose up -d
❌ .env dans Git
# .env commité — DANGER !
DATABASE_URL=postgres://admin:pass@db:5432/soslock
JWT_SECRET=my-super-secret-key
Tout le monde a accès à tes secrets !
✅ .env sur le serveur uniquement
# Sur le VPS : /opt/soslock/.env
DATABASE_URL=postgres://prod_user:xxx@db:5432/soslock
JWT_SECRET=a8f3b2c1d4...
Le fichier .env n'existe que sur le serveur
# .gitignore — TOUJOURS
.env
.env.production
❌ Toujours :latest
Impossible de rollback si tu n'as pas de tag de version
✅ Tag par commit SHA
soslock-api:abc1234 — tu peux revenir à n'importe quelle version
❌ Oublier docker compose pull
L'ancienne image est réutilisée depuis le cache local
✅ pull avant up
docker compose pull && docker compose up -d
❌ Pas de healthcheck
Docker croit que le conteneur est healthy alors que l'app a crashé
✅ healthcheck sur chaque service
wget --spider /health pour le backend, pg_isready pour la DB
❌ YAML mal indenté
Une erreur d'espace casse tout le workflow GitHub Actions
✅ Valide ton YAML
Utilise yamllint ou le validateur intégré de GitHub
CI = filet de sécurité
Chaque push = lint + test + build automatique
Docker = même environnement
Multi-stage build pour des images légères
Compose = orchestration
restart + healthcheck + depends_on pour la prod
Secrets = jamais dans Git
GitHub Secrets + .env sur le serveur uniquement
SOSLock en production : push → CI → build Docker → deploy VPS
Tout automatique, tout reproductible, tout sécurisé