Aller au contenu principal

Pipelines CI/CD complets


Table des matières

  1. Architecture d'un pipeline
  2. Pipeline Node.js
  3. Pipeline Docker
  4. Pipeline avec déploiement
  5. Bonnes pratiques
  6. Exercices pratiques


1 - Architecture d'un pipeline

Étapes typiques

Stratégie de branches

BrancheActions
feature/*Lint, Test
developLint, Test, Build, Deploy Staging
mainLint, Test, Build, Deploy Production
release/*Full pipeline + Release

Exemple de structure

name: CI/CD Pipeline

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

jobs:
lint:
# Vérification code

test:
needs: lint
# Tests unitaires

build:
needs: test
# Build application

deploy-staging:
needs: build
if: github.ref == 'refs/heads/develop'
# Déploiement staging

deploy-production:
needs: build
if: github.ref == 'refs/heads/main'
# Déploiement production

🔝 Retour à la table des matières



2 - Pipeline Node.js

Pipeline complet

name: Node.js CI/CD

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

env:
NODE_VERSION: '18'

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- run: npm ci
- run: npm run lint

test:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- run: npm ci
- run: npm test -- --coverage

- uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/

build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- run: npm ci
- run: npm run build

- uses: actions/upload-artifact@v4
with:
name: build
path: dist/

deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/download-artifact@v4
with:
name: build
path: ./dist

- name: Deploy to server
env:
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
# Déploiement via rsync/scp
echo "Deploying..."

🔝 Retour à la table des matières



3 - Pipeline Docker

Build et push

name: Docker CI/CD

on:
push:
branches: [main]
tags: ['v*']

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

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v4

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

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

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha

- name: Build and push
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

deploy:
needs: build-and-push
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to server
run: |
# docker pull et restart
echo "Deploying new image..."

Multi-plateforme

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

🔝 Retour à la table des matières



4 - Pipeline avec déploiement

Déploiement multi-environnements

name: Full Pipeline

on:
push:
branches: [main, develop]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test

build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

deploy-staging:
needs: build
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.example.com
steps:
- uses: actions/download-artifact@v4
with:
name: dist
- name: Deploy to Staging
run: ./deploy.sh staging
env:
DEPLOY_TOKEN: ${{ secrets.STAGING_TOKEN }}

deploy-production:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- uses: actions/download-artifact@v4
with:
name: dist
- name: Deploy to Production
run: ./deploy.sh production
env:
DEPLOY_TOKEN: ${{ secrets.PROD_TOKEN }}

Déploiement AWS

deploy-aws:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4

- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1

- name: Deploy to S3
run: aws s3 sync ./dist s3://my-bucket --delete

- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CF_DISTRIBUTION_ID }} \
--paths "/*"

Déploiement via SSH

deploy-ssh:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts

- name: Deploy
run: |
rsync -avz --delete ./dist/ ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:/var/www/app/
ssh ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} "sudo systemctl restart myapp"

🔝 Retour à la table des matières



5 - Bonnes pratiques

Protection des branches

# Require status checks
deploy:
needs: [lint, test, build]
if: github.ref == 'refs/heads/main'

Concurrency

concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true

Notifications

notify:
needs: [deploy]
if: always()
runs-on: ubuntu-latest
steps:
- uses: slackapi/slack-github-action@v1
with:
channel-id: 'deployments'
slack-message: |
Deploy ${{ needs.deploy.result }}
Commit: ${{ github.sha }}
Author: ${{ github.actor }}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_TOKEN }}

Rollback

rollback:
if: failure() && needs.deploy.result == 'failure'
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Rollback to previous version
run: ./rollback.sh

Security scanning

security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'CRITICAL,HIGH'
exit-code: '1'

🔝 Retour à la table des matières



6 - Exercices pratiques

Exercice 1 : Pipeline basique

Créez un pipeline lint → test → build :

Solution
name: CI

on: push

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- run: npm ci
- run: npm run lint

test:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- run: npm ci
- run: npm test

build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- run: npm ci
- run: npm run build

Exercice 2 : Déploiement conditionnel

Déployez sur staging pour develop, production pour main :

Solution
name: Deploy

on:
push:
branches: [main, develop]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build

deploy-staging:
needs: build
if: github.ref == 'refs/heads/develop'
environment: staging
runs-on: ubuntu-latest
steps:
- run: echo "Deploy to staging"

deploy-prod:
needs: build
if: github.ref == 'refs/heads/main'
environment: production
runs-on: ubuntu-latest
steps:
- run: echo "Deploy to production"

🔝 Retour à la table des matières



Points clés à retenir

  • Pipeline typique : Lint → Test → Build → Deploy
  • Utiliser needs pour les dépendances entre jobs
  • if: github.ref == ... pour déploiement conditionnel
  • Environments pour staging/production
  • Artifacts pour partager entre jobs
  • concurrency pour éviter les déploiements simultanés
  • Toujours avoir un plan de rollback

🔝 Retour à la table des matières


← Chapitre précédent | Chapitre suivant : Exercices →