Docker Compose : Rust + PostgreSQL
Pourquoi Docker Compose : Rust + PostgreSQL ?
Dans le monde d'un développeur Rust, le développement d'applications qui nécessitent une base de données peut être un défi majeur. En effet, l'installation et la configuration des outils nécessaires peuvent être fastidieuses et chronophage. C'est là que Docker Compose entre en jeu. Il permet de définir et de gérer les applications multi-conteneurs à partir d'un simple fichier YAML. Pour ce tutoriel, nous allons explorer comment utiliser Docker Compose avec Rust et PostgreSQL pour créer un environnement de développement efficace et portable.
Prerequis
Avant de commencer, vous devrez disposer des connaissances suivantes :
- Connaissances avancées en Rust
- Familiarité avec les bases de données relationnelles comme PostgreSQL
- Compréhension de Docker et Docker Compose
Vous aurez besoin d'installer les outils suivants :
- Rust : Installez la version recommandée via
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - PostgreSQL : Installez PostgreSQL en utilisant votre gestionnaire de paquets (ex:
sudo apt-get install postgresql) - Docker : Installez Docker depuis le site officiel (https://docs.docker.com/get-docker/)
- Docker Compose : Installez Docker Compose via
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
Concepts fondamentaux
1. Docker Compose
Docker Compose est un outil pour définir et gérer des applications multi-conteneurs en utilisant un fichier YAML nommé docker-compose.yml. Voici comment il fonctionne :
version: '3'
services:
app:
build: .
ports:
- "8080:8080"
Dans cet exemple, on définit un service appelé app qui est construit à partir du Dockerfile dans le répertoire courant et expose le port 8080.
2. Base de données PostgreSQL
PostgreSQL est une base de données relationnelle open-source très populaire. Pour utiliser PostgreSQL avec Docker Compose, on définit un service comme suit :
version: '3'
services:
db:
image: postgres:13
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: password
Ce service utilise l'image officielle de PostgreSQL et définit les variables d'environnement nécessaires pour créer une base de données.
3. Connexion entre les services
Pour connecter le service Rust à la base de données, on peut utiliser un environnement de développement complet. Voici comment configurer Docker Compose pour cela :
version: '3'
services:
app:
build: .
ports:
- "8080:8080"
depends_on:
- db
environment:
DATABASE_URL: postgres://user:password@db/mydb
db:
image: postgres:13
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: password
Dans ce fichier, le service app dépend du service db, et on définit l'environnement pour la connexion à la base de données.
Mise en pratique : projet fil rouge
Pour illustrer comment utiliser Rust et PostgreSQL avec Docker Compose, nous allons créer un simple gestionnaire de tâches. Voici les étapes pour construire ce projet :
1. Création du projet
Créez un nouveau répertoire et initialisez le projet Rust :
mkdir task_manager
cd task_manager
cargo new --bin task_manager
2. Ajout des dépendances
Ajoutez les dépendances nécessaires dans Cargo.toml :
[dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
sqlx = { version = "0.6", features = ["runtime-tokio-native-tls", "postgres"] }
dotenv = "0.15"
3. Configuration de l'environnement
Créez un fichier .env pour stocker les variables d'environnement :
DATABASE_URL=postgres://user:password@db/mydb
4. Connexion à la base de données
Modifiez src/main.rs pour établir une connexion à la base de données et créer un simple CRUD API :
use sqlx::postgres::PgPool;
use std::env;
#[derive(sqlx::FromRow)]
struct Task {
id: i32,
title: String,
completed: bool,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let database_url = env::var("DATABASE_URL")?;
let pool = PgPool::connect(&database_url).await?;
// Création de la table si elle n'existe pas
sqlx::query!(
"CREATE TABLE IF NOT EXISTS tasks (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
completed BOOLEAN NOT NULL DEFAULT false
)"
)
.execute(&pool)
.await?;
// Ajout d'une nouvelle tâche
sqlx::query!(
"INSERT INTO tasks (title, completed) VALUES ($1, $2) RETURNING *",
"Buy groceries",
false
)
.fetch_one(&pool)
.await?;
// Récupération de toutes les tâches
let tasks: Vec<Task> = sqlx::query_as!("SELECT * FROM tasks")
.fetch_all(&pool)
.await?;
println!("{:#?}", tasks);
Ok(())
}
5. Création du docker-compose.yml
Créez un fichier docker-compose.yml pour définir les services :
version: '3'
services:
app:
build: .
ports:
- "8080:8080"
depends_on:
- db
environment:
DATABASE_URL: postgres://user:password@db/mydb
db:
image: postgres:13
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: password
6. Construction et exécution
Exécutez les commandes suivantes pour construire et exécuter le projet :
docker-compose up --build
Erreurs frequentes et debugging
Voici quelques erreurs courantes qui peuvent survenir lors de l'utilisation de Docker Compose avec Rust et PostgreSQL :
Erreur de connexion à la base de données
# ❌ Mauvais sqlx::query!("SELECT * FROM tasks") .fetch_all(&pool) .await?; # ✅ Correct let tasks: Vec<Task> = sqlx::query_as!( "SELECT * FROM tasks", Task as _, ) .fetch_all(&pool) .await?;Erreur de migration de la base de données
# ❌ Mauvais sqlx::query!("CREATE TABLE IF NOT EXISTS tasks (id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, completed BOOLEAN NOT NULL DEFAULT false)") .execute(&pool) .await?; # ✅ Correct sqlx::query!( "CREATE TABLE IF NOT EXISTS tasks ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, completed BOOLEAN NOT NULL DEFAULT false )" ) .execute(&pool) .await?;Erreur de syntaxe dans le Dockerfile
# ❌ Mauvais FROM rust:1.56.0 ADD . /app WORKDIR /app RUN cargo build --release # ✅ Correct FROM rust:1.56.0 as builder COPY Cargo.toml Cargo.lock ./ RUN cargo fetch COPY . . RUN cargo build --release FROM alpine:latest COPY --from=builder /app/target/release/task_manager /usr/local/bin/task_manager CMD ["task_manager"]
Pour aller plus loin
Voici trois pistes pour approfondir ce sujet :
- Utiliser des migrations avec Flyway ou Liquibase : Ajoutez des migrations pour gérer les schémas de votre base de données.
- Ajouter une interface utilisateur Web : Utilisez une bibliothèque comme Actix-web pour créer une API RESTful.
- Intégrer un système d'authentification : Ajoutez une authentification JWT pour sécuriser les routes de votre application.
Un défi pratique à réaliser seul est de créer une API simple qui permet de gérer des utilisateurs et leurs tâches. Utilisez actix-web pour le backend et PostgreSQL pour la base de données.
C'est tout ! Vous maintenant comment utiliser Docker Compose avec Rust et PostgreSQL pour créer un environnement de développement efficient et portable.