{}const=>[]async()letfn</>var
DéveloppementBases

CI/CD en quelques mots : déploiement automatique en une soirée

Une explication simple de CI/CD et un exemple prêt à l'emploi d'auto-déploiement via GitHub Actions.

К

Kodik

Auteur

5 min de lecture

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. 🧘‍♂️

🔥 100 000+ étudiants déjà avec nous

Marre de lire la théorie ?
Il est temps de coder !

Kodik — une appli où tu apprends à coder par la pratique. Mentor IA, leçons interactives, projets réels.

🤖 IA 24/7
🎓 Certificats
💰 Gratuit
🚀 Commencer
Ont rejoint aujourd'hui

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 :latest poussez :v1.4.2 — il est plus facile de revenir en arrière.

  • Rollback: basculer la balise dans docker-compose.yml et répéter pull/up -d.

  • Schéma bleu/vert (simplifié) : maintenez deux services web_blue et web_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 /health et /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 .env, docker logs, healthcheck, exécutez les migrations

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

docker system prune -f, rotation des journaux

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 ?

🎯Arrête de reporter

Tu as aimé l'article ?
Place à la pratique !

Avec Kodik, tu ne lis pas seulement — tu codes immédiatement. Théorie + pratique = vraies compétences.

Pratique instantanée
🧠L'IA explique le code
🏆Certificat

Sans inscription • Sans carte