🐳 Infrastructure QA Moderne

Docker & Kubernetes pour une QA scalable et reproductible
🎯 Objectif : Construire une infrastructure QA robuste et tool-agnostic. Ce guide couvre les patterns pratiques pour faire tourner n'importe quel framework de test dans des environnements containerisés, de Docker Compose jusqu'aux clusters Kubernetes.

Pourquoi Docker/K8s en QA ?

🔥 Problèmes classiques sans containers

  • « Ça marche chez moi » - Développeur en Java 17, CI en Java 11, QA en Java 8
  • Environnements divergents - Versions de DB différentes, configs OS variables
  • Setup complexe - 2h pour monter un environnement de test complet
  • Pas de parallélisation - Tests qui se marchent dessus, ressources partagées
  • Debugging impossible - Logs éparpillés, environnements qui disparaissent

✅ Bénéfices avec containers

  • Reproductibilité totale - Même environnement partout
  • Isolation parfaite - Chaque test dans son bac à sable
  • Scalabilité native - 1 test ou 100 tests, même complexité
  • Environments on-demand - Créer/détruire un environnement en 30s
  • Tool-agnostic - Peu importe votre framework de test
💡 En pratique : Passer de "2h de setup + 30min de debug" à "1 commande = environnement prêt"

Architecture de Base

🏗️ Stack Type

Voici l'architecture classique qu'on va utiliser :

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   TEST RUNNER   │───▶│   YOUR APP      │───▶│    DATABASE     │
│  (ton framework)│    │ (SUT - System   │    │   + REDIS       │
│                 │    │  Under Test)    │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘
         │                                               │
         ▼                                               │
┌─────────────────┐                               ┌─────▼───────────┐
│    ARTIFACTS    │                               │   MONITORING    │
│  (rapports,     │◀──────────────────────────────│  (logs, metrics)│
│   screenshots)  │                               │                 │
└─────────────────┘                               └─────────────────┘

📂 Structure de Projet

qa-infrastructure/
├── docker-compose.yml          # Orchestration locale
├── Dockerfile                  # Image de test
├── environments/
│   ├── local.yml              # Config dev local
│   ├── ci.yml                 # Config CI/CD
│   └── staging.yml            # Config staging
├── tests/
│   ├── smoke/                 # Tests smoke
│   ├── integration/           # Tests d'intégration
│   └── e2e/                   # Tests end-to-end
├── scripts/
│   ├── run-tests.sh           # Script d'exécution
│   └── collect-results.sh     # Collecte des résultats
├── k8s/
│   ├── namespace.yaml
│   ├── deployments/
│   └── jobs/
└── reports/                   # Sortie des résultats
    ├── junit/
    ├── coverage/
    └── screenshots/

🐳 Docker Compose Simple

version: '3.8'

services:
  # Votre application sous test
  app:
    image: ${SUT_IMAGE}:${VERSION}
    environment:
      - DATABASE_URL=postgresql://qa:qa@db:5432/qa_db
      - REDIS_URL=redis://redis:6379
      - NODE_ENV=test
    depends_on:
      - db
      - redis
    ports:
      - "8080:8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      retries: 5

  # Base de données
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: qa_db
      POSTGRES_USER: qa
      POSTGRES_PASSWORD: qa
    volumes:
      - ./fixtures/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U qa"]
      interval: 5s

  # Cache Redis
  redis:
    image: redis:7-alpine

  # Vos tests
  test-runner:
    build: .
    environment:
      - TARGET_URL=http://app:8080
      - TEST_SUITE=${TEST_SUITE:-smoke}
      - OUTPUT_DIR=/output
    volumes:
      - ./reports:/output
    depends_on:
      app:
        condition: service_healthy

  # Stockage des résultats
  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: qa-user
      MINIO_ROOT_PASSWORD: qa-password
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - minio-data:/data

volumes:
  minio-data:
🚀 Usage :
docker-compose up -d - Démarre tout
docker-compose run --rm test-runner - Lance les tests
docker-compose down - Nettoie tout

Dockerfile pour Tests

📦 Multi-stage Build

# Étape 1: Base avec outils communs
FROM alpine:3.18 AS base
RUN apk add --no-cache \
    curl \
    jq \
    bash \
    ca-certificates

# Étape 2: Runtime spécifique (exemple Node.js)
FROM node:18-alpine AS nodejs-runtime
RUN apk add --no-cache chromium
ENV CHROME_BIN=/usr/bin/chromium-browser

# Étape 3: Outils de test
FROM nodejs-runtime AS test-tools
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# Étape 4: Tests
FROM test-tools AS test-runner
COPY tests/ /tests/
COPY scripts/ /scripts/

# Variables d'environnement
ENV TARGET_URL=""
ENV TEST_SUITE="smoke"
ENV OUTPUT_DIR="/output"
ENV HEADLESS="true"

# Point d'entrée flexible
COPY entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["entrypoint.sh"]

🎯 Script d'Entrypoint Générique

#!/bin/bash
# entrypoint.sh - Point d'entrée flexible

set -euo pipefail

echo "🚀 Starting test execution"
echo "Target: ${TARGET_URL}"
echo "Suite: ${TEST_SUITE}"
echo "Output: ${OUTPUT_DIR}"

# Attendre que l'app soit prête
echo "⏳ Waiting for application..."
timeout 300 bash -c 'until curl -sf $TARGET_URL/health; do sleep 2; done'

# Créer les répertoires de sortie
mkdir -p "$OUTPUT_DIR"/{reports,screenshots,videos}

# Exécuter selon le type de suite
case "$TEST_SUITE" in
    "smoke")
        echo "🟢 Running smoke tests"
        npm run test:smoke
        ;;
    "integration")
        echo "🔗 Running integration tests"
        npm run test:integration
        ;;
    "e2e")
        echo "🎭 Running E2E tests"
        npm run test:e2e
        ;;
    *)
        echo "🧪 Running custom suite: $TEST_SUITE"
        npm run "test:$TEST_SUITE"
        ;;
esac

echo "✅ Tests completed"
🔄 Tool-Agnostic : Remplacer npm par pytest, mvn test, go test, etc. Le pattern reste le même !

Gestion des Environnements

🌍 Pattern Multi-Environnements

Une base commune + des overrides par environnement :

# docker-compose.override.yml pour CI
version: '3.8'

services:
  app:
    mem_limit: 512m
    restart: "no"

  test-runner:
    environment:
      - CI=true
      - BUILD_NUMBER=${CI_BUILD_NUMBER}
      - PARALLEL_JOBS=4
    mem_limit: 1g

  db:
    tmpfs:
      - /var/lib/postgresql/data  # DB en RAM pour CI
# .env.staging
SUT_IMAGE=myapp
VERSION=staging-latest
TARGET_URL=https://staging.myapp.com
TEST_SUITE=smoke,integration
DATABASE_URL=postgresql://staging_user:pass@staging-db:5432/myapp

🚀 Script de Déploiement

#!/bin/bash
# deploy-env.sh
ENV=${1:-"local"}

case "$ENV" in
    "local")
        export COMPOSE_FILE="docker-compose.yml"
        ;;
    "ci")
        export COMPOSE_FILE="docker-compose.yml:ci.yml"
        ;;
    "staging")
        export COMPOSE_FILE="docker-compose.yml:staging.yml"
        ;;
esac

echo "🌍 Deploying to: $ENV"

# Démarrer l'environnement
docker-compose --env-file=".env.$ENV" up -d

# Lancer les tests
docker-compose run --rm test-runner

# Nettoyer
docker-compose down --volumes

Pipeline CI/CD

⚙️ GitHub Actions Simple

name: QA Pipeline

on: [push, pull_request]

jobs:
  qa-tests:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        suite: [smoke, integration, e2e]
        
    steps:
      - uses: actions/checkout@v4
      
      - name: Build test image
        run: docker build -t qa-runner:${{ github.sha }} .
      
      - name: Start environment
        run: |
          export SUT_IMAGE=myapp:${{ github.sha }}
          docker-compose up -d app db redis
      
      - name: Wait for app
        run: timeout 60 bash -c 'until curl -sf http://localhost:8080/health; do sleep 2; done'
      
      - name: Run ${{ matrix.suite }} tests
        run: |
          docker-compose run --rm \
            -e TEST_SUITE=${{ matrix.suite }} \
            test-runner
      
      - name: Upload results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results-${{ matrix.suite }}
          path: reports/
      
      - name: Cleanup
        if: always()
        run: docker-compose down --volumes

🦊 GitLab CI Équivalent

stages:
  - test

variables:
  DOCKER_DRIVER: overlay2

.test-template: &test-template
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - docker build -t qa-runner:$CI_COMMIT_SHA .
    - docker-compose up -d app db redis
    - timeout 60 bash -c 'until curl -sf http://app:8080/health; do sleep 2; done'
  after_script:
    - docker-compose down --volumes
  artifacts:
    reports:
      junit: reports/*.xml
    paths:
      - reports/
    when: always

smoke-tests:
  <<: *test-template
  stage: test
  script:
    - docker-compose run --rm -e TEST_SUITE=smoke test-runner

integration-tests:
  <<: *test-template
  stage: test
  script:
    - docker-compose run --rm -e TEST_SUITE=integration test-runner

e2e-tests:
  <<: *test-template
  stage: test
  script:
    - docker-compose run --rm -e TEST_SUITE=e2e test-runner

Kubernetes pour Scale

☸️ Pourquoi K8s ?

  • Auto-scaling - Plus de tests = plus de pods automatiquement
  • Resource management - Limites CPU/RAM par test
  • Job scheduling - Tests périodiques, retry logic
  • Service discovery - Les services se trouvent automatiquement
  • Rolling updates - Déploiements sans interruption

📋 Job Kubernetes Simple

apiVersion: batch/v1
kind: Job
metadata:
  name: qa-smoke-tests
  namespace: qa-testing
spec:
  parallelism: 3          # 3 pods en parallèle
  completions: 3          # 3 tâches à compléter
  backoffLimit: 2         # 2 tentatives max
  
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: test-runner
        image: qa-runner:latest
        env:
        - name: TARGET_URL
          value: "http://app-service:8080"
        - name: TEST_SUITE
          value: "smoke"
        - name: WORKER_ID
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        resources:
          requests:
            memory: "256Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "200m"
        volumeMounts:
        - name: results
          mountPath: /output
      
      volumes:
      - name: results
        persistentVolumeClaim:
          claimName: test-results-pvc

🔄 CronJob pour Tests Réguliers

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-regression
  namespace: qa-testing
spec:
  schedule: "0 2 * * *"    # Tous les jours à 2h
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: regression-tests
            image: qa-runner:nightly
            env:
            - name: TEST_SUITE
              value: "regression"
            - name: SLACK_WEBHOOK
              valueFrom:
                secretKeyRef:
                  name: qa-secrets
                  key: slack-webhook
            resources:
              requests:
                memory: "1Gi"
                cpu: "500m"

🚀 Déploiement avec Helm

# helm install qa-infra ./qa-chart
# values.yaml
app:
  image: myapp:latest
  replicas: 2

testRunner:
  image: qa-runner:latest
  
jobs:
  smoke:
    enabled: true
    schedule: "*/30 * * * *"
  nightly:
    enabled: true
    schedule: "0 2 * * *"
    
resources:
  requests:
    memory: 256Mi
    cpu: 100m
  limits:
    memory: 512Mi
    cpu: 200m

Monitoring & Observabilité

📊 Métriques Essentielles

  • Taux de succès des tests - % de tests qui passent
  • Durée d'exécution - Trend des temps de test
  • Utilisation des ressources - CPU/RAM par pod
  • Queue des jobs - Combien de tests en attente
  • Errors patterns - Types d'erreurs les plus fréquents

🔍 Stack Observabilité Rapide

# docker-compose.monitoring.yml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
      
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=qa-password
    volumes:
      - ./monitoring/dashboards:/var/lib/grafana/dashboards

  # Collecte des logs
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
      
  # Envoi des logs vers Loki
  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/log:/var/log:ro
      - ./monitoring/promtail.yml:/etc/promtail/promtail.yml

📈 Métriques Custom

// Dans votre test runner
const client = require('prom-client');

const testCounter = new client.Counter({
  name: 'qa_tests_total',
  help: 'Total number of tests executed',
  labelNames: ['suite', 'status', 'environment']
});

const testDuration = new client.Histogram({
  name: 'qa_test_duration_seconds', 
  help: 'Test execution time',
  labelNames: ['suite', 'test_name']
});

// À la fin de chaque test
testCounter.inc({ suite: 'smoke', status: 'passed', environment: 'ci' });
testDuration.observe({ suite: 'smoke', test_name: 'login' }, 2.5);
📊 Dashboard Grafana : Importer le dashboard ID 12345 qui contient tous les panneaux QA essentiels

Sécurité & Best Practices

🔒 Sécurité de Base

# Dockerfile sécurisé
FROM node:18-alpine

# Créer un utilisateur non-root
RUN addgroup -g 1001 -S qauser && \
    adduser -S qauser -u 1001 -G qauser

# Installer les dépendances en tant que root
COPY package*.json ./
RUN npm ci --only=production && \
    npm cache clean --force

# Changer vers utilisateur non-root
USER qauser

# Copier le code
COPY --chown=qauser:qauser . .

# Pas d'exposition de ports inutiles
# EXPOSE 8080

# Healthcheck
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

🛡️ Pod Security en K8s

apiVersion: v1
kind: Pod
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1001
    fsGroup: 1001
    
  containers:
  - name: test-runner
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL
    
    # Volumes temporaires pour écriture
    volumeMounts:
    - name: tmp
      mountPath: /tmp
    - name: cache
      mountPath: /.cache
      
  volumes:
  - name: tmp
    emptyDir: {}
  - name: cache
    emptyDir: {}

🔐 Gestion des Secrets

# Ne JAMAIS faire ça
ENV API_KEY=abc123  # ❌

# Faire ça à la place
apiVersion: v1
kind: Secret
metadata:
  name: qa-secrets
type: Opaque
data:
  api-key: YWJjMTIz  # base64 encoded
  db-password: c2VjcmV0

---
# Dans le pod
env:
- name: API_KEY
  valueFrom:
    secretKeyRef:
      name: qa-secrets
      key: api-key

Debugging & Troubleshooting

🔍 Commands de Debug Rapides

# Docker Compose
docker-compose logs test-runner          # Logs du test runner
docker-compose exec test-runner bash     # Shell dans le container
docker-compose ps                        # Status des services
docker-compose top                       # Processus en cours

# Kubernetes  
kubectl logs -f pod/test-runner-abc123   # Logs en temps réel
kubectl exec -it test-runner-abc123 bash # Shell dans le pod
kubectl describe pod test-runner-abc123  # Détails du pod
kubectl get events --sort-by=.metadata.creationTimestamp

❌ Problèmes Courants

Test qui timeout :
1. Vérifier que l'app répond : curl http://app:8080/health
2. Vérifier les logs : docker-compose logs app
3. Vérifier les ressources : docker stats
Out of Memory :
1. Augmenter les limites : mem_limit: 2g
2. Profiler l'app : docker exec app top
3. Nettoyer les caches entre tests
Tests flaky :
1. Ajouter des waits explicites
2. Vérifier les race conditions
3. Isoler les données de test

🚀 Script de Health Check

#!/bin/bash
# health-check.sh

echo "🏥 QA Infrastructure Health Check"

# Check Docker
docker version >/dev/null || { echo "❌ Docker not running"; exit 1; }

# Check Compose services
echo "📋 Checking services..."
docker-compose ps

# Check app health
if curl -sf http://localhost:8080/health >/dev/null; then
    echo "✅ App is healthy"
else
    echo "❌ App is not responding"
fi

# Check database
if docker-compose exec -T db pg_isready -U qa >/dev/null; then
    echo "✅ Database is ready"
else
    echo "❌ Database is not ready"
fi

echo "🎉 Health check complete"

Récap & Prochaines Étapes

✅ Ce qu'on a couvert

  • Architecture - Stack complète avec Docker Compose
  • Flexibilité - Tool-agnostic, multi-environnements
  • CI/CD - Intégration GitHub Actions / GitLab
  • Kubernetes - Scale avec Jobs et CronJobs
  • Monitoring - Observabilité avec Prometheus/Grafana
  • Sécurité - Best practices containers
  • Debug - Outils pour résoudre les problèmes

🚀 Pour aller plus loin

  • GitOps - ArgoCD pour déployer vos environnements QA
  • Service Mesh - Istio pour traffic management entre services
  • Chaos Engineering - Tester la robustesse avec Chaos Monkey
  • Test Data Management - Automatiser la création de jeux de données
  • Performance Testing - k6 ou JMeter dans Kubernetes

📚 Ressources Utiles

🎯 Action Items :
1. Commencer par Docker Compose en local
2. Intégrer dans votre pipeline CI
3. Migrer vers K8s quand vous avez >10 tests parallèles
4. Ajouter monitoring quand l'équipe grandit
💡 Remember : L'infrastructure QA n'est pas un but en soi, c'est un moyen. Commencez simple, itérez, et ajoutez de la complexité seulement quand c'est justifié par la valeur métier.

Cheat Sheet Commands

🐳 Docker Compose

# Développement
docker-compose up -d                    # Démarrer les services
docker-compose run --rm test-runner     # Lancer les tests
docker-compose logs -f app              # Voir les logs en temps réel
docker-compose exec app bash            # Shell dans le container
docker-compose down --volumes           # Tout nettoyer

# Debug
docker-compose ps                       # Status des services  
docker-compose top                      # Processus actifs
docker-compose config                   # Valider la config
docker system prune -f                  # Nettoyer Docker

☸️ Kubernetes

# Jobs
kubectl create job smoke-test --image=qa-runner:latest
kubectl get jobs -w                     # Suivre les jobs
kubectl logs job/smoke-test             # Logs du job
kubectl delete job smoke-test           # Supprimer le job

# Pods  
kubectl get pods -o wide               # Lister les pods
kubectl describe pod test-runner-123   # Détails du pod
kubectl logs -f test-runner-123        # Logs en temps réel
kubectl exec -it test-runner-123 bash  # Shell dans le pod

# Debugging
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl top pods                       # Utilisation CPU/RAM
kubectl describe node                  # Infos des nœuds

📊 Monitoring

# Prometheus queries utiles
rate(qa_tests_total[5m])               # Taux de tests par seconde
qa_tests_failed_total / qa_tests_total  # Taux d'échec
histogram_quantile(0.95, qa_test_duration_seconds)  # 95e percentile des durées

# Grafana
- Dashboard ID: 12345 (QA Overview)
- Alert sur taux d'échec > 10%
- Panel durée moyenne des tests

🔧 Troubleshooting

# Tests qui ne passent pas
curl http://localhost:8080/health      # L'app répond ?
docker-compose logs db                 # Problème DB ?
docker stats                          # Ressources suffisantes ?

# Performance
docker-compose exec app htop           # Utilisation CPU/RAM  
docker-compose exec db pgbench -i qa_db  # Test perf DB
curl -w "@curl-format.txt" http://app/api  # Temps de réponse API

# Nettoyage
docker system prune -a --volumes       # Nettoyage complet
kubectl delete --all jobs              # Supprimer tous les jobs
kubectl delete pvc --all               # Supprimer volumes (ATTENTION!)

🧰 Boîte à outils QA – Docker & Kubernetes

Cette section rassemble les commandes essentielles sous forme de cheat sheet, pour vous aider à lancer, déboguer et monitorer vos environnements de test.

🐳 Docker Compose


# Développement
docker-compose up -d                    # Démarrer les services
docker-compose run --rm test-runner     # Lancer les tests
docker-compose logs -f app              # Voir les logs en temps réel
docker-compose exec app bash            # Shell dans le container
docker-compose down --volumes           # Tout nettoyer

# Debug
docker-compose ps                       # Status des services  
docker-compose top                      # Processus actifs
docker-compose config                   # Valider la config
docker system prune -f                  # Nettoyer Docker
      

☸️ Kubernetes


# Jobs
kubectl create job smoke-test --image=qa-runner:latest
kubectl get jobs -w                     # Suivre les jobs
kubectl logs job/smoke-test             # Logs du job
kubectl delete job smoke-test           # Supprimer le job

# Pods  
kubectl get pods -o wide                # Lister les pods
kubectl describe pod test-runner-123    # Détails du pod
kubectl logs -f test-runner-123         # Logs en temps réel
kubectl exec -it test-runner-123 bash   # Shell dans le pod

# Debugging
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl top pods                        # Utilisation CPU/RAM
kubectl describe node                   # Infos des nœuds
      

📊 Monitoring


# Prometheus queries utiles
rate(qa_tests_total[5m])               # Taux de tests par seconde
qa_tests_failed_total / qa_tests_total  # Taux d'échec
histogram_quantile(0.95, qa_test_duration_seconds)  # 95e percentile des durées

# Grafana
- Dashboard ID: 12345 (QA Overview)
- Alert sur taux d'échec > 10%
- Panel durée moyenne des tests
      

🔧 Troubleshooting


# Tests qui ne passent pas
curl http://localhost:8080/health      # L'app répond ?
docker-compose logs db                 # Problème DB ?
docker stats                           # Ressources suffisantes ?

# Performance
docker-compose exec app htop           # Utilisation CPU/RAM  
docker-compose exec db pgbench -i qa_db  # Test perf DB
curl -w "@curl-format.txt" http://app/api  # Temps de réponse API

# Nettoyage
docker system prune -a --volumes       # Nettoyage complet
kubectl delete --all jobs              # Supprimer tous les jobs
kubectl delete pvc --all               # Supprimer volumes (ATTENTION!)
      

📝 Exercice rapide

Cet exercice a pour objectif de mettre en pratique les concepts vus dans la formation. Il est volontairement détaillé afin de vous guider étape par étape dans la réflexion et la mise en œuvre.
👉 Aucune correction n’est fournie ici : l’objectif est que vous testiez, exploriez et déboguiez par vous-même.

🎯 Contexte

Vous faites partie d’une équipe QA qui doit tester une application de gestion d’articles (API REST). L’application expose des endpoints HTTP et dépend d’une base PostgreSQL. Votre mission est de mettre en place un environnement de test containerisé et d’y exécuter une première suite de tests automatisés.

📂 Étapes attendues

  1. Dockerfile : Écrire un Dockerfile pour construire l’image de test runner. L’image doit contenir Node.js (ou le langage de votre choix) et les dépendances nécessaires pour exécuter une suite de tests.
  2. docker-compose.yml : Créer un fichier Compose avec :
    • un service app basé sur une image simple (ex: Node ou Python API),
    • un service db basé sur postgres:15-alpine,
    • un service test-runner qui dépend de app et exécute automatiquement une commande de test.
  3. Fixtures DB : Ajouter un script SQL d’initialisation pour précharger la base avec 2 ou 3 articles factices. Monter ce script dans le container db.
  4. Healthcheck : Mettre en place un healthcheck pour l’application (/health) afin que le test-runner n’attende pas indéfiniment.
  5. Exécution : Lancer l’environnement en local, exécuter les tests, et collecter les rapports dans un volume partagé (./reports).
  6. Kubernetes : Convertir ensuite le même environnement en un Job Kubernetes (1 pod applicatif, 1 pod DB, 1 pod test-runner). Fournir les YAML nécessaires.
  7. Bonus : Ajouter un CronJob pour exécuter les tests chaque nuit à 2h du matin.

📦 Livrables attendus

  • Un Dockerfile fonctionnel
  • Un docker-compose.yml capable de démarrer l’environnement complet
  • Un script SQL d’initialisation (init.sql)
  • Des manifestes Kubernetes (job.yaml, cronjob.yaml)
  • Un répertoire reports/ contenant au moins un rapport de test
⏱️ Durée conseillée : 45 à 60 minutes.
🛠️ Astuce : utilisez la section « Boîte à outils » comme aide-mémoire pour les commandes essentielles.

💡 Cartes de conseils – Docker, Kubernetes & QA

Voici 50 conseils pratiques regroupés par thèmes. Chaque carte est indépendante et sert de rappel rapide au quotidien.

🐳 Docker – Fondations

📦 Images légères

Utilisez alpine ou slim pour réduire la taille et accélérer vos builds.

📑 Cache Docker

Placez vos fichiers de dépendances avant COPY pour tirer parti du cache Docker.

🛠️ Volumes

Montez vos répertoires en volumes pour tester en live sans rebuild complet.

📑 Logs

Avec docker logs -f, suivez vos services en temps réel.

🔍 Exec

Ouvrez un shell dans vos conteneurs avec docker exec -it pour déboguer.

🐳 Docker – Avancé

📂 Multi-stage builds

Construisez vos tests en plusieurs étapes pour réduire vos images finales.

⚡ Entrypoint flexible

Un script entrypoint.sh générique rend vos images réutilisables.

🌍 Variables d’environnement

Centralisez vos configs dans des fichiers .env pour plus de clarté.

📦 Artifacts

Partagez vos reports/ via volumes pour collecter facilement les résultats.

👤 Non-root

Exécutez vos conteneurs avec un utilisateur non-root pour plus de sécurité.

☸️ Kubernetes – Fondations

📋 Jobs

Exécutez vos tests ponctuels avec des Jobs K8s.

⏱️ CronJobs

Automatisez vos régressions nocturnes avec des CronJobs.

📊 Probes

Stabilisez vos pods grâce aux readiness et livenessProbes.

☁️ Namespaces

Isolez vos environnements de test dans un namespace dédié.

🔐 ConfigMaps

Stockez vos paramètres applicatifs dans des ConfigMaps au lieu de hardcoder.

☸️ Kubernetes – Avancé

🛡️ RBAC

Attribuez le strict minimum de permissions à vos runners.

📈 Autoscaling

Adaptez la capacité de vos tests avec un HorizontalPodAutoscaler.

📦 Sidecars

Ajoutez des sidecars (ex: Fluentbit) pour collecter les logs.

🔄 Rolling Updates

Déployez vos applis tout en continuant vos tests.

📂 PVC

Conservez vos rapports via des volumes persistants.

📊 Monitoring & Observabilité

📈 Prometheus

Exposez vos tests comme métriques pour mesurer le succès et la durée.

📊 Grafana

Créez des dashboards dédiés à vos suites QA.

📜 Logs centralisés

Regroupez vos logs avec Loki ou Elastic pour accélérer le debug.

🔔 Alerting

Mettez des alertes (taux d’échec >10%) pour réagir rapidement.

🔎 Tracing

Ajoutez du tracing (ex: Jaeger) pour comprendre les chemins de vos tests.

🔐 Sécurité & Bonnes pratiques

🧑‍💻 Utilisateur non-root

Évitez root dans vos Dockerfiles → attaquable.

🔑 Secrets

Stockez vos clés sensibles dans des Secrets K8s.

🛡️ Scans

Analysez vos images avec trivy ou clair pour détecter des failles.

📜 Policies

Appliquez des PodSecurityPolicies pour limiter les privilèges.

🔒 HTTPS partout

Même pour vos environnements QA, activez TLS.

⚙️ CI/CD & Automatisation

🤖 GitHub Actions

Automatisez build/test avec des workflows YAML.

🦊 GitLab CI

Réutilisez des templates de jobs pour vos suites QA.

📦 Artifacts CI

Conservez vos rapports dans des artefacts CI/CD.

🔄 Pipelines parallèles

Lancez smoke, integration, e2e en parallèle.

🚀 CD incrémental

Ne déployez en staging que si vos tests passent en CI.

🧪 QA & Testing concret

📂 Données de test

Versionnez vos jeux de données comme du code.

⏱️ Flakiness

Traitez la flaky test comme un bug prioritaire.

🖥️ Parallélisation

Découpez vos tests en jobs indépendants pour accélérer.

📸 Evidence

Capturez logs, screenshots, vidéos pour chaque run.

🔁 Repeatability

Un test doit donner le même résultat localement et en CI.

🚨 Debug & Troubleshooting

🪵 Logs rapides

docker-compose logs -f → premier réflexe en cas d’échec.

🔍 Inspect

Avec docker inspect ou kubectl describe, récupérez l’état complet.

📊 Ressources

docker stats / kubectl top pods pour vérifier CPU/RAM.

🚑 Healthcheck

Un test qui timeout ? Vérifiez d’abord l’endpoint /health.

🔄 Restart policy

Configurez des politiques de redémarrage pour éviter les faux négatifs.

📚 Culture & Mindset

🚀 Commencez simple

Démarrez par Docker Compose avant K8s complet.

🔄 Itérations

Ajoutez la complexité progressivement → valeur métier d’abord.

🧭 GitOps

Considérez Git comme source unique de vérité pour vos envs.

⚡ Chaos Testing

Injectez des pannes volontaires pour tester la résilience.

📈 ROI QA

Mesurez vos gains (temps, stabilité) pour justifier vos investissements QA.