DEV Community

Ulrich (Houngbe)
Ulrich (Houngbe)

Posted on

Docker pour les devs backend

Docker pour les Développeurs Backend : Guide Pratique

Docker révolutionne le développement backend en résolvant le fameux "ça marche sur ma machine". Ce guide vous accompagne dans la maîtrise de Docker pour vos applications backend.

Pourquoi Docker pour le Backend ?

Problèmes Résolus

  • Environnements cohérents entre développement, test et production
  • Isolation des dépendances et des versions
  • Déploiements reproductibles et scalables
  • Gestion simplifiée des services (bases de données, cache, etc.)

Concepts Fondamentaux

1. Images vs Conteneurs

# Une image est un template immutable
docker build -t myapp:v1.0 .

# Un conteneur est une instance en cours d'exécution
docker run -d --name myapp-instance myapp:v1.0

# Lister les images et conteneurs
docker images
docker ps -a
Enter fullscreen mode Exit fullscreen mode

2. Architecture Docker

Application
    ↓
Docker Daemon
    ↓
Host OS Kernel
Enter fullscreen mode Exit fullscreen mode

Dockerfile pour Applications Backend

1. Application Node.js/Express

# Dockerfile
FROM node:18-alpine AS base

# Installer des dépendances système si nécessaire
RUN apk add --no-cache python3 make g++

WORKDIR /app

# Optimisation du cache Docker
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# Multi-stage build pour optimiser la taille
FROM node:18-alpine AS development
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

# Image de production
FROM base AS production
COPY . .
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs
EXPOSE 3000
CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

2. Application Python/FastAPI

# Dockerfile
FROM python:3.11-slim AS base

# Variables d'environnement
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

# Installer les dépendances système
RUN apt-get update && apt-get install -y \
    build-essential \
    curl \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Installer Poetry pour la gestion des dépendances
RUN pip install poetry
COPY pyproject.toml poetry.lock ./
RUN poetry config virtualenvs.create false \
    && poetry install --no-dev --no-interaction --no-ansi

# Image de développement
FROM base AS development
RUN poetry install --no-interaction --no-ansi
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

# Image de production
FROM base AS production
COPY . .
RUN adduser --disabled-password --gecos '' appuser
USER appuser
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Enter fullscreen mode Exit fullscreen mode

3. Application Java/Spring Boot

# Dockerfile
FROM openjdk:17-jdk-slim AS build

WORKDIR /app
COPY gradlew .
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .

# Cache des dépendances
RUN ./gradlew dependencies --no-daemon

COPY src src
RUN ./gradlew bootJar --no-daemon

# Image de production
FROM openjdk:17-jre-slim AS production

RUN addgroup --system spring && adduser --system spring --ingroup spring
USER spring:spring

COPY --from=build /app/build/libs/*.jar app.jar

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
Enter fullscreen mode Exit fullscreen mode

Docker Compose pour le Stack Complet

1. Stack Node.js avec PostgreSQL et Redis

# docker-compose.yml
version: '3.8'

services:
  app:
    build:
      context: .
      target: development
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DB_HOST=postgres
      - DB_PORT=5432
      - DB_NAME=myapp
      - DB_USER=postgres
      - DB_PASSWORD=password
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - app-network

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    networks:
      - app-network

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app
    networks:
      - app-network

volumes:
  postgres_data:
  redis_data:

networks:
  app-network:
    driver: bridge
Enter fullscreen mode Exit fullscreen mode

2. Configuration Nginx

# nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream app_servers {
        server app:3000;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://app_servers;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }

        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Optimisation et Bonnes Pratiques

1. Multi-stage Build Optimisé

# Dockerfile optimisé
FROM node:18-alpine AS dependencies
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS runtime
RUN addgroup -g 1001 -S nodejs \
    && adduser -S nodejs -u 1001

WORKDIR /app
USER nodejs

# Copier seulement ce qui est nécessaire
COPY --from=dependencies --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=build --chown=nodejs:nodejs /app/dist ./dist
COPY --from=build --chown=nodejs:nodejs /app/package.json ./package.json

EXPOSE 3000
CMD ["node", "dist/index.js"]
Enter fullscreen mode Exit fullscreen mode

2. .dockerignore Efficace

# .dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
README.md
.env
.nyc_output
coverage
.nyc_output
.coverage
.pytest_cache
__pycache__
.vscode
.idea
*.md
tests/
docs/
.github/
Enter fullscreen mode Exit fullscreen mode

3. Health Checks

# Dockerfile avec health check
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

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

CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode
// Health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({
    status: 'healthy',
    timestamp: new Date().toISOString(),
    uptime: process.uptime()
  });
});
Enter fullscreen mode Exit fullscreen mode

Patterns Avancés

1. Configuration par Variables d'Environnement

# docker-compose.override.yml (développement)
version: '3.8'

services:
  app:
    environment:
      - NODE_ENV=development
      - LOG_LEVEL=debug
      - DB_HOST=localhost
    volumes:
      - .:/app
      - /app/node_modules

# docker-compose.prod.yml (production)
version: '3.8'

services:
  app:
    environment:
      - NODE_ENV=production
      - LOG_LEVEL=info
    deploy:
      replicas: 3
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M
Enter fullscreen mode Exit fullscreen mode

2. Secrets et Configuration Sécurisée

# docker-compose.yml avec secrets
version: '3.8'

services:
  app:
    image: myapp:latest
    secrets:
      - db_password
      - api_key
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password
      - API_KEY_FILE=/run/secrets/api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    external: true
Enter fullscreen mode Exit fullscreen mode
// Lecture des secrets dans l'application
const fs = require('fs');

function readSecret(secretName) {
  try {
    return fs.readFileSync(`/run/secrets/${secretName}`, 'utf8').trim();
  } catch (error) {
    console.error(`Failed to read secret ${secretName}:`, error);
    return process.env[secretName.toUpperCase()];
  }
}

const dbPassword = readSecret('db_password');
const apiKey = readSecret('api_key');
Enter fullscreen mode Exit fullscreen mode

3. Scaling et Load Balancing

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

services:
  app:
    image: myapp:latest
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
    networks:
      - app-network

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app
    networks:
      - app-network
Enter fullscreen mode Exit fullscreen mode

Monitoring et Debugging

1. Logs et Monitoring

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

services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana
    ports:
      - "3001:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
Enter fullscreen mode Exit fullscreen mode

2. Debugging avec Docker

# Accéder au shell d'un conteneur
docker exec -it myapp-container /bin/sh

# Voir les logs en temps réel
docker logs -f myapp-container

# Inspecter un conteneur
docker inspect myapp-container

# Statistiques des ressources
docker stats myapp-container

# Debugging d'une image
docker run -it --entrypoint /bin/sh myapp:latest
Enter fullscreen mode Exit fullscreen mode

Production et Déploiement

1. Image de Production Optimisée

FROM node:18-alpine AS production

# Sécurité : utilisateur non-root
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

# Optimisations
RUN apk add --no-cache dumb-init

WORKDIR /app
COPY --chown=nodejs:nodejs package*.json ./
RUN npm ci --only=production && npm cache clean --force

COPY --chown=nodejs:nodejs . .

USER nodejs

EXPOSE 3000
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "index.js"]
Enter fullscreen mode Exit fullscreen mode

2. Pipeline CI/CD avec Docker

# .github/workflows/docker.yml
name: Docker Build and Deploy

on:
  push:
    branches: [main]

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

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

      - name: Login to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: myapp:${{ github.sha }},myapp:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max
Enter fullscreen mode Exit fullscreen mode

Commandes Utiles

# Construction et gestion
docker build -t myapp:latest .
docker-compose up -d --build
docker-compose down -v

# Nettoyage
docker system prune -a
docker volume prune
docker network prune

# Debugging
docker-compose logs -f app
docker-compose exec app sh
docker inspect <container_id>

# Scaling
docker-compose up -d --scale app=3

# Backup et restore
docker-compose exec postgres pg_dump -U postgres myapp > backup.sql
docker-compose exec -T postgres psql -U postgres myapp < backup.sql
Enter fullscreen mode Exit fullscreen mode

Conclusion

Docker transforme le développement backend en offrant :

  • Cohérence des environnements de développement à production
  • Isolation et portabilité des applications
  • Simplification du déploiement et de la scalabilité
  • Amélioration de la collaboration en équipe
  • Facilitation des tests et de l'intégration continue

Maîtriser Docker est devenu essentiel pour tout développeur backend moderne. L'investissement en temps d'apprentissage est rapidement rentabilisé par la productivité et la fiabilité apportées.

Top comments (0)