Kubernetes : Deploiement d’Applications Conteneurisees
Introduction Kubernetes (K8s) est le standard pour l'orchestration de containers en production. Ce guide couvre…
Docker transforme le développement en garantissant que votre application fonctionne identiquement partout. Ce guide couvre les pratiques essentielles pour conteneuriser vos applications efficacement.
┌─────────────────────────────────────┐
│ Application (Votre Code) │
├─────────────────────────────────────┤
│ Container Runtime (Docker) │
├─────────────────────────────────────┤
│ Host OS (Linux/Windows/Mac) │
├─────────────────────────────────────┤
│ Infrastructure (Physique/Cloud) │
└─────────────────────────────────────┘
# Ubuntu/Debian
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Configuration post-installation
sudo systemctl enable docker
sudo systemctl start docker
# Vérification
docker --version
docker run hello-world
# macOS/Windows
# Télécharger Docker Desktop depuis:
# https://www.docker.com/products/docker-desktop
# Vérifier l'installation
docker info
docker compose version
// /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"default-address-pools": [
{
"base": "172.17.0.0/16",
"size": 24
}
],
"dns": ["8.8.8.8", "8.8.4.4"],
"insecure-registries": [],
"registry-mirrors": [],
"features": {
"buildkit": true
}
}
# Recharger la configuration
sudo systemctl daemon-reload
sudo systemctl restart docker
# Mauvaise approche (À NE PAS FAIRE)
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]
# Problèmes:
# - Image énorme (~1GB)
# - Installe dev dependencies
# - Rebuild cache inefficace
# - Tourne en root
# - Pas de healthcheck
# Meilleure approche
FROM node:18-alpine AS base
# Metadata
LABEL maintainer="dev@example.com"
LABEL version="1.0"
LABEL description="Production-ready Node.js application"
# Install security updates
RUN apk update &&
apk upgrade &&
apk add --no-cache dumb-init &&
rm -rf /var/cache/apk/
# Create app directory
WORKDIR /app
# Create non-root user
RUN addgroup -g 1001 -S nodejs &&
adduser -S nodejs -u 1001
# Copy dependency files first (better cache)
COPY --chown=nodejs:nodejs package.json ./
# Install dependencies
RUN npm ci --only=production &&
npm cache clean --force
# Copy application code
COPY --chown=nodejs:nodejs . .
# Switch to non-root user
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD node healthcheck.js || exit 1
# Use dumb-init to handle signals properly
ENTRYPOINT ["dumb-init", "--"]
# Start application
CMD ["node", "server.js"]
# Stage 1: Dependencies
FROM node:18-alpine AS deps
WORKDIR /app
COPY package.json ./
RUN npm ci --only=production &&
npm cache clean --force
# Stage 2: Build
FROM node:18-alpine AS builder
WORKDIR /app
# Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
# Copy source code
COPY . .
# Build application
RUN npm run build &&
npm prune --production
# Stage 3: Test (optional, can be skipped in prod builds)
FROM builder AS test
# Install dev dependencies for testing
RUN npm install --only=development
# Run tests
RUN npm run test &&
npm run lint
# Stage 4: Production
FROM node:18-alpine AS production
WORKDIR /app
# Install only runtime dependencies
RUN apk add --no-cache dumb-init
# Create non-root user
RUN addgroup -g 1001 -S nodejs &&
adduser -S nodejs -u 1001
# Copy built application from builder
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/package.json ./
# Create necessary directories
RUN mkdir -p /app/logs &&
chown -R nodejs:nodejs /app
USER nodejs
EXPOSE 3000
ENV NODE_ENV=production
PORT=3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/server.js"]
# Multi-stage Python application
FROM python:3.11-slim AS base
# Prevent Python from writing .pyc files
ENV PYTHONDONTWRITEBYTECODE=1
PYTHONUNBUFFERED=1
WORKDIR /app
# Install system dependencies
RUN apt-get update &&
apt-get install -y --no-install-recommends
gcc
libpq-dev &&
rm -rf /var/lib/apt/lists/
# Stage: Dependencies
FROM base AS deps
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip &&
pip install --no-cache-dir -r requirements.txt
# Stage: Production
FROM python:3.11-slim AS production
WORKDIR /app
# Copy installed packages
COPY --from=deps /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=deps /usr/local/bin /usr/local/bin
# Create non-root user
RUN useradd -m -u 1001 appuser &&
chown -R appuser:appuser /app
# Copy application
COPY --chown=appuser:appuser . .
USER appuser
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s
CMD python -c "import requests; requests.get('http://localhost:8000/health')" || exit 1
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "app:app"]
# Stage 1: Build
FROM golang:1.21-alpine AS builder
WORKDIR /app
# Copy go mod files
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy source code
COPY . .
# Build binary
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
# Stage 2: Production
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# Copy binary from builder
COPY --from=builder /app/main .
# Expose port
EXPOSE 8080
# Run
CMD ["./main"]
# Stage 1: Build
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
# Copy pom.xml first for better caching
COPY pom.xml .
# Download dependencies
RUN mvn dependency:go-offline
# Copy source and build
COPY src ./src
RUN mvn package -DskipTests
# Stage 2: Production
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# Create non-root user
RUN addgroup -g 1001 spring &&
adduser -S spring -u 1001 -G spring
# Copy jar from builder
COPY --from=builder /app/target/.jar app.jar
# Change ownership
RUN chown spring:spring app.jar
USER spring
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s
CMD wget --quiet --tries=1 --spider http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-jar", "app.jar"]
# docker-compose.yml
version: '3.8'
# Réseaux personnalisés
networks:
frontend:
driver: bridge
backend:
driver: bridge
# Volumes persistants
volumes:
mongo-data:
driver: local
redis-data:
driver: local
nginx-logs:
driver: local
services:
# MongoDB Database
mongodb:
image: mongo:7
container_name: app-mongodb
restart: unless-stopped
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER:-admin}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD:-secret}
MONGO_INITDB_DATABASE: ${MONGO_DATABASE:-appdb}
volumes:
- mongo-data:/data/db
- ./mongo-init:/docker-entrypoint-initdb.d:ro
networks:
- backend
ports:
- "27017:27017"
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
command: --quiet --logpath /dev/null
# Redis Cache
redis:
image: redis:7-alpine
container_name: app-redis
restart: unless-stopped
volumes:
- redis-data:/data
- ./redis.conf:/usr/local/etc/redis/redis.conf:ro
networks:
- backend
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
command: redis-server /usr/local/etc/redis/redis.conf
# Backend API (Node.js)
api:
build:
context: ./backend
dockerfile: Dockerfile
target: production
args:
NODE_ENV: development
container_name: app-api
restart: unless-stopped
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: ${NODE_ENV:-development}
PORT: 5000
MONGODB_URI: mongodb://${MONGO_ROOT_USER:-admin}:${MONGO_ROOT_PASSWORD:-secret}@mongodb:27017/${MONGO_DATABASE:-appdb}?authSource=admin
REDIS_URL: redis://redis:6379
JWT_SECRET: ${JWT_SECRET:-your-secret-key}
LOG_LEVEL: ${LOG_LEVEL:-info}
volumes:
- ./backend:/app
- /app/node_modules
- ./logs:/app/logs
networks:
- frontend
- backend
ports:
- "5000:5000"
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Frontend (React)
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
target: development
args:
REACT_APP_API_URL: http://localhost:5000/api
container_name: app-frontend
restart: unless-stopped
depends_on:
- api
environment:
REACT_APP_API_URL: ${API_URL:-http://localhost:5000/api}
CHOKIDAR_USEPOLLING: true
volumes:
- ./frontend:/app
- /app/node_modules
networks:
- frontend
ports:
- "3000:3000"
stdin_open: true
tty: true
# Nginx Reverse Proxy
nginx:
image: nginx:alpine
container_name: app-nginx
restart: unless-stopped
depends_on:
- api
- frontend
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- nginx-logs:/var/log/nginx
networks:
- frontend
ports:
- "80:80"
- "443:443"
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
# Worker for background jobs
worker:
build:
context: ./backend
dockerfile: Dockerfile
target: production
container_name: app-worker
restart: unless-stopped
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: ${NODE_ENV:-development}
MONGODB_URI: mongodb://${MONGO_ROOT_USER:-admin}:${MONGO_ROOT_PASSWORD:-secret}@mongodb:27017/${MONGO_DATABASE:-appdb}?authSource=admin
REDIS_URL: redis://redis:6379
volumes:
- ./backend:/app
- /app/node_modules
networks:
- backend
command: node workers/queue-processor.js
# Monitoring - Prometheus
prometheus:
image: prom/prometheus:latest
container_name: app-prometheus
restart: unless-stopped
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
- backend
ports:
- "9090:9090"
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
# Monitoring - Grafana
grafana:
image: grafana/grafana:latest
container_name: app-grafana
restart: unless-stopped
depends_on:
- prometheus
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning:ro
networks:
- backend
- frontend
ports:
- "3001:3000"
volumes:
prometheus-data:
grafana-data:
# .env
# Application
NODE_ENV=development
LOG_LEVEL=debug
# Database
MONGO_ROOT_USER=admin
MONGO_ROOT_PASSWORD=supersecretpassword
MONGO_DATABASE=appdb
# API
JWT_SECRET=your-jwt-secret-key-change-in-production
API_URL=http://localhost:5000/api
# Monitoring
GRAFANA_USER=admin
GRAFANA_PASSWORD=admin123
# nginx/conf.d/default.conf
upstream frontend {
server frontend:3000;
}
upstream api {
server api:5000;
}
# Rate limiting
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
listen 80;
server_name localhost;
client_max_body_size 20M;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Compression
gzip on;
gzip_vary on;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss;
# Frontend
location / {
proxy_pass http://frontend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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;
}
# API with rate limiting
location /api {
limit_req zone=api_limit burst=20 nodelay;
limit_conn conn_limit 10;
proxy_pass http://api;
proxy_http_version 1.1;
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;
# Timeout settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthyn";
add_header Content-Type text/plain;
}
}
# Démarrer tous les services
docker compose up -d
# Démarrer avec rebuild
docker compose up -d --build
# Voir les logs
docker compose logs -f
# Logs d'un service spécifique
docker compose logs -f api
# Arrêter tous les services
docker compose down
# Arrêter et supprimer les volumes
docker compose down -v
# Redémarrer un service
docker compose restart api
# Exécuter une commande dans un service
docker compose exec api npm test
# Scaler un service
docker compose up -d --scale worker=3
# Voir l'état des services
docker compose ps
# Voir les ressources utilisées
docker compose stats
# Valider le fichier docker-compose
docker compose config
# Pull des dernières images
docker compose pull
# Build sans cache
docker compose build --no-cache
# Créer et démarrer seulement certains services
docker compose up -d mongodb redis api
# .dockerignore
# Dependencies
node_modules/
npm-debug.log
yarn-error.log
package-lock.json
# Testing
coverage/
.nyc_output/
test-results/
# Build
dist/
build/
.log
# IDE
.vscode/
.idea/
.swp
.swo
.DS_Store
# Git
.git/
.gitignore
.gitattributes
# CI/CD
.github/
.gitlab-ci.yml
.travis.yml
# Docker
Dockerfile
docker-compose
.dockerignore
# Documentation
README.md
CHANGELOG.md
LICENSE
docs/
# Environment
.env
.env.
!.env.example
# OS
Thumbs.db
# syntax=docker/dockerfile:1.4
FROM node:18-alpine AS base
# Enable BuildKit cache mounts
WORKDIR /app
# Stage: Dependencies avec cache mount
FROM base AS deps
RUN --mount=type=cache,target=/root/.npm
--mount=type=bind,source=package.json,target=package.json
--mount=type=bind,source=package-lock.json,target=package-lock.json
npm ci --only=production
# Stage: Build avec cache mount
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN --mount=type=cache,target=/root/.npm
npm run build
# Stage: Production minimale
FROM base AS production
COPY --from=builder /app/dist ./dist
COPY --from=deps /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]
# Build avec BuildKit
DOCKER_BUILDKIT=1 docker build -t myapp:latest .
# Build avec cache registry
docker buildx build
--cache-from=type=registry,ref=myregistry.com/myapp:cache
--cache-to=type=registry,ref=myregistry.com/myapp:cache,mode=max
-t myapp:latest
--push
.
# Setup buildx
docker buildx create --name multiarch --use
docker buildx inspect --bootstrap
# Build pour plusieurs architectures
docker buildx build
--platform linux/amd64,linux/arm64,linux/arm/v7
-t myapp:latest
--push
.
# docker-compose.prod.yml
version: '3.8'
services:
api:
image: myregistry.com/myapp:${VERSION:-latest}
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
order: start-first
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
// healthcheck.js
const http = require('http');
const options = {
host: 'localhost',
port: process.env.PORT || 3000,
path: '/health',
timeout: 2000
};
const request = http.request(options, (res) => {
console.log(STATUS: ${res.statusCode});
if (res.statusCode === 200) {
process.exit(0);
} else {
process.exit(1);
}
});
request.on('error', (err) => {
console.error('ERROR:', err);
process.exit(1);
});
request.end();
# Dockerfile avec sécurité renforcée
FROM node:18-alpine AS base
# Scan vulnerabilities pendant le build
RUN apk add --no-cache
curl
&& curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# Stage de scan
FROM base AS scan
COPY package.json ./
RUN trivy fs --severity HIGH,CRITICAL --exit-code 1 .
# Stage production
FROM node:18-alpine AS production
# Installer seulement les paquets nécessaires
RUN apk add --no-cache dumb-init
# Créer utilisateur non-root
RUN addgroup -g 1001 -S nodejs &&
adduser -S nodejs -u 1001
# Ne pas exposer de secrets
ARG BUILD_DATE
ARG VCS_REF
LABEL org.opencontainers.image.created=$BUILD_DATE
org.opencontainers.image.revision=$VCS_REF
# Copier seulement le nécessaire
COPY --chown=nodejs:nodejs dist/ ./dist/
COPY --chown=nodejs:nodejs node_modules/ ./node_modules/
# Read-only filesystem sauf /tmp
RUN chmod -R 555 /app &&
mkdir /tmp/app &&
chown nodejs:nodejs /tmp/app
USER nodejs
# Utiliser ENTRYPOINT pour le init system
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/server.js"]
# Build avec verbose output
docker build --progress=plain --no-cache -t myapp .
# Build jusqu'à un stage spécifique
docker build --target builder -t myapp:builder .
# Inspecter une layer
docker history myapp:latest
# Voir les détails d'une image
docker inspect myapp:latest
# Entrer dans un container failed
docker run -it --entrypoint /bin/sh myapp:latest
# Copier des fichiers depuis un container
docker cp container_id:/app/logs ./local-logs
# Voir les logs
docker logs -f container_name
# Voir les logs avec timestamps
docker logs -f --timestamps container_name
# Exec dans un container en cours
docker exec -it container_name sh
# Voir les processus
docker top container_name
# Voir les stats en temps réel
docker stats container_name
# Inspecter le network
docker network inspect bridge
# Voir les events
docker events
# Debug avec strace
docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined
-it myapp strace -f node server.js
# 1. Container exit immédiatement
# Problème: CMD invalide ou erreur au démarrage
# Debug:
docker logs container_name
docker run -it --entrypoint /bin/sh myapp
# 2. Build lent
# Solution: Optimiser l'ordre des COPY et utiliser cache
# Vérifier:
docker build --progress=plain .
# 3. Image trop grosse
# Analyser:
docker history myapp:latest
dive myapp:latest # Installer: https://github.com/wagoodman/dive
# 4. Network issues entre containers
# Debug:
docker network ls
docker network inspect mynetwork
docker exec container1 ping container2
docker exec container1 nslookup container2
# 5. Permission denied
# Fix:
RUN chown -R nodejs:nodejs /app
USER nodejs
# 6. Out of space
docker system df
docker system prune -a --volumes
# docker-compose.monitoring.yml
version: '3.8'
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
privileged: true
devices:
- /dev/kmsg:/dev/kmsg
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker:/var/lib/docker:ro
- /cgroup:/cgroup:ro
ports:
- "8080:8080"
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
ports:
- "9100:9100"
services:
api:
# Soft limits (réservations)
deploy:
resources:
reservations:
cpus: '0.5'
memory: 256M
limits:
cpus: '2'
memory: 1G
# Limites mémoire au niveau runtime
mem_limit: 1g
mem_reservation: 512m
cpus: 2
# OOM killer priority
oom_score_adj: -500
# ulimits
ulimits:
nofile:
soft: 65536
hard: 65536
nproc: 65535
# .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [main]
tags: ['v']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Scan image
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
format: 'sarif'
output: 'trivy-results.sarif'
# Makefile
.PHONY: help build up down logs clean
COMPOSE=docker compose
COMPOSE_PROD=docker compose -f docker-compose.yml -f docker-compose.prod.yml
help: ## Afficher l'aide
@grep -E '^[a-zA-Z-]+:.?## .$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.?## "}; {printf " 33[36m%-30s 33[0m %sn", $$1, $$2}'
build: ## Build les images
$(COMPOSE) build
up: ## Démarrer en mode dev
$(COMPOSE) up -d
down: ## Arrêter les services
$(COMPOSE) down
logs: ## Voir les logs
$(COMPOSE) logs -f
restart: ## Redémarrer
$(COMPOSE) restart
clean: ## Nettoyer containers, images, volumes
$(COMPOSE) down -v --rmi local
docker system prune -f
prod: ## Démarrer en mode production
$(COMPOSE_PROD) up -d
test: ## Run tests
$(COMPOSE) run --rm api npm test
shell: ## Shell dans container api
$(COMPOSE) exec api sh
db-shell: ## Shell MongoDB
$(COMPOSE) exec mongodb mongosh -u admin -p secret
backup: ## Backup MongoDB
mkdir -p backups
$(COMPOSE) exec -T mongodb mongodump --archive > backups/dump$$(date +%Y%m%d%H%M%S).archive
restore: ## Restore MongoDB (utiliser: make restore FILE=backups/dump.archive)
$(COMPOSE) exec -T mongodb mongorestore --archive < $(FILE)
#!/bin/bash
# deploy.sh
set -e
VERSION=${1:-latest}
ENVIRONMENT=${2:-staging}
echo "Deploying version $VERSION to $ENVIRONMENT..."
# Pull latest images
docker compose -f docker-compose.${ENVIRONMENT}.yml pull
# Backup database
echo "Creating backup..."
docker compose exec -T mongodb mongodump --archive > backup$(date +%Y%m%d%H%M%S).archive
# Deploy with zero-downtime
echo "Starting new containers..."
docker compose -f docker-compose.${ENVIRONMENT}.yml up -d --no-deps --scale api=2 api
# Wait for health check
echo "Waiting for health check..."
sleep 10
# Health check
if curl -f http://localhost:5000/health; then
echo "Health check passed"
# Scale down old containers
docker compose -f docker-compose.${ENVIRONMENT}.yml up -d --no-deps --scale api=2 api
echo "Deployment successful!"
else
echo "Health check failed, rolling back..."
docker compose -f docker-compose.${ENVIRONMENT}.yml up -d --no-deps --scale api=2 api
exit 1
fi
# Cleanup old images
docker image prune -f
Docker transforme le développement moderne en assurant :
Checklist de production :
Avec ces pratiques, Docker devient un outil puissant pour le développement et la production.
Cet article est vivant - corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.