Qu'est-ce que CI/CD et pourquoi en avez-vous besoin
CI (Continuous Integration) — chaque modification est collectée et testée automatiquement.
CD (Continuous Delivery/Deployment) — après le succès, nous déployons sur le stand/produit sans les mains.
Avantages : moins d'erreurs manuelles, des versions rapides, de la transparence pour l'équipe et des déploiements prévisibles. 🧘♂️
Serveur : formation de base (VPS)
# 1) Docker et plugin compose (Ubuntu)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# 2) Catalogue des applications
sudo mkdir -p /opt/myapp && sudo chown -R $USER:$USER /opt/myapp
cd /opt/myapp
# 3) .env (sur le serveur, ne pas commiter)
cat > .env << 'ENV'
PORT=3000
ENV
# 4) docker-compose.yml
cat > docker-compose.yml << 'YAML'
services:
web:
image: registry.example.com/myapp:latest
env_file: .env
ports:
- "80:3000"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 10s
timeout: 3s
retries: 5
YAML
# 5) Premier lancement (sans CI pour le moment)
docker compose pull && docker compose up -d
Dockerfile (exemple minimal pour Node/PNPM)
# Dockerfile
FROM node:20-alpine AS deps
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm i --frozen-lockfile
FROM node:20-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules node_modules
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/dist dist
COPY package.json ./
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm i --prod --frozen-lockfile
EXPOSE 3000
CMD ["node", "dist/server.js"]
GitHub Actions : création d'image et déploiement via SSH
Ajoutez au dépôt .github/workflows/deploy.yml :
name: CI/CD Deploy
on:
push:
branches: [ "main" ]
permissions:
contents: read
packages: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Buildx
uses: docker/setup-buildx-action@v3
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.REGISTRY_URL }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build & push image
uses: docker/build-push-action@v6
with:
push: true
context: .
tags: ${{ secrets.REGISTRY_URL }}/${{ secrets.IMAGE_NAME }}:latest
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
set -e
cd /opt/myapp
docker compose pull
docker compose up -d
docker image prune -f
Secrets : REGISTRY_URL, REGISTRY_USER, REGISTRY_PASSWORD, IMAGE_NAME, SERVER_HOST, SERVER_USER, SERVER_SSH_KEY.
GitLab CI : une alternative
# .gitlab-ci.yml
stages: [build, deploy]
variables:
IMAGE: $CI_REGISTRY_IMAGE:latest
build:
stage: build
image: docker:27.0
services: [ "docker:27.0-dind" ]
script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- docker build -t $IMAGE .
- docker push $IMAGE
artifacts:
expire_in: 1 week
when: on_success
paths: []
deploy:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
script:
- ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$DEPLOY_HOST "
set -e
cd /opt/myapp &&
docker compose pull &&
docker compose up -d &&
docker image prune -f
"
only:
- main
Zéro temps d'arrêt et de roulement
Zero‑downtime:
restart: unless-stopped+healthcheck+up -d— le nouveau conteneur démarre, l'ancien s'éteint.Balises de publication : en plus de
:latestpoussez:v1.4.2— il est plus facile de revenir en arrière.Rollback: basculer la balise dans
docker-compose.ymlet répéterpull/up -d.Schéma bleu/vert (simplifié) : maintenez deux services
web_blueetweb_green, équilibrez le trafic via Nginx.
Vérifications minimales dans le pipeline
# exemple d'étape avec des tests dans GitHub Actions
- name: Install deps & test
run: |
npm ci
npm run test -- --ci
Seuil pour le CI « du soir » : exécuter les tests unitaires, assembler la version, passer le linter (ESLint/flake8), vérifier les types (tsc/mypy).
Surveillance et journalisation
Ajoutez
/healthet/metrics(format Prometheus) au service.Collecte de journaux :
docker logs→ Loki/ELK ; alertes par code d'état/latence.Dans CI, il y a des artefacts avec des rapports de test et de linter pour voir les régressions.
Secrets et sécurité
Secrets uniquement dans Secrets / Variables CI ;
.env- sur le serveur.Désactivez la connexion SSH par mot de passe, laissez la connexion par clé, limitez les ports.
Ne stockez pas les clés privées dans le dépôt, même sous forme chiffrée.
🧯 Problèmes courants et solutions rapides
Symptôme | Raison | Fix |
|---|---|---|
CI tombe sur l'assemblage | RAM insuffisante / délai d'attente | Mise en cache des calques, base d'image plus légère, augmenter le délai d'attente |
L'application ne démarre pas | Port/ENV/migration | Vérifiez |
Déploiement lent | Image lourde | Multi-stage, alpine, .dockerignore, mise en cache des dépendances |
« Ça marche pour moi » | Différentes versions de Node/Python | Verrouillez les versions dans Docker, utilisez des fichiers de verrouillage |
Le disque est plein | Images/conteneurs anciens |
|
Dans l'application « Kodik - apprentissage de la programmation » — des leçons courtes et des mini-projets. C'est intéressant chez nous !
Et nous avons aussi un chaîne de télégram, où nous discutons d'idées intéressantes, partageons nos expériences et analysons ensemble les tâches, apprendre devient non seulement utile, mais aussi amusant.
Total
CI/CD n'est pas une « grande magie », mais un ensemble d'étapes simples. Assemblez une image, poussez-la dans le registre, redémarrez le service sur VPS et vous obtenez des versions rapides et reproductibles sans routine manuelle. Commencez dès aujourd'hui, et demain, l'équipe aura déjà oublié à quoi ressemblait le déploiement manuel.
Sur quoi allez-vous tourner l'autodeploy — GitHub Actions ou GitLab CI ?
