Docker Compose : NestJS + PostgreSQL
Pourquoi Docker Compose : NestJS + PostgreSQL ?
Docker Compose est une outil de gestion des conteneurs multi-conteneur. Il permet de définir et d'exécuter des applications avec plusieurs services en utilisant un simple fichier docker-compose.yml. C'est particulièrement utile pour les développeurs qui travaillent sur des projets complexes qui nécessitent plusieurs services, comme une application NestJS qui utilise une base de données PostgreSQL.
Un cas concret est la mise en place d'un microservice qui nécessite une interaction continue avec une base de données. Docker Compose permet une configuration simple et réplicable, ce qui facilite le développement et le déploiement de l'application dans un environnement local et dans un environnement de production.
Prerequis
Connaissances Nécessaires :
- Base en NestJS
- Connaissance des bases de données relationnelles (PostgreSQL)
- Familiarité avec Docker et Docker Compose
Outils à Installer :
- Node.js v14.x ou plus tard
- npm v6.0.0 ou plus tard
- PostgreSQL v12.x ou plus tard
- Docker v3.0.0 ou plus tard
- Docker Compose v1.29.2 ou plus tard
Concepts Fondamentaux
1. Dockerfile
Un Dockerfile est un fichier texte qui contient une série d'instructions pour construire une image Docker. Voici un exemple simple pour une application NestJS :
## utilisation de l'image officielle Node.js en version LTS
FROM node:14 as builder
## création du répertoire de travail dans le conteneur
WORKDIR /usr/src/app
## copie des fichiers package.json et package-lock.json
COPY package*.json ./
## installation des dépendances
RUN npm install
## copie du code source
COPY . .
## compilation de l'application NestJS
RUN npm run build
2. docker-compose.yml
Le fichier docker-compose.yml est utilisé pour définir et exécuter plusieurs services conteneurs. Voici un exemple pour notre application NestJS avec PostgreSQL :
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_USER=myuser
- POSTGRES_PASSWORD=mypassword
- POSTGRES_DB=mydatabase
depends_on:
- postgres
postgres:
image: postgres:12
environment:
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_USER=myuser
- POSTGRES_PASSWORD=mypassword
- POSTGRES_DB=mydatabase
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
3. Volumes
Les volumes permettent de stocker des données persistantes en dehors du conteneur, facilitant la sauvegarde et le partage des données entre les conteneurs.
4. Environment Variables
Les variables d'environnement sont utilisées pour passer des configurations à l'application dans le conteneur.
Mise en Pratique : Projet Fil Rouge
Nous allons créer un gestionnaire de tâches simple avec une API NestJS et une base de données PostgreSQL.
Étape 1 : Créer le projet NestJS
npm install -g @nestjs/cli
nest new task-manager
cd task-manager
Étape 2 : Installer les dépendances nécessaires
npm install pg sequelize sequelize-cli --save
npx sequelize-cli init
Étape 3 : Configurer la base de données
Modifier src/config/ormconfig.json :
{
"type": "postgres",
"host": "postgres",
"port": 5432,
"username": "myuser",
"password": "mypassword",
"database": "mydatabase",
"synchronize": true,
"logging": false
}
Étape 4 : Créer le modèle de données
Créer un fichier task.entity.ts dans src/task/ :
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class Task {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column({ default: false })
completed: boolean;
}
Étape 5 : Créer le service et le contrôleur
Créer un fichier task.service.ts dans src/task/ :
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Task } from './task.entity';
@Injectable()
export class TaskService {
constructor(
@InjectRepository(Task)
private readonly taskRepository: Repository<Task>,
) {}
findAll(): Promise<Task[]> {
return this.taskRepository.find();
}
findOne(id: number): Promise<Task> {
return this.taskRepository.findOne(id);
}
async remove(id: number): Promise<void> {
await this.taskRepository.delete(id);
}
}
Créer un fichier task.controller.ts dans src/task/ :
import { Controller, Get, Post, Body, Param, Delete } from '@nestjs/common';
import { TaskService } from './task.service';
import { Task } from './task.entity';
@Controller('tasks')
export class TaskController {
constructor(private readonly taskService: TaskService) {}
@Get()
findAll(): Promise<Task[]> {
return this.taskService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): Promise<Task> {
return this.taskService.findOne(+id);
}
@Delete(':id')
remove(@Param('id') id: string): Promise<void> {
return this.taskService.remove(+id);
}
}
Étape 6 : Mettre à jour app.module.ts
Ajouter les modules nécessaires :
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TaskController } from './task/task.controller';
import { TaskService } from './task/task.service';
import { TaskEntity } from './task/task.entity';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'postgres',
port: 5432,
username: 'myuser',
password: 'mypassword',
database: 'mydatabase',
entities: [TaskEntity],
synchronize: true,
}),
TypeOrmModule.forFeature([TaskEntity]),
],
controllers: [TaskController],
providers: [TaskService],
})
export class AppModule {}
Étape 7 : Lancer les conteneurs avec Docker Compose
docker-compose up --build
Erreurs Frequentes et Debugging
1. Erreur de connexion à la base de données
code_incorrect = await this.taskRepository.findOne(+id);
code_correct = await this.taskRepository.findOne(id);
2. Problème avec les volumes PostgreSQL
Il peut y avoir des problèmes liés aux permissions sur le volume PostgreSQL. Assurez-vous que le fichier docker-compose.yml est correctement configuré et que les permissions sont définies.
sudo chown -R $USER:$USER /path/to/your/docker/volumes/postgres_data
3. Problème avec la synchronisation des tables
Si vous rencontrez des problèmes de synchronisation des tables, assurez-vous que synchronize: true est activé dans ormconfig.json.
Pour Aller Plus Loi
- Amélioration de la sécurité : Utilisez des variables d'environnement pour stocker les informations sensibles comme les mots de passe et configurez l'authentification SSL avec PostgreSQL.
- Monitoring et logging : Ajoutez des outils de monitoring et de logging pour suivre les performances de votre application et les erreurs.
- Scalabilité : Configurez Docker Swarm ou Kubernetes pour déployer votre application sur plusieurs instances.
Défi Pratique
Créez une application NestJS qui permet de gérer des utilisateurs avec des routes pour créer, lire, mettre à jour et supprimer des utilisateurs. Utilisez PostgreSQL pour stocker les données des utilisateurs. Assurez-vous d'avoir correctement configuré Docker Compose pour exécuter l'application et la base de données.
Ce tutoriel a été écrit avec une approche détaillée pour aider les développeurs à comprendre comment utiliser Docker Compose pour développer une application NestJS avec PostgreSQL.