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
2. Architecture Docker
Application
↓
Docker Daemon
↓
Host OS Kernel
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"]
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"]
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"]
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
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;
}
}
}
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"]
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/
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"]
// Health check endpoint
app.get('/health', (req, res) => {
res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
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
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
// 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');
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
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
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
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"]
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
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
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)