Docker Compose : FastAPI + PostgreSQL
Pourquoi Docker Compose : FastAPI + PostgreSQL ?
En tant que développeur, vous avez certainement dû travailler sur des applications qui nécessitent une base de données relationnelle comme PostgreSQL. Le développement et le déploiement de telles applications peuvent être fastidieux et chronophage, surtout lorsqu'elles sont complexes et dépendent de plusieurs services différents. C'est là que Docker Compose entre en jeu.
Docker Compose est un outil qui permet de définir et de gérer des applications multi-conteneurs à l'aide d'un seul fichier YAML. Il simplifie le processus de développement, du test au déploiement en facilitant la création et la gestion des environnements conteneurisés.
Un cas concret est celui d'une application de gestion de tâches qui nécessite une base de données PostgreSQL pour stocker les informations sur les tâches. Avec Docker Compose, vous pouvez facilement configurer et exécuter le backend avec FastAPI et le frontend avec une base de données PostgreSQL dans un environnement isolé.
Prerequis
- Connaissance de base de Python
- Familiarité avec FastAPI et ASGI
- Connaissances en SQL et PostgreSQL
- Installation de Docker (version >= 1.23.0)
- Installation de Docker Compose (version >= 1.29.2)
Concepts fondamentaux
1. Conteneurisation : Le principe
Un conteneur est une unité isolée qui encapsule le logiciel et ses dépendances pour qu'il puisse être exécuté de manière indépendante des autres applications sur la même machine physique ou virtuelle.
## Dockerfile pour une application FastAPI
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]
2. Docker Compose : Le fichier docker-compose.yml
Le fichier docker-compose.yml est utilisé pour définir et exécuter des applications multi-conteneurs.
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:12
environment:
POSTGRES_DB: todoapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
3. Services : Les composants de votre application
Dans le fichier docker-compose.yml, les services définissent les conteneurs qui constituent l'application.
services:
app:
build: .
ports:
- "8000:8000"
4. Volumes : Persistance des données
Les volumes permettent de persister des données entre les redémarrages du conteneur et d'éviter la perte des données.
volumes:
db_data:
Mise en pratique : projet fil rouge
Nous allons créer un gestionnaire de tâches simple avec FastAPI et PostgreSQL. Voici une étape à l'étape pour mettre en place le projet.
Étape 1 : Création du projet
Créez un nouveau répertoire pour votre projet :
mkdir fastapi-postgresql-todo
cd fastapi-postgresql-todo
Étape 2 : Création des fichiers nécessaires
Créer les fichiers suivants :
requirements.txtmain.pydocker-compose.yml
requirements.txt
fastapi[all]
uvicorn
psycopg2-binary
sqlalchemy
main.py
from fastapi import FastAPI, Depends
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
app = FastAPI()
SQLALCHEMY_DATABASE_URL = "postgresql://user:password@db/todoapp"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class Task(Base):
__tablename__ = "tasks"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String)
Base.metadata.create_all(bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.post("/tasks/")
async def create_task(task: dict, db: Session = Depends(get_db)):
new_task = Task(title=task["title"], description=task.get("description"))
db.add(new_task)
db.commit()
db.refresh(new_task)
return new_task
@app.get("/tasks/")
async def read_tasks(db: Session = Depends(get_db)):
tasks = db.query(Task).all()
return tasks
docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:12
environment:
POSTGRES_DB: todoapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Étape 3 : Construction et exécution du projet
Construisez et exécutez le projet avec Docker Compose :
docker-compose up --build
Étape 4 : Test de l'API
Ouvrez un navigateur et accédez à http://localhost:8000/docs. Vous devriez voir la documentation Swagger de votre API FastAPI. Essayez les endpoints /tasks/.
Erreurs frequentes et debugging
1. Connexion échoue : ConnectionRefusedError
L'erreur suivante peut apparaître si le conteneur PostgreSQL ne se lance pas correctement :
Could not connect to database: could not connect to server: Connection refused
Is the server running on host "db" (172.18.0.3) and accepting connections on port 5432?
Cause : Le conteneur PostgreSQL ne s'est pas lancé correctement.
Correction :
docker-compose logs db
Vérifiez les journaux de l'erreur et corrigez le problème avant de relancer la commande docker-compose up --build.
2. Mauvaise image Docker
L'erreur suivante peut apparaître si vous utilisez une image Docker incorrecte :
Could not pull image: no such image: postgres:12: Pulling from library/postgres
Error response from daemon: manifest for library/postgres:12 not found
Cause : L'image Docker spécifiée n'existe pas.
Correction :
Assurez-vous d'avoir correctement indiqué la version de l'image PostgreSQL dans le fichier docker-compose.yml.
3. Mauvais chemin pour les fichiers
L'erreur suivante peut apparaître si vous utilisez un chemin incorrect pour les fichiers :
Could not find module 'main': No module named 'main'
Cause : Le chemin vers le fichier main.py est incorrect.
Correction :
Assurez-vous de bien indiquer le chemin dans le Dockerfile.
Pour aller plus loin
- Intégration continue avec GitHub Actions : Configurez un pipeline CI/CD pour automatiser les tests et le déploiement.
- Authentification JWT : Ajoutez une couche de sécurité en intégrant l'authentification JWT.
- Documentation Swagger UI personnalisée : Personnalisez la documentation Swagger UI avec des informations supplémentaires.
Défi pratique : Implémentez une fonctionnalité d'édition et de suppression de tâches dans votre API FastAPI.