Pipelines CI/CD complets
Table des matières
- Architecture d'un pipeline
- Pipeline Node.js
- Pipeline Docker
- Pipeline avec déploiement
- Bonnes pratiques
- Exercices pratiques
1 - Architecture d'un pipeline
Étapes typiques
Stratégie de branches
| Branche | Actions |
|---|---|
feature/* | Lint, Test |
develop | Lint, Test, Build, Deploy Staging |
main | Lint, 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
needspour les dépendances entre jobs if: github.ref == ...pour déploiement conditionnel- Environments pour staging/production
- Artifacts pour partager entre jobs
concurrencypour éviter les déploiements simultanés- Toujours avoir un plan de rollback