DevToolBoxGRATUIT
Blog

GitHub Actions + Docker CI/CD: Build, Push et Déploiement

13 minpar DevToolBox

Un pipeline CI/CD robuste avec GitHub Actions et Docker automatise tout le cycle de déploiement. Ce guide construit un pipeline de niveau production avec des builds multi-plateforme et des déploiements sans temps d'arrêt.

Vue d'ensemble du pipeline

Le pipeline comporte quatre étapes : CI (test), Build (image Docker), Push (vers le registre) et Deploy (vers le serveur).

Pipeline Flow:
  git push → GitHub Actions triggered
       │
       ├─ [Job 1] CI: npm test, lint, type-check
       │         (runs on all PRs and main pushes)
       │
       ├─ [Job 2] Build: docker build --platform linux/amd64,linux/arm64
       │         (runs only on main branch push)
       │         Push to ghcr.io/org/app:sha-abc1234
       │
       └─ [Job 3] Deploy: SSH to server, docker pull + restart
                 (runs after successful build)
                 Zero-downtime with blue-green or rolling restart

Meilleures pratiques pour Dockerfile

Un Dockerfile bien structuré est la base. Les builds multi-étapes réduisent considérablement la taille de l'image finale.

# Multi-stage Dockerfile (Node.js example)

# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && cp -R node_modules /prod_node_modules
RUN npm ci   # install ALL deps for building

# Stage 2: Builder
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# Stage 3: Production runner (minimal image)
FROM node:20-alpine AS runner
WORKDIR /app

# Security: run as non-root user
RUN addgroup --system --gid 1001 nodejs \
 && adduser --system --uid 1001 appuser

# Copy only what's needed for runtime
COPY --from=deps /prod_node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./

USER appuser
EXPOSE 3000

# Health check for orchestrators
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
  CMD wget -qO- http://localhost:3000/health || exit 1

CMD ["node", "dist/index.js"]

# Result: ~150MB instead of ~800MB for the same app

Pipeline CI/CD de base

Ce workflow construit et pousse vers GitHub Container Registry (ghcr.io) à chaque push sur main.

# .github/workflows/deploy.yml

name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  # Stage 1: Test
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Run lint
        run: npm run lint

  # Stage 2: Build and Push Docker image
  build-push:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    permissions:
      contents: read
      packages: write

    outputs:
      image-digest: ${{ steps.build.outputs.digest }}

    steps:
      - uses: actions/checkout@v4

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}  # Auto-provided by GitHub

      - name: Extract Docker metadata (tags, labels)
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=sha,prefix=sha-
            type=raw,value=latest,enable={{is_default_branch}}

      - name: Build and push Docker image
        id: build
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  # Stage 3: Deploy to server
  deploy:
    needs: build-push
    runs-on: ubuntu-latest
    environment: production  # GitHub Environment with protection rules

    steps:
      - name: Deploy to production server via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            # Pull latest image
            echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
            docker pull ghcr.io/${{ github.repository }}:latest

            # Zero-downtime restart
            docker compose -f /app/docker-compose.prod.yml up -d --no-deps app

            # Verify deployment
            sleep 10
            docker compose -f /app/docker-compose.prod.yml ps

Fonctionnalités avancées du pipeline

Les pipelines de production nécessitent des fonctionnalités supplémentaires : builds multi-plateforme, analyse de sécurité et déploiements sans temps d'arrêt.

# Advanced Pipeline Features

# 1. Multi-platform builds (AMD64 + ARM64)
- name: Set up QEMU
  uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build multi-platform image
  uses: docker/build-push-action@v5
  with:
    platforms: linux/amd64,linux/arm64
    push: true
    tags: ${{ steps.meta.outputs.tags }}

# 2. Security scanning with Trivy
- name: Scan image for vulnerabilities
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
    format: 'sarif'
    output: 'trivy-results.sarif'
    severity: 'CRITICAL,HIGH'
    exit-code: '1'  # Fail pipeline on critical vulnerabilities

# 3. Semantic versioning with tags
on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  release:
    steps:
      - name: Extract version from tag
        id: version
        run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT

      - uses: docker/build-push-action@v5
        with:
          tags: |
            ghcr.io/myorg/myapp:${{ steps.version.outputs.VERSION }}
            ghcr.io/myorg/myapp:latest

# 4. Rollback on failure
- name: Deploy with rollback
  run: |
    PREVIOUS_IMAGE=$(docker inspect --format='{{.Config.Image}}' app-container)
    docker pull $NEW_IMAGE

    if docker run --rm $NEW_IMAGE node -e "require('./dist/index.js')"; then
      docker stop app-container
      docker run -d --name app-container $NEW_IMAGE
    else
      echo "New image failed healthcheck, keeping previous"
      exit 1
    fi

Questions fréquentes

Comment stocker les secrets dans GitHub Actions ?

Allez dans les paramètres du dépôt → Secrets and variables → Actions → New repository secret.

Différence entre ghcr.io et Docker Hub ?

GitHub Container Registry est gratuit pour les dépôts publics et intégré aux permissions GitHub.

Comment builder pour AMD64 et ARM64 ?

Utilisez docker/setup-qemu-action et docker/setup-buildx-action, puis définissez les plateformes dans docker/build-push-action.

Comment implémenter des déploiements spécifiques à l'environnement ?

Utilisez les environnements GitHub pour staging et production.

Outils associés

𝕏 Twitterin LinkedIn
Cet article vous a-t-il aidé ?

Restez informé

Recevez des astuces dev et les nouveaux outils chaque semaine.

Pas de spam. Désabonnez-vous à tout moment.

Essayez ces outils associés

YMLYAML Validator & Formatter{ }JSON Formatter→BBase64 Decoder

Articles connexes

Tutoriel Docker Compose : des bases aux stacks prets pour la production

Tutoriel complet Docker Compose : syntaxe docker-compose.yml, services, reseaux, volumes, variables d'environnement, healthchecks et exemples Node.js/Python/WordPress.

Strategies de branchement Git : GitFlow vs Trunk-Based vs GitHub Flow

Comparaison des strategies GitFlow, Trunk-Based Development et GitHub Flow. Structures de branches, workflows de fusion, integration CI/CD et choix de la bonne strategie.

Kubernetes pour débutants : Tutoriel complet (2026)

Apprenez Kubernetes de zéro. Pods, Services, Deployments et plus.