🔝 Retour au Sommaire
Un conteneur est une unité légère et portable qui regroupe une application et toutes ses dépendances (bibliothèques, configuration, binaires) dans un package isolé du système hôte.
Analogie simple :
Imaginez que vous déménagez :
- Bare Metal : Vous emportez tous vos meubles en vrac, vous devez tout remonter dans le nouveau logement
- VM : Vous emportez votre appartement entier (murs, électricité, plomberie) pour le reconstruire ailleurs
- Conteneur : Vous mettez tout dans des cartons standardisés qui s'adaptent à n'importe quel logement. Vous ouvrez le carton et c'est prêt !
| Terme | Définition | Exemple |
|---|---|---|
| Conteneur | Instance en cours d'exécution d'une image | PostgreSQL tournant dans un conteneur |
| Image | Template immuable contenant l'application | postgres:18 |
| Dockerfile | Recette pour construire une image | Instructions pour créer image PostgreSQL personnalisée |
| Registry | Dépôt d'images | Docker Hub, Quay.io |
| Volume | Stockage persistant pour conteneurs | Données PostgreSQL PGDATA |
| Network | Réseau virtuel pour connecter conteneurs | Bridge, host, overlay |
| Orchestrateur | Gère déploiement à grande échelle | Kubernetes, Docker Swarm |
┌────────────────────────────────────────────────────────────┐
│ VIRTUAL MACHINES │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │App + Libs│ │App + Libs│ │App + Libs│ │
│ │Guest OS │ │Guest OS │ │Guest OS │ ← OS complet │
│ │(2-4 GB) │ │(2-4 GB) │ │(2-4 GB) │ dans chaque │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ├────────────── Hyperviseur ──────────────┤ │
│ │ Host OS + Hardware │ │
│ └─────────────────────────────────────────┘ │
│ Overhead : 5-10% | Démarrage : 30-60s │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ CONTENEURS │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │App+L│ │App+L│ │App+L│ │App+L│ │App+L│ ← Seulement │
│ │50 MB│ │50 MB│ │50 MB│ │50 MB│ │50 MB│ app+libs │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ ├───────── Runtime Conteneur (Docker/Podman) ─────┤ │
│ │ Host OS + Kernel Linux │ │
│ │ Hardware │ │
│ └─────────────────────────────────────────────────┘ │
│ Overhead : 2-5% | Démarrage : <5s │
└────────────────────────────────────────────────────────────┘
Différences clés :
| Caractéristique | VM | Conteneur |
|---|---|---|
| Isolation | Forte (OS complet) | Moyenne (partage kernel) |
| Taille | 2-20 GB | 50-500 MB |
| Démarrage | 30-60 secondes | 1-5 secondes |
| Overhead | 5-10% | 2-5% |
| Densité | 10-20 par hôte | 50-1000+ par hôte |
| Portabilité | Moyenne | Excellente |
| Sécurité | Très forte | Bonne (dépend config) |
Les conteneurs utilisent des fonctionnalités du kernel Linux :
Conteneur PostgreSQL
├─ Namespaces : Isolation (PID, network, mount, IPC, UTS)
│ └─ Le conteneur "pense" être seul sur la machine
├─ Cgroups : Limitation ressources (CPU, RAM, I/O)
│ └─ "Tu peux utiliser max 2 CPU et 4 GB RAM"
├─ Union Filesystem : Système de fichiers en couches
│ └─ Layers empilées (base OS → PostgreSQL → config)
└─ Capabilities : Permissions granulaires
└─ Moins de privilèges que root complet
Exemple concret :
# Lancer PostgreSQL en conteneur
docker run -d \
--name postgres18 \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
postgres:18
# En quelques secondes :
# ✅ PostgreSQL 18 démarre
# ✅ Isolé du système hôte
# ✅ Données persistantes dans volume
# ✅ Portable : même commande sur n'importe quel OSPrésentation :
- Créé en 2013, leader du marché
- Architecture client-serveur (daemon)
- Écosystème mature et riche
- Docker Hub : registre officiel avec millions d'images
Architecture Docker :
┌─────────────────────────────────────┐
│ Utilisateur │
└───────────┬─────────────────────────┘
│ docker run postgres:18
↓
┌─────────────────────────────────────┐
│ Docker Client (CLI) │
└───────────┬─────────────────────────┘
│ API REST
↓
┌─────────────────────────────────────┐
│ Docker Daemon (dockerd) │
│ - Gestion conteneurs │
│ - Gestion images │
│ - Gestion réseau │
│ - Gestion volumes │
└───────────┬─────────────────────────┘
│
↓
┌─────────────────────────────────────┐
│ containerd + runc │
│ (runtime bas-niveau) │
└───────────┬─────────────────────────┘
│
↓
[Conteneurs]
Avantages Docker :
- ✅ Documentation très complète
- ✅ Énorme communauté (Stack Overflow, forums)
- ✅ Écosystème riche (Docker Compose, Swarm, Desktop)
- ✅ Support commercial (Docker Inc.)
- ✅ Compatible Windows et macOS (Docker Desktop)
- ✅ Intégration CI/CD mature
Inconvénients Docker :
- ❌ Nécessite daemon root (problème sécurité)
- ❌ Architecture centralisée (SPOF)
- ❌ Licence restrictive pour entreprises (Docker Desktop payant)
- ❌ Complexité pour environnements multi-utilisateurs
Cas d'usage Docker pour PostgreSQL :
- Développement local (avec Docker Desktop)
- CI/CD (tests d'intégration)
- Petites infrastructures (<50 conteneurs)
- Équipes habituées à Docker
- Environnement Windows/macOS
Présentation :
- Créé par Red Hat en 2018
- Alternative open source à Docker
- Architecture daemonless (sans daemon)
- Compatible API Docker (drop-in replacement)
- Intégré à RHEL, Fedora, CentOS Stream
Architecture Podman :
┌─────────────────────────────────────┐
│ Utilisateur │
└───────────┬─────────────────────────┘
│ podman run postgres:18
↓
┌─────────────────────────────────────┐
│ Podman CLI │
│ (Processus utilisateur direct) │
└───────────┬─────────────────────────┘
│ Fork direct
↓
┌─────────────────────────────────────┐
│ conmon + runc │
│ (runtime conteneur) │
└───────────┬─────────────────────────┘
│
↓
[Conteneurs]
Pas de daemon central ! Plus sécurisé.
Avantages Podman :
- ✅ Sans daemon : Pas de processus root permanent
- ✅ Rootless : Conteneurs sans privilèges root
- ✅ Sécurité : Isolation utilisateur native
- ✅ Pods : Support natif groupes de conteneurs (comme Kubernetes)
- ✅ Systemd : Intégration native services systemd
- ✅ Licence : 100% open source Apache 2.0
- ✅ Compatible Docker :
alias docker=podmanfonctionne
Inconvénients Podman :
- ❌ Communauté plus petite que Docker
- ❌ Documentation moins abondante
- ❌ Quelques incompatibilités mineures avec Docker
- ❌ Pas de Docker Desktop équivalent (Podman Desktop en beta)
- ❌ Moins mature pour Windows/macOS
Cas d'usage Podman pour PostgreSQL :
- ✅ Production Linux (meilleure sécurité)
- ✅ Environnements multi-utilisateurs
- ✅ Infrastructure Red Hat / Fedora
- ✅ Migration vers Kubernetes facilitée
- ✅ Conformité sécurité stricte
| Critère | Docker | Podman | Recommandation |
|---|---|---|---|
| Sécurité | ⭐⭐⭐ (daemon root) | ⭐⭐⭐⭐⭐ (rootless) | Podman |
| Maturité | ⭐⭐⭐⭐⭐ (10 ans) | ⭐⭐⭐⭐ (5 ans) | Docker |
| Communauté | ⭐⭐⭐⭐⭐ Énorme | ⭐⭐⭐⭐ Grande | Docker |
| Performance | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ (pas daemon) | Podman |
| Compatibilité | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ (99% Docker) | Docker |
| Production | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | Podman |
| Développement | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Docker |
| Windows/Mac | ⭐⭐⭐⭐⭐ | ⭐⭐ | Docker |
Notre recommandation :
Si développement (Windows/macOS) :
└─ Docker Desktop
Si production Linux :
└─ Podman (sécurité supérieure)
Si équipe déjà sur Docker :
└─ Rester sur Docker (sauf besoin sécurité critique)
Si infrastructure Red Hat :
└─ Podman (natif)
Note : Le reste du document utilise principalement Docker pour les exemples, mais les commandes Podman sont quasi-identiques (docker → podman).
Docker Hub : postgres
Registre : hub.docker.com/_/postgres
Versions disponibles :
├─ postgres:18 → Dernière 18.x
├─ postgres:18.1 → Version spécifique
├─ postgres:18-alpine → Version légère Alpine Linux
├─ postgres:17 → Précédente version
├─ postgres:latest → ⚠️ Déconseillé production
└─ postgis/postgis:18 → PostgreSQL + PostGIS
Tags recommandés :
✅ postgres:18.1 # Version spécifique (recommandé production)
✅ postgres:18 # Dernière 18.x (dev/staging)
⚠️ postgres:18-alpine # Léger mais différences comportement
❌ postgres:latest # Version changeante (jamais en production !)Pourquoi éviter :latest ?
Aujourd'hui :
postgres:latest → 18.1
Demain (après release PG 19) :
postgres:latest → 19.0
Votre conteneur redémarre → Upgrade surprise → Incompatibilités
Règle d'or : Toujours spécifier version exacte en production.
Couches (layers) de l'image :
Image postgres:18 (~370 MB)
├─ Layer 1 : Debian bookworm base (~80 MB)
├─ Layer 2 : Dépendances système (~50 MB)
├─ Layer 3 : PostgreSQL 18 binaires (~200 MB)
├─ Layer 4 : Scripts d'initialisation (~5 MB)
├─ Layer 5 : Configuration par défaut (~1 MB)
└─ Layer 6 : Entrypoint et CMD (~1 KB)
Avantages couches :
✅ Réutilisation (cache layers partagés)
✅ Mises à jour efficaces (seules layers modifiées)
✅ Stockage optimisé (déduplication)
Fichier Dockerfile de l'image officielle (simplifié) :
FROM debian:bookworm-slim
# Variables d'environnement
ENV POSTGRES_VERSION 18
ENV PGDATA /var/lib/postgresql/data
# Installation PostgreSQL
RUN apt-get update && apt-get install -y \
postgresql-18 \
postgresql-contrib-18 \
&& rm -rf /var/lib/apt/lists/*
# Volume pour données
VOLUME /var/lib/postgresql/data
# Exposition port
EXPOSE 5432
# Point d'entrée
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["postgres"] docker run -d \
--name postgres18-demo \
-e POSTGRES_PASSWORD=MySecretPassword \
-p 5432:5432 \
postgres:18Décortiquons cette commande :
docker run # Créer et lancer conteneur
-d # Detached (arrière-plan)
--name postgres18-demo # Nom du conteneur
-e POSTGRES_PASSWORD=MySecretPassword # Variable d'environnement
-p 5432:5432 # Mapping port hôte:conteneur
postgres:18 # Image à utiliserQue se passe-t-il ?
- Docker télécharge l'image
postgres:18(si pas déjà en cache) - Crée un conteneur nommé
postgres18-demo - Configure mot de passe superuser
postgres - Expose port 5432 (accessible depuis hôte)
- Démarre PostgreSQL
Vérification :
# Lister conteneurs en cours
docker ps
# Logs
docker logs postgres18-demo
# Connexion au conteneur
docker exec -it postgres18-demo psql -U postgresdocker run -d \
--name postgres18-prod \
# ===== CONFIGURATION DE BASE =====
-e POSTGRES_PASSWORD=SecretPass123 # ✅ Obligatoire
-e POSTGRES_USER=myapp # Utilisateur custom (défaut: postgres)
-e POSTGRES_DB=myappdb # Base créée au démarrage
# ===== INITIALISATION =====
-e POSTGRES_INITDB_ARGS="--data-checksums --encoding=UTF8 --locale=fr_FR.UTF-8"
# Options initdb (checksums activés par défaut PG18)
-e POSTGRES_HOST_AUTH_METHOD=scram-sha-256 # Méthode auth (défaut: scram)
# ⚠️ Ne JAMAIS utiliser 'trust' en production !
# ===== TUNING =====
-e POSTGRES_SHARED_BUFFERS=2GB # Équivalent shared_buffers
-e POSTGRES_WORK_MEM=64MB # Équivalent work_mem
# ===== CHEMINS =====
-e PGDATA=/var/lib/postgresql/data/pgdata # Sous-répertoire PGDATA
postgres:18Variables communes :
| Variable | Description | Défaut | Exemple |
|---|---|---|---|
POSTGRES_PASSWORD |
Mot de passe superuser | (obligatoire) | MySecret123 |
POSTGRES_USER |
Nom superuser | postgres |
admin |
POSTGRES_DB |
Base initiale | = POSTGRES_USER |
production |
PGDATA |
Répertoire données | /var/lib/postgresql/data |
/pgdata |
POSTGRES_INITDB_ARGS |
Arguments initdb | --auth-host=scram-sha-256 |
--data-checksums |
POSTGRES_INITDB_WALDIR |
Répertoire WAL séparé | (dans PGDATA) | /pg_wal |
# Lancer conteneur sans volume
docker run -d --name pg-temp -e POSTGRES_PASSWORD=pass postgres:18
# Créer une table
docker exec -it pg-temp psql -U postgres -c "CREATE TABLE users (id INT);"
# Arrêter et supprimer conteneur
docker stop pg-temp
docker rm pg-temp
# Relancer conteneur
docker run -d --name pg-temp -e POSTGRES_PASSWORD=pass postgres:18
# La table n'existe plus ! Données perdues 😱Pourquoi ? Les données étaient stockées dans le conteneur, pas sur l'hôte.
3 types de montage :
# Créer volume
docker volume create pgdata-prod
# Lancer conteneur avec volume
docker run -d \
--name postgres18-prod \
-e POSTGRES_PASSWORD=secret \
-v pgdata-prod:/var/lib/postgresql/data \
postgres:18
# Avantages :
# ✅ Géré par Docker (backup, migration faciles)
# ✅ Performance optimale
# ✅ Indépendant du système de fichiers hôte
# ✅ Survit à la suppression du conteneurInspection :
# Lister volumes
docker volume ls
# Inspecter volume
docker volume inspect pgdata-prod
# {
# "Mountpoint": "/var/lib/docker/volumes/pgdata-prod/_data",
# ...
# }
# Emplacement physique (nécessite root)
sudo ls -la /var/lib/docker/volumes/pgdata-prod/_data# Créer répertoire local
mkdir -p ~/postgres-data
# Lancer avec bind mount
docker run -d \
--name postgres18-dev \
-e POSTGRES_PASSWORD=secret \
-v ~/postgres-data:/var/lib/postgresql/data \
postgres:18
# Avantages :
# ✅ Accès direct fichiers depuis hôte
# ✅ Facile pour déboguer
# ✅ Édition configuration à chaud
# Inconvénients :
# ❌ Permissions complexes (problème UID/GID)
# ❌ Performance variable selon filesystem hôte
# ❌ Moins portableProblème de permissions typique :
# L'utilisateur postgres dans conteneur a UID 999
# Vos fichiers locaux appartiennent à UID 1000 (vous)
# → Erreur permission denied
# Solution :
sudo chown -R 999:999 ~/postgres-data# Volume en mémoire RAM (non persistant)
docker run -d \
--name postgres18-test \
-e POSTGRES_PASSWORD=secret \
--tmpfs /var/lib/postgresql/data:rw,size=1g \
postgres:18
# Avantages :
# ✅ Très rapide (RAM)
# ✅ Sécurité (données effacées à l'arrêt)
# Inconvénients :
# ❌ Aucune persistance
# ❌ Limité par RAM
# ❌ Usage : Tests uniquement# Créer volumes séparés
docker volume create pgdata-prod # Données principales
docker volume create pg-wal-prod # WAL séparé
docker volume create pg-backups-prod # Sauvegardes
docker run -d \
--name postgres18-prod \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_INITDB_WALDIR=/pg_wal \
-v pgdata-prod:/var/lib/postgresql/data \
-v pg-wal-prod:/pg_wal \
-v pg-backups-prod:/backups \
postgres:18
# Architecture :
# Conteneur
# ├─ /var/lib/postgresql/data → Volume pgdata-prod (données)
# ├─ /pg_wal → Volume pg-wal-prod (WAL isolé)
# └─ /backups → Volume pg-backups-prod (sauvegardes)Avantages :
- Optimisation I/O (WAL séparé réduit contention)
- Gestion sauvegardes simplifiée
- Snapshots sélectifs possibles
docker run -d \
--name postgres18 \
-p 5432:5432 \
postgres:18
# Fonctionnement :
# Conteneur → Bridge docker0 → Interface hôte → Réseau externe
# IP conteneur : 172.17.0.x (réseau privé Docker)
# Accessible depuis hôte : localhost:5432Caractéristiques :
- ✅ Isolation réseau
- ✅ Port mapping flexible
- ❌ NAT = légère latence (+0.5-1ms)
- ✅ Usage : Développement, petite infra
docker run -d \
--name postgres18 \
--network host \
postgres:18
# Fonctionnement :
# Conteneur partage stack réseau de l'hôte
# Pas d'isolation réseau
# Écoute directement sur 5432 de l'hôteCaractéristiques :
- ✅ Performance maximale (pas de NAT)
- ✅ Latence minimale
- ❌ Perte isolation
- ❌ Conflits de ports possibles
⚠️ Usage : Production haute performance (avec précautions)
# Créer réseau custom
docker network create pg-network
# Lancer PostgreSQL
docker run -d \
--name postgres18 \
--network pg-network \
-e POSTGRES_PASSWORD=secret \
postgres:18
# Lancer application
docker run -d \
--name myapp \
--network pg-network \
-e DATABASE_URL=postgresql://postgres:secret@postgres18:5432/postgres \
myapp:latest
# Communication :
# myapp → DNS "postgres18" → PostgreSQL
# Pas besoin port mapping (réseau isolé)Avantages :
- ✅ DNS automatique entre conteneurs
- ✅ Isolation réseau par projet
- ✅ Pas de publication ports externe nécessaire
- ✅ Sécurité accrue
# Différentes syntaxes port mapping
# Port unique
-p 5432:5432 # hôte:conteneur
# Port hôte différent
-p 5433:5432 # PostgreSQL sur port 5433 de l'hôte
# IP spécifique
-p 10.0.1.50:5432:5432 # Écoute uniquement sur IP spécifique
# Port aléatoire hôte
-p 5432 # Docker choisit port hôte libre
# Tous les ports exposés
-P # Mappe tous EXPOSE du DockerfileSécurité :
# ❌ Dangereux : Exposition publique
docker run -p 0.0.0.0:5432:5432 postgres:18
# ✅ Mieux : Localhost uniquement
docker run -p 127.0.0.1:5432:5432 postgres:18
# ✅ Optimal : Réseau custom sans exposition
docker run --network pg-network postgres:18docker run -d \
--name postgres18 \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_SHARED_BUFFERS=2GB \
-e POSTGRES_WORK_MEM=64MB \
-e POSTGRES_MAX_CONNECTIONS=200 \
postgres:18
# Limitations :
# ⚠️ Paramètres limités
# ⚠️ Pas toutes les options disponiblesdocker run -d \
--name postgres18 \
-e POSTGRES_PASSWORD=secret \
postgres:18 \
postgres \
-c shared_buffers=2GB \
-c work_mem=64MB \
-c max_connections=200 \
-c log_statement=all \
-c log_min_duration_statement=1000
# Avantages :
# ✅ Tous paramètres disponibles
# ✅ Visible dans docker ps
# ✅ Facile à modifier (recréer conteneur)Création fichier custom :
# custom-postgresql.conf
listen_addresses = '*'
max_connections = 200
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 64MB
maintenance_work_mem = 1GB
wal_level = replica
max_wal_size = 4GB
checkpoint_completion_target = 0.9
# PostgreSQL 18 spécifique
io_method = 'worker'
io_async_workers = 8
wal_compression = zstd Montage dans conteneur :
docker run -d \
--name postgres18-prod \
-e POSTGRES_PASSWORD=secret \
-v $(pwd)/custom-postgresql.conf:/etc/postgresql/postgresql.conf \
-v pgdata:/var/lib/postgresql/data \
postgres:18 \
postgres -c config_file=/etc/postgresql/postgresql.confFROM postgres:18
# Copier configuration custom
COPY custom-postgresql.conf /etc/postgresql/postgresql.conf
COPY custom-pg_hba.conf /etc/postgresql/pg_hba.conf
# Scripts d'initialisation
COPY init-scripts/*.sql /docker-entrypoint-initdb.d/
# Variables par défaut
ENV POSTGRES_PASSWORD=changeme \
POSTGRES_DB=production
# Commande personnalisée
CMD ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]Build et run :
# Construire image
docker build -t mycompany/postgres18:1.0 .
# Lancer
docker run -d \
--name postgres18-custom \
-v pgdata:/var/lib/postgresql/data \
mycompany/postgres18:1.0Fichier custom pg_hba.conf :
# custom-pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
# Connexions locales (dans conteneur)
local all all scram-sha-256
# Depuis réseau Docker (172.17.0.0/16)
host all all 172.17.0.0/16 scram-sha-256
# Depuis réseau custom spécifique
host all all 10.0.1.0/24 scram-sha-256
# Réplication
host replication replicator 10.0.1.0/24 scram-sha-256
Montage :
docker run -d \
--name postgres18 \
-v $(pwd)/custom-pg_hba.conf:/var/lib/postgresql/data/pg_hba.conf \
-v pgdata:/var/lib/postgresql/data \
postgres:18Docker Compose permet de définir et gérer des applications multi-conteneurs via un fichier YAML.
Avantages :
- ✅ Configuration déclarative (Infrastructure as Code)
- ✅ Gestion multi-conteneurs simplifiée
- ✅ Réseau et volumes automatiques
- ✅ Reproductibilité
- ✅ Versioning (Git)
docker-compose.yml :
version: '3.8'
services:
postgres:
image: postgres:18
container_name: postgres18
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme}
POSTGRES_USER: postgres
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pgdata:
driver: localUtilisation :
# Démarrer
docker-compose up -d
# Logs
docker-compose logs -f postgres
# Arrêter
docker-compose down
# Arrêter + supprimer volumes
docker-compose down -vversion: '3.8'
services:
# ===== PostgreSQL =====
postgres:
image: postgres:18
container_name: postgres18
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-SecretPass123}
POSTGRES_DB: production
POSTGRES_INITDB_ARGS: "--data-checksums"
volumes:
- pgdata:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d # Scripts init
- ./postgresql.conf:/etc/postgresql/postgresql.conf
command: postgres -c config_file=/etc/postgresql/postgresql.conf
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
cpus: '4'
memory: 8G
reservations:
cpus: '2'
memory: 4G
# ===== Application =====
app:
image: myapp:latest
container_name: myapp
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-SecretPass123}@postgres:5432/production
networks:
- backend
- frontend
ports:
- "8080:8080"
# ===== pgAdmin (Administration) =====
pgadmin:
image: dpage/pgadmin4:latest
container_name: pgadmin
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: admin@example.com
PGADMIN_DEFAULT_PASSWORD: admin
PGADMIN_CONFIG_SERVER_MODE: 'False'
volumes:
- pgadmin-data:/var/lib/pgadmin
networks:
- backend
- frontend
ports:
- "5050:80"
depends_on:
- postgres
networks:
backend:
driver: bridge
frontend:
driver: bridge
volumes:
pgdata:
driver: local
pgadmin-data:
driver: localFonctionnalités avancées :
# Healthcheck : Attendre PostgreSQL prêt
depends_on:
postgres:
condition: service_healthy
# Limites ressources
deploy:
resources:
limits:
cpus: '4'
memory: 8G
# Variables d'environnement depuis fichier
env_file:
- .env
# Redémarrage automatique
restart: unless-stoppedStructure :
project/
├── docker-compose.yml
├── init-scripts/
│ ├── 01-schema.sql # Ordre alphabétique
│ ├── 02-data.sql
│ └── 03-functions.sql
└── postgresql.conf
01-schema.sql :
-- Scripts exécutés au premier démarrage uniquement
CREATE SCHEMA IF NOT EXISTS app;
CREATE TABLE app.users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_users_email ON app.users(email);02-data.sql :
INSERT INTO app.users (username, email) VALUES
('admin', 'admin@example.com'),
('user1', 'user1@example.com');# Limiter à 2 CPU
docker run -d \
--name postgres18 \
--cpus="2" \
-e POSTGRES_PASSWORD=secret \
postgres:18
# Limiter à 50% d'un CPU
docker run -d \
--name postgres18 \
--cpus="0.5" \
postgres:18
# CPU shares (poids relatif)
docker run -d \
--name postgres18 \
--cpu-shares=1024 \
postgres:18Comportement :
--cpus="2": Maximum 2 cœurs utilisés- Si charge < 2 CPU : utilisation normale
- Si charge > 2 CPU : limitation (throttling)
# Limiter à 4 GB RAM
docker run -d \
--name postgres18 \
--memory="4g" \
-e POSTGRES_PASSWORD=secret \
postgres:18
# RAM + Swap total
docker run -d \
--memory="4g" \
--memory-swap="6g" \ # 4 GB RAM + 2 GB swap
postgres:18
# Réservation mémoire minimale
docker run -d \
--memory="4g" \
--memory-reservation="2g" \ # Soft limit
postgres:18# Désactiver swap (recommandé)
docker run -d \
--memory="4g" \
--memory-swap="4g" \ # Égal à memory = pas de swap
postgres:18
# Ou via postgresql.conf
-c shared_buffers=1GB # Adapter à la RAM allouée# Limiter I/O disque (IOPS)
docker run -d \
--name postgres18 \
--device-read-iops /dev/sda:1000 \
--device-write-iops /dev/sda:1000 \
postgres:18
# Limiter bande passante (MB/s)
docker run -d \
--device-read-bps /dev/sda:100mb \
--device-write-bps /dev/sda:100mb \
postgres:18Cas d'usage :
- Environnements multi-tenants
- Éviter qu'un conteneur sature I/O
- Tests de performance avec contraintes
services:
postgres:
image: postgres:18
deploy:
resources:
limits:
cpus: '4'
memory: 8G
reservations: # Garanties minimales
cpus: '2'
memory: 4G
volumes:
- pgdata:/var/lib/postgresql/dataProblème :
Par défaut, les processus dans conteneurs s'exécutent souvent en root, ce qui est un risque si le conteneur est compromis.
Solution : Utilisateur non-root
# Dockerfile custom
FROM postgres:18
# L'image officielle utilise déjà user postgres (UID 999)
# Vérification
USER postgresAvec Podman (Rootless) :
# Podman permet conteneurs complètement sans root
podman run -d \
--name postgres18 \
-e POSTGRES_PASSWORD=secret \
postgres:18
# Processus tournent sous votre UID utilisateur
# Sécurité maximale❌ Mauvaise pratique : Mot de passe en clair
docker run -e POSTGRES_PASSWORD=SuperSecret123 postgres:18
# Visible dans docker inspect, logs, historique✅ Bonne pratique : Docker Secrets (Swarm)
# Créer secret
echo "SuperSecret123" | docker secret create postgres_password -
# Utiliser dans service
docker service create \
--name postgres18 \
--secret postgres_password \
-e POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password \
postgres:18✅ Alternative : Fichier .env
# .env (ne pas commiter !)
POSTGRES_PASSWORD=SuperSecret123
# docker-compose.yml
services:
postgres:
env_file: .env
# .gitignore
.env✅ Avec gestionnaire secrets (Vault, AWS Secrets Manager)
services:
postgres:
environment:
POSTGRES_PASSWORD: ${VAULT_POSTGRES_PASSWORD}# docker-compose.yml
services:
postgres:
networks:
- backend # Réseau privé
# Pas de ports: exposés publiquement
app:
networks:
- backend # Accède PostgreSQL
- frontend # Accessible publiquement
ports:
- "443:443"
networks:
backend:
internal: true # Pas d'accès Internet
frontend:docker run -d \
--name postgres18 \
--cap-drop ALL \ # Retire toutes capabilities
--cap-add CHOWN \ # Ajoute seulement nécessaires
--cap-add DAC_OVERRIDE \
--cap-add SETGID \
--cap-add SETUID \
postgres:18docker run -d \
--name postgres18 \
--read-only \ # Filesystem root en lecture seule
--tmpfs /tmp:rw,noexec,nosuid,size=100m \ # tmpfs pour /tmp
--tmpfs /run:rw,noexec,nosuid,size=100m \
-v pgdata:/var/lib/postgresql/data:rw \ # Volume RW pour données
postgres:18Avantages :
- Protection contre modifications filesystem malveillantes
- Conteneur immuable
- Conformité sécurité renforcée
# Avec Trivy (scanner open source)
trivy image postgres:18
# Avec Snyk
snyk container test postgres:18
# Avec Docker Scout
docker scout cves postgres:18Exemple résultat :
postgres:18 (debian bookworm)
├─ CRITICAL: 0
├─ HIGH: 2
├─ MEDIUM: 15
└─ LOW: 48
Recommandation : Mettre à jour vers postgres:18.1
AppArmor (Ubuntu/Debian) :
# Profil AppArmor custom pour PostgreSQL
docker run -d \
--security-opt apparmor=docker-postgresql \
postgres:18SELinux (RHEL/Fedora) :
# Avec contexte SELinux
docker run -d \
--security-opt label=type:container_runtime_t \
postgres:18# docker-compose.yml sécurisé
services:
postgres:
image: postgres:18.1 # Version spécifique
user: postgres # Non-root
read_only: true # Filesystem RO
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- SETGID
- SETUID
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp
- /run
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- backend # Réseau privé
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
deploy:
resources:
limits:
memory: 4G
secrets:
db_password:
external: true
networks:
backend:
internal: true# Simple mais pas de HA
services:
postgres:
image: postgres:18
volumes:
- pgdata:/var/lib/postgresql/dataLimitations :
- ❌ SPOF (Single Point of Failure)
- ❌ Pas de tolérance panne
- ❌ Downtime pendant mises à jour
Architecture :
┌──────────────────┐ Streaming ┌──────────────────┐
│ Primary │ Replication │ Standby │
│ (Read/Write) │ ════════════> │ (Read-Only) │
│ Container 1 │ │ Container 2 │
└──────────────────┘ └──────────────────┘
│ │
└─────────── Shared Volume (WAL) ─────┘
docker-compose.yml (réplication manuelle) :
version: '3.8'
services:
postgres-primary:
image: postgres:18
container_name: postgres-primary
environment:
POSTGRES_PASSWORD: secret
POSTGRES_USER: postgres
POSTGRES_DB: production
# Configuration réplication
POSTGRES_INITDB_ARGS: "-c wal_level=replica -c max_wal_senders=5"
volumes:
- pgdata-primary:/var/lib/postgresql/data
- ./setup-replication.sh:/docker-entrypoint-initdb.d/setup-replication.sh
command: |
postgres
-c wal_level=replica
-c max_wal_senders=5
-c max_replication_slots=5
-c hot_standby=on
networks:
- pg-network
postgres-standby:
image: postgres:18
container_name: postgres-standby
environment:
POSTGRES_PASSWORD: secret
PGDATA: /var/lib/postgresql/data
volumes:
- pgdata-standby:/var/lib/postgresql/data
command: |
bash -c "
if [ ! -f /var/lib/postgresql/data/PG_VERSION ]; then
pg_basebackup -h postgres-primary -D /var/lib/postgresql/data -U replication -Fp -Xs -R
fi
postgres
"
depends_on:
- postgres-primary
networks:
- pg-network
networks:
pg-network:
volumes:
pgdata-primary:
pgdata-standby:Configuration manuelle réplication (complexe) :
# Sur primary : Créer utilisateur réplication
docker exec -it postgres-primary psql -U postgres -c \
"CREATE USER replication WITH REPLICATION PASSWORD 'repl_pass';"
# Configurer pg_hba.conf primary
docker exec -it postgres-primary bash -c \
"echo 'host replication replication 0.0.0.0/0 scram-sha-256' >> /var/lib/postgresql/data/pg_hba.conf"
# Reload
docker exec -it postgres-primary psql -U postgres -c "SELECT pg_reload_conf();"
# Sur standby : pg_basebackup
docker exec -it postgres-standby bash -c \
"pg_basebackup -h postgres-primary -D /var/lib/postgresql/data -U replication -Fp -Xs -R"Patroni = Solution HA automatisée pour PostgreSQL avec :
- Auto-failover
- Détection panne automatique
- Promotion standby automatique
- Consensus distribué (etcd, Consul, ZooKeeper)
Architecture Patroni :
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Patroni 1 │ │ Patroni 2 │ │ Patroni 3 │
│ + PG (P) │ │ + PG (S) │ │ + PG (S) │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────┼────────────────┘
│
┌──────▼──────┐
│ etcd │ ← Consensus
│ (Cluster) │
└─────────────┘
│
┌──────▼──────┐
│ HAProxy │ ← Load Balancer
└─────────────┘
docker-compose.yml avec Patroni :
version: '3.8'
services:
# ===== ETCD (Consensus) =====
etcd:
image: quay.io/coreos/etcd:v3.5
environment:
ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379
ETCD_ADVERTISE_CLIENT_URLS: http://etcd:2379
networks:
- pg-ha
# ===== Patroni Node 1 (Initial Primary) =====
patroni1:
image: patroni/patroni:latest
hostname: patroni1
environment:
PATRONI_NAME: patroni1
PATRONI_SCOPE: pg-cluster
PATRONI_ETCD3_HOSTS: "'etcd:2379'"
PATRONI_RESTAPI_CONNECT_ADDRESS: patroni1:8008
PATRONI_POSTGRESQL_CONNECT_ADDRESS: patroni1:5432
PATRONI_POSTGRESQL_DATA_DIR: /var/lib/postgresql/data
PATRONI_POSTGRESQL_PGPASS: /tmp/pgpass
PATRONI_SUPERUSER_USERNAME: postgres
PATRONI_SUPERUSER_PASSWORD: postgres
PATRONI_REPLICATION_USERNAME: replicator
PATRONI_REPLICATION_PASSWORD: replicator
volumes:
- pgdata1:/var/lib/postgresql/data
networks:
- pg-ha
depends_on:
- etcd
# ===== Patroni Node 2 (Standby) =====
patroni2:
image: patroni/patroni:latest
hostname: patroni2
environment:
PATRONI_NAME: patroni2
PATRONI_SCOPE: pg-cluster
PATRONI_ETCD3_HOSTS: "'etcd:2379'"
PATRONI_RESTAPI_CONNECT_ADDRESS: patroni2:8008
PATRONI_POSTGRESQL_CONNECT_ADDRESS: patroni2:5432
PATRONI_POSTGRESQL_DATA_DIR: /var/lib/postgresql/data
PATRONI_SUPERUSER_USERNAME: postgres
PATRONI_SUPERUSER_PASSWORD: postgres
PATRONI_REPLICATION_USERNAME: replicator
PATRONI_REPLICATION_PASSWORD: replicator
volumes:
- pgdata2:/var/lib/postgresql/data
networks:
- pg-ha
depends_on:
- etcd
# ===== HAProxy (Load Balancer) =====
haproxy:
image: haproxy:latest
ports:
- "5432:5432" # Primary
- "5433:5433" # Standbys (read-only)
- "7000:7000" # Stats
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
networks:
- pg-ha
depends_on:
- patroni1
- patroni2
networks:
pg-ha:
volumes:
pgdata1:
pgdata2:haproxy.cfg :
global
maxconn 100
defaults
mode tcp
timeout connect 5s
timeout client 30s
timeout server 30s
# Primary (Read/Write)
listen primary
bind *:5432
option httpchk
http-check expect status 200
default-server inter 3s fall 3 rise 2
server patroni1 patroni1:5432 check port 8008
server patroni2 patroni2:5432 check port 8008 backup
# Standbys (Read-Only)
listen standbys
bind *:5433
balance roundrobin
option httpchk
http-check expect status 200
default-server inter 3s fall 3 rise 2
server patroni1 patroni1:5432 check port 8008
server patroni2 patroni2:5432 check port 8008
# Stats
listen stats
bind *:7000
stats enable
stats uri /
Fonctionnement Patroni :
-
État normal :
- patroni1 = Primary (Read/Write)
- patroni2 = Standby (Read-Only)
- HAProxy route écritures vers Primary
-
Panne Primary :
- Patroni détecte panne via etcd
- Promotion automatique patroni2 → Primary
- HAProxy redirige traffic automatiquement
- Downtime : 10-30 secondes
-
Récupération ancien Primary :
- Redémarre automatiquement en Standby
- Replication reprend
Configuration logs :
services:
postgres:
image: postgres:18
command: |
postgres
-c log_statement=all
-c log_min_duration_statement=1000
-c log_connections=on
-c log_disconnections=on
-c log_line_prefix='%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
volumes:
- pgdata:/var/lib/postgresql/data
- ./logs:/var/log/postgresqlExporter logs vers système centralisé :
services:
postgres:
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "3"
# Ou vers syslog, fluentd, etc.Monitoring avec Prometheus :
services:
postgres:
image: postgres:18
# ... config ...
postgres-exporter:
image: prometheuscommunity/postgres-exporter:latest
environment:
DATA_SOURCE_NAME: "postgresql://postgres:secret@postgres:5432/postgres?sslmode=disable"
ports:
- "9187:9187"
depends_on:
- postgresservices:
postgres:
image: postgres:18
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30sHealth check avancé :
healthcheck:
test: |
pg_isready -U postgres && \
psql -U postgres -c "SELECT 1" > /dev/null 2>&1
interval: 10s
timeout: 5s
retries: 3Script backup avec cron :
services:
postgres:
# ... config ...
postgres-backup:
image: postgres:18
environment:
POSTGRES_HOST: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret
BACKUP_SCHEDULE: "0 2 * * *" # 2h du matin
volumes:
- ./backups:/backups
- ./backup-script.sh:/backup-script.sh
command: crond -fbackup-script.sh :
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
pg_dump -h postgres -U postgres -Fc production > /backups/backup_${DATE}.dump
# Rotation (garder 7 jours)
find /backups -name "backup_*.dump" -mtime +7 -deleteAvec extension pg_basebackup :
docker exec postgres-primary pg_basebackup \
-D /backups/base_$(date +%Y%m%d) \
-Ft -z -Xs -PStratégie Blue/Green :
# docker-compose.blue.yml (Version actuelle)
services:
postgres:
image: postgres:17 # Ancienne version
container_name: postgres-blue
ports:
- "5432:5432"
# docker-compose.green.yml (Nouvelle version)
services:
postgres:
image: postgres:18 # Nouvelle version
container_name: postgres-green
ports:
- "5433:5432" # Port différentProcédure upgrade :
# 1. Démarrer green (PG 18) sur port 5433
docker-compose -f docker-compose.green.yml up -d
# 2. Restore backup dans green
docker exec postgres-green psql -U postgres < backup.sql
# 3. Tester green
psql -h localhost -p 5433 -U postgres
# 4. Basculer traffic (HAProxy ou DNS)
# ...
# 5. Arrêter blue si OK
docker-compose -f docker-compose.blue.yml downservices:
postgres:
image: postgres:18
deploy:
resources:
limits:
cpus: '8'
memory: 16G
reservations:
cpus: '4'
memory: 8G
ulimits:
nofile:
soft: 65536
hard: 65536
nproc:
soft: 65536
hard: 65536Symptôme :
docker ps -a
# STATUS: Exited (1) 5 seconds agoDiagnostic :
# Voir les logs
docker logs postgres18
# Erreur typique :
# ERROR: database files are incompatible with serverSolutions courantes :
# 1. Volume avec mauvaise version PostgreSQL
# → Supprimer volume et recréer
docker volume rm pgdata
docker run -d --name postgres18 -v pgdata:/var/lib/postgresql/data postgres:18
# 2. Permissions volume incorrectes
docker run --rm -v pgdata:/data busybox chown -R 999:999 /data
# 3. Mot de passe manquant
docker run -e POSTGRES_PASSWORD=secret postgres:18Diagnostic :
# CPU/RAM utilisés
docker stats postgres18
# I/O en temps réel
docker exec postgres18 iostat -x 1
# Connexions actives
docker exec postgres18 psql -U postgres -c \
"SELECT count(*) FROM pg_stat_activity WHERE state = 'active';"Causes fréquentes :
-
Shared buffers trop bas :
# Augmenter docker run -e POSTGRES_SHARED_BUFFERS=2GB postgres:18 -
Limitation CPU :
# Vérifier limites docker inspect postgres18 | grep -i cpu # Augmenter docker update --cpus="4" postgres18
-
Volume I/O lent :
# Tester vitesse volume docker run --rm -v pgdata:/data ubuntu \ dd if=/dev/zero of=/data/test bs=1M count=1000 oflag=direct
Symptôme :
docker logs postgres18
# ... killed by OOM killerSolutions :
# 1. Augmenter limite mémoire
docker run --memory="8g" postgres:18
# 2. Adapter shared_buffers
# Règle : shared_buffers < 25% de RAM conteneur
docker run --memory="4g" \
postgres:18 \
postgres -c shared_buffers=1GB
# 3. Réduire work_mem si beaucoup de connexions
postgres -c work_mem=16MBSymptôme :
psql -h localhost -p 5432 -U postgres
# connection refusedDiagnostic :
# 1. Conteneur tourne-t-il ?
docker ps | grep postgres
# 2. Port bien mappé ?
docker port postgres18
# 3. PostgreSQL écoute sur bonne interface ?
docker exec postgres18 netstat -tlnp | grep 5432
# 4. Firewall hôte ?
sudo ufw statusSolutions :
# Vérifier pg_hba.conf
docker exec postgres18 cat /var/lib/postgresql/data/pg_hba.conf
# Doit contenir : host all all 0.0.0.0/0 scram-sha-256
# Vérifier listen_addresses
docker exec postgres18 psql -U postgres -c "SHOW listen_addresses;"
# Doit être '*' ou '0.0.0.0'| Critère | Bare Metal | VM | Conteneurs |
|---|---|---|---|
| Performance | ⭐⭐⭐⭐⭐ 100% | ⭐⭐⭐⭐ 90-95% | ⭐⭐⭐⭐ 95-98% |
| Overhead | 0% | 5-10% | 2-5% |
| Démarrage | Minutes | 30-60s | 1-5s |
| Taille | N/A | 2-20 GB | 50-500 MB |
| Densité | 1 serveur | 10-20/hôte | 50-1000+/hôte |
| Isolation | Totale | Forte | Moyenne |
| Portabilité | Faible | Moyenne | ⭐⭐⭐⭐⭐ Excellente |
| Coût initial | €€€€€ | €€€€ | €€ |
| Complexité | Élevée | Moyenne | Faible-Moyenne |
| HA | Manuelle | Automatisable | Automatisable |
| Mises à jour | Complexes | Moyennes | Simples |
| Backup | Complexe | Snapshots | Volumes |
Bare Metal :
- Trading haute fréquence
- Latence critique < 1ms
- Conformité interdisant virtualisation
- Infrastructure < 3 serveurs
VMs :
- Infrastructure 5-100 serveurs
- Besoin Live Migration
- Charges stables longue durée
- Isolation forte requise
Conteneurs :
- ✅ Microservices / Architecture moderne
- ✅ CI/CD / Environnements éphémères
- ✅ Développement local
- ✅ Cloud-native applications
- ✅ Déploiements fréquents
- ✅ Infrastructure as Code
1. VMs + Conteneurs (Recommandé Production) :
Infrastructure
├─ Serveurs Physiques (3×)
│ └─ Hyperviseur (Proxmox/VMware)
│ ├─ VM 1 : Kubernetes Node 1
│ │ └─ PostgreSQL Containers (Patroni)
│ ├─ VM 2 : Kubernetes Node 2
│ │ └─ PostgreSQL Containers (Patroni)
│ └─ VM 3 : Kubernetes Node 3
│ └─ PostgreSQL Containers (Patroni)
Avantages :
✅ Isolation VM + Flexibilité Conteneurs
✅ Live Migration VMs
✅ Orchestration Kubernetes
2. Bare Metal + Conteneurs (Performance Maximale) :
Serveurs Bare Metal (2×)
├─ Server 1 : Docker/Podman
│ └─ PostgreSQL Primary Container
└─ Server 2 : Docker/Podman
└─ PostgreSQL Standby Container
Usage : Bases critiques haute performance
# Docker → Podman (alias possible)
alias docker=podman
# Identiques
docker run → podman run
docker ps → podman ps
docker images → podman images
docker build → podman build # Créer pod (groupe de conteneurs partageant réseau)
podman pod create --name pg-pod -p 5432:5432
# Lancer PostgreSQL dans pod
podman run -d \
--pod pg-pod \
--name postgres \
-e POSTGRES_PASSWORD=secret \
postgres:18
# Lancer pgAdmin dans même pod
podman run -d \
--pod pg-pod \
--name pgadmin \
dpage/pgadmin4
# Avantage : Partage localhost, comme sur Kubernetes# En tant qu'utilisateur normal (pas root)
podman run -d \
--name postgres18 \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
postgres:18
# Processus sous votre UID
ps aux | grep postgres
# user 1000 ...Sécurité :
- Pas de daemon root
- User namespaces
- Isolation renforcée
# Générer service systemd depuis conteneur
podman generate systemd --new --name postgres18 > postgres.service
# Installer service
sudo cp postgres.service /etc/systemd/system/
sudo systemctl enable postgres
sudo systemctl start postgres
# Gestion comme service natif
sudo systemctl status postgres# Générer YAML Kubernetes depuis pod
podman generate kube pg-pod > postgres-k8s.yaml
# Déployer sur Kubernetes
kubectl apply -f postgres-k8s.yaml✅ Développement Local
- Setup en secondes
- Environnement reproductible
- Isolation des projets
- Versions PostgreSQL multiples
✅ CI/CD (Tests Automatisés)
- Tests d'intégration rapides
- Environnements éphémères
- Parallélisation facile
- Nettoyage automatique
✅ Microservices
- Déploiement indépendant
- Scaling horizontal
- Updates sans downtime (rolling)
- Service discovery natif
✅ Cloud-Native Applications
- Portabilité multi-cloud
- Infrastructure as Code
- Auto-scaling
- Intégration Kubernetes
✅ Prototypage et POC
- Démarrage instantané
- Coût minimal
- Flexibilité maximale
❌ Données critiques sans HA robuste
- Conteneur = Éphémère par nature
- Nécessite orchestration (Kubernetes, Patroni)
- Sinon, préférer VM avec réplication native
❌ Performance absolue requise
- Trading ultra haute fréquence
- Latence sub-milliseconde
- Bare metal reste optimal
❌ Équipe sans expertise conteneurs
- Courbe d'apprentissage
- Préférer VM si déjà maîtrisé
❌ Réglementations interdisant conteneurs
- Certifications spécifiques
- Secteurs conservateurs (finance, santé)
-
Conteneurs ≠ Moins Sécurisés : Bien configurés (rootless, read-only, secrets), ils sont très sûrs.
-
Volumes = Critical : Toujours utiliser named volumes en production, jamais de stockage éphémère.
-
Orchestration Requise Production : Docker Compose pour dev, Kubernetes/Patroni pour production.
-
Performance ~95-98% : Overhead négligeable pour la majorité des cas d'usage.
-
Podman > Docker en Production Linux : Sécurité supérieure, architecture daemonless.
-
PostgreSQL 18 compatible : Améliorations I/O async bénéficient même en conteneur.
Recommandation finale :
Développement :
└─ Docker Desktop (Windows/macOS) ou Podman (Linux)
Staging :
└─ Docker Compose ou Kubernetes (petite échelle)
Production :
├─ Small-Medium : Podman + Systemd ou Patroni
└─ Large : Kubernetes avec Operators (CloudNativePG, Zalando)
Les conteneurs sont l'avenir du déploiement PostgreSQL pour 80% des cas d'usage. Ils combinent flexibilité, portabilité et performance dans un package simple et moderne.
Prochaines étapes suggérées :
- 19.1.4. Kubernetes (StatefulSets, Operators)
-
- Drivers, Connexion Applicative et Bonnes Pratiques
-
- Extensions et Intégrations
⏭️ Kubernetes (StatefulSets, Operators : Zalando, CloudNativePG)