Skip to content

Guide Docker

Ce guide explique comment utiliser Docker pour développer et déployer l'application.

Architecture Docker

L'application est composée de deux services containerisés :

  • Backend : API FastAPI (Python 3.13)
  • Frontend : Application Next.js (Node.js 20)

Les services communiquent via un réseau Docker dédié.

Démarrage rapide

Prérequis

  • Docker 20.10+
  • Docker Compose 2.0+

Commandes Make

# Build et démarrage (tout-en-un)
make docker-deploy

# Ou étape par étape
make docker-build    # Build des images
make docker-up       # Démarrage des conteneurs
make docker-logs     # Voir les logs
make docker-down     # Arrêt des conteneurs

Dockerfiles

Backend : Dockerfile.backend

FROM python:3.13-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv

WORKDIR /app
COPY uv.lock pyproject.toml ./
RUN uv sync --frozen --no-install-project

COPY . /app
RUN uv sync --frozen

ENV PYTHONUNBUFFERED=1
EXPOSE 8000
CMD ["uv", "run", "uvicorn", "backend.app:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

Caractéristiques : - Image légère python:3.13-slim - Utilisation de uv pour une installation rapide - Hot-reload activé en développement - Variables d'environnement passées au runtime (sécurisé)

Frontend : Dockerfile.frontend

Build multi-stage pour optimiser la taille de l'image :

  1. Stage deps : Installation des dépendances
  2. Stage builder : Build de l'application Next.js
  3. Stage runner : Image de production minimale

Caractéristiques : - Images Alpine légères (~150MB final) - Utilisateur non-root pour la sécurité - Mode standalone Next.js - Variables NEXT_PUBLIC_* injectées au build

Docker Compose

Configuration

services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile.backend
    ports:
      - "8000:8000"
    environment:
      - NOTION_TOKEN=${NOTION_TOKEN}
      - DATABASE_ID=${DATABASE_ID}
      - GCS_URI=${GCS_URI}
      - GOOGLE_APPLICATION_CREDENTIALS=/app/credentials.json
    volumes:
      - ./gcs-credentials.json:/app/credentials.json:ro

  frontend:
    build:
      context: .
      dockerfile: Dockerfile.frontend
      args:
        - NEXT_PUBLIC_API_URL=http://localhost:8000
    ports:
      - "3000:3000"
    depends_on:
      - backend

Services disponibles

Une fois démarrés, les services sont accessibles sur :

Variables d'environnement

Fichier .env

Créez un fichier .env à la racine :

# .env
NOTION_TOKEN=secret_xxxxxxxxxxxxx
DATABASE_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

# Google Cloud Storage
GCS_URI=gs://notion-dataascode/data_leads
HMAC_KEY=GOOG1EXXX...
HMAC_SECRET=your-hmac-secret

# Observabilité
LOGFIRE_TOKEN=logfire_xxxxxxxxxxxxx

Docker Compose charge automatiquement ce fichier.

Credentials GCS

Placez votre fichier de credentials GCS à la racine du projet :

# Le fichier gcs-credentials.json doit être à la racine
cp /chemin/vers/votre/credentials.json ./gcs-credentials.json

Sécurité

Assurez-vous que gcs-credentials.json est dans le .gitignore pour ne jamais le committer.

Build args vs ENV

Sécurité

  • ✅ Utilisez ENV au runtime pour les secrets
  • ❌ N'utilisez jamais ARG pour les secrets (visible dans l'historique Docker)

Backend : Secrets passés via environment au runtime

environment:
  - NOTION_TOKEN=${NOTION_TOKEN}  # ✅ Sécurisé
  - GCS_URI=${GCS_URI}            # ✅ Pas un secret
  - GOOGLE_APPLICATION_CREDENTIALS=/app/credentials.json  # ✅ Chemin dans le conteneur
volumes:
  - ./gcs-credentials.json:/app/credentials.json:ro  # ✅ Monté en lecture seule

Frontend : URL de l'API passée via build args (pas de secret)

args:
  - NEXT_PUBLIC_API_URL=http://localhost:8000  # ✅ Pas de secret

Volumes Docker

Backend

volumes:
  - ./gcs-credentials.json:/app/credentials.json:ro

Le fichier de credentials GCS est monté en lecture seule (:ro) dans le conteneur.

Stockage des données

Les données Delta Lake sont maintenant stockées sur Google Cloud Storage (GCS) et non plus localement. Le montage d'un volume pour data_leads n'est plus nécessaire.

Frontend

Pas de volume nécessaire car Next.js est compilé dans l'image.

Health Checks

Les services ont des health checks configurés :

healthcheck:
  test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8000/docs"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 40s

Vérifier le statut :

docker ps
docker inspect dataascode-backend | grep -A 10 Health

Réseaux

Les services communiquent via un réseau bridge dédié :

networks:
  dataascode-network:
    driver: bridge

Logs

Voir les logs

# Tous les services
make docker-logs

# Service spécifique
docker logs dataascode-backend
docker logs dataascode-frontend

# Follow mode
docker logs -f dataascode-backend

Logs structurés avec Logfire

Le backend utilise Logfire + Loguru pour des logs structurés et de l'observabilité :

2025-10-26 15:30:12 | INFO | 📊 Starting weekly aggregation for columns: [...]
2025-10-26 15:30:13 | INFO | ✅ Weekly aggregation completed: 24 weeks returned

Visualisation dans Logfire : - Dashboard temps réel : https://logfire.pydantic.dev - Traces distribuées des requêtes - Métriques de performance - Recherche et filtrage avancés

Debugging

Accéder à un conteneur

# Backend
docker exec -it dataascode-backend /bin/sh
uv run python

# Frontend
docker exec -it dataascode-frontend /bin/sh

Rebuild après modifications

# Rebuild complet
make docker-build

# Rebuild sans cache
docker-compose build --no-cache

# Rebuild un seul service
docker-compose build backend

Optimisations

Cache Docker

Les Dockerfiles utilisent des layers cachés pour accélérer les builds :

  1. Copie des fichiers de dépendances d'abord
  2. Installation des dépendances (mise en cache)
  3. Copie du code source (invalide le cache seulement si le code change)

.dockerignore

Des fichiers .dockerignore spécifiques excluent les fichiers inutiles :

  • Dockerfile.backend.dockerignore : Exclut frontend/
  • Dockerfile.frontend.dockerignore : Exclut backend/

Taille des images

# Voir la taille des images
docker images | grep dataascode

# Résultats typiques
dataascode-backend    ~500MB
dataascode-frontend   ~150MB

Production

Build pour la production

# Frontend avec URL API personnalisée
docker-compose build \
  --build-arg NEXT_PUBLIC_API_URL=https://api.example.com \
  frontend

Docker Compose production

Créez un docker-compose.prod.yml :

services:
  backend:
    restart: always
    command: ["uv", "run", "uvicorn", "backend.app:app", "--host", "0.0.0.0", "--port", "8000"]
    # Sans --reload

  frontend:
    restart: always
    environment:
      - NODE_ENV=production
docker-compose -f docker-compose.prod.yml up -d

Troubleshooting

Port déjà utilisé

# Erreur : bind: address already in use
# Trouver le processus
lsof -i :3000
lsof -i :8000

# Arrêter le processus ou changer le port dans docker-compose.yml

Conteneur ne démarre pas

# Voir les logs d'erreur
docker logs dataascode-backend

# Vérifier le statut
docker ps -a

Build échoue

# Rebuild sans cache
docker-compose build --no-cache

# Nettoyer les images
docker system prune -a

Commandes utiles

# Statut des conteneurs
docker ps

# Arrêter tout
docker-compose down

# Arrêter et supprimer les volumes
docker-compose down -v

# Nettoyer tout
docker system prune -a --volumes

# Voir l'utilisation des ressources
docker stats

Prochaines étapes