CI/CD — Intégration et Déploiement Continus

Status: Basic Tags: CD DevOps Automation Docker Created: 2026-08-09 Related: Git, Docker, Ubuntu

Introduction

CI/CD (Continuous Integration/Continuous Deployment) automates the process of building, testing, and deploying software. It ensures code changes are integrated and deployed reliably.


Core Concepts

Continuous Integration (CI)

  • Definition: Automatically build and test code changes
  • Frequency: Every commit triggers a build
  • Goal: Detect issues early

Continuous Deployment (CD)

  • Definition: Automatically deploy tested code to production
  • Frequency: Every successful build deploys
  • Goal: Rapid, reliable releases

Key Components

  1. Source Control: Git repository
  2. Build Server: Executes builds and tests
  3. Artifacts: Built software packages
  4. Deployment Targets: Staging, production environments

GitHub Actions

Basic Workflow

name: CI/CD Pipeline
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
 
jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.12'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    
    - name: Run tests
      run: |
        python -m pytest tests/ -v
    
    - name: Build Docker image
      run: |
        docker build -t myapp:${{ github.sha }} .
        docker tag myapp:${{ github.sha }} myregistry/myapp:latest
    
    - name: Deploy to production
      if: github.ref == 'refs/heads/main'
      run: |
        ssh deploy@server "docker pull myregistry/myapp:latest"
        ssh deploy@server "docker-compose up -d"

Advanced Features

name: Multi-Stage Pipeline
on:
  push:
    branches: [main, develop]
 
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Run linter
      run: |
        pip install flake8
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
 
  test:
    needs: lint
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_DB: testdb
          POSTGRES_USER: testuser
          POSTGRES_PASSWORD: testpass
    steps:
    - uses: actions/checkout@v3
    - name: Run tests with coverage
      run: |
        pip install -r requirements.txt
        pytest tests/ --cov=app --cov-report=xml
    
    - name: Upload coverage
      uses: codecov/codecov-action@v3
 
  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
    - uses: actions/checkout@v3
    - name: Deploy to production
      run: |
        ssh deploy@server "cd /opt/myapp && ./deploy.sh"

GitLab CI/CD

Basic Configuration

# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy
 
build:
  stage: build
  script:
    - docker build -t myapp:$CI_COMMIT_SHA .
    - docker tag myapp:$CI_COMMIT_SHA myregistry/myapp:latest
    - docker push myregistry/myapp:latest
 
test:
  stage: test
  script:
    - docker run myapp:$CI_COMMIT_SHA python -m pytest tests/
 
deploy:
  stage: deploy
  script:
    - ssh deploy@server "docker pull myregistry/myapp:latest"
    - ssh deploy@server "docker-compose up -d"
  only:
    - main

Variables and Secrets

variables:
  DOCKER_REGISTRY: myregistry.com
  DOCKER_IMAGE: myapp
 
deploy:
  stage: deploy
  script:
    - docker login $DOCKER_REGISTRY -u $DOCKER_USER -p $DOCKER_PASSWORD
    - docker push $DOCKER_REGISTRY/$DOCKER_IMAGE:$CI_COMMIT_SHA
  environment:
    name: production

Jenkins

Pipeline Configuration

// Jenkinsfile
pipeline {
    agent any
    
    stages {
        stage('Build') {
            steps {
                sh 'docker build -t myapp:${BUILD_NUMBER} .'
            }
        }
        
        stage('Test') {
            steps {
                sh 'docker run myapp:${BUILD_NUMBER} python -m pytest tests/'
            }
        }
        
        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh 'ssh deploy@server "docker pull myregistry/myapp:${BUILD_NUMBER}"'
                sh 'ssh deploy@server "docker-compose up -d"'
            }
        }
    }
}

Travis CI

Configuration

# .travis.yml
language: python
python:
  - "3.12"
 
services:
  - docker
 
install:
  - pip install -r requirements.txt
  - pip install pytest
 
script:
  - pytest tests/
 
deploy:
  provider: heroku
  api_key:
    secure: encrypted_api_key
  app: myapp
  on:
    branch: main

Docker CI/CD

Build and Test

name: Docker CI
on:
  push:
    branches: [main]
 
jobs:
  build-and-test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Build Docker image
      run: docker build -t myapp:${{ github.sha }} .
    
    - name: Run tests
      run: docker run myapp:${{ github.sha }} python -m pytest tests/
    
    - name: Scan for vulnerabilities
      run: |
        docker scan myapp:${{ github.sha }}
    
    - name: Push to registry
      run: |
        echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
        docker push myapp:${{ github.sha }}

Kubernetes Deployment

Deployment Manifest

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myregistry/myapp:latest
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "128Mi"
            cpu: "250m"
          limits:
            memory: "256Mi"
            cpu: "500m"
 
---
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer

Monitoring and Alerts

Health Checks

# Docker health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1
 
# Kubernetes health check
livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 3
  periodSeconds: 10

Logging

# Docker logging
logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"
 
# Kubernetes logging
logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

Best Practices

Security

  • Use official images: Verified and maintained
  • Scan images: Use docker scan or trivy
  • Limit privileges: Run as non-root user
  • Use secrets: Never hardcode sensitive data
  • Keep updated: Regularly update base images

Reliability

  • Automate everything: No manual steps
  • Test thoroughly: Unit tests, integration tests, E2E tests
  • Monitor closely: Track performance and errors
  • Roll back easily: Quick recovery from failures

Efficiency

  • Cache dependencies: Speed up builds
  • Parallelize tasks: Run tests and builds in parallel
  • Use multi-stage builds: Reduce image size
  • Optimize pipelines: Minimize execution time

Resources

Documentation

Tools