DevOps

Déployer sa première application avec Docker

De votre code à un conteneur en production sur un VPS abordable : Dockerfile, image légère et docker compose, pas à pas, avec les pièges à éviter.

Vous avez codé une petite API ou une application web, elle tourne parfaitement sur votre machine, mais le jour où vous voulez la mettre en ligne, tout casse : mauvaise version de Node, dépendance manquante, port introuvable. Cette phrase « ça marche chez moi » est exactement le problème que Docker vient résoudre. Dans cet article, nous allons partir d’une application simple et la déployer, étape par étape, sur un VPS abordable (un serveur à 4 ou 5 dollars par mois suffit largement pour démarrer).

Objectif concret : à la fin, vous aurez un Dockerfile qui produit une image légère, un fichier docker compose pour orchestrer le tout, et votre service accessible depuis Internet. On suppose une API Node.js comme fil rouge, mais la démarche est identique pour Python, PHP ou Go.

Pourquoi un conteneur change tout

Un conteneur, c’est votre application empaquetée avec exactement ce dont elle a besoin pour fonctionner : le code, le runtime, les bibliothèques, la configuration. Contrairement à une machine virtuelle, il ne réinstalle pas tout un système d’exploitation : il partage le noyau de l’hôte, ce qui le rend rapide à démarrer et léger.

Concrètement, cela vous apporte :

  • La reproductibilité : l’image que vous testez en local est octet pour octet celle qui tournera en production.
  • L’isolation : deux applications avec des versions de dépendances incompatibles cohabitent sans conflit.
  • La portabilité : la même image tourne sur votre laptop, chez un collègue ou sur le VPS, sans réglage manuel.

Écrire un Dockerfile qui produit une image légère

Le Dockerfile est la recette de votre image. La clé pour une image légère, c’est le multi-stage build : on installe et on construit dans une première étape, puis on ne copie que le strict nécessaire dans une image finale minimale.

# Étape 1 : construction
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Étape 2 : image finale, minimale
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]

Deux détails font toute la différence ici. D’abord, le tag alpine : cette base Linux minuscule fait passer une image Node de plusieurs centaines de mégaoctets à quelques dizaines. Ensuite, l’ordre des instructions : on copie package*.json et on installe les dépendances avant de copier le reste du code. Ainsi, tant que vos dépendances ne changent pas, Docker réutilise le cache et reconstruit en quelques secondes.

Le fichier .dockerignore, votre meilleur ami

N’embarquez jamais node_modules ni vos fichiers locaux dans l’image. Créez un .dockerignore à côté du Dockerfile :

node_modules
.git
.env
npm-debug.log
dist

Orchestrer avec docker compose

Une vraie application a rarement un seul service. Avec docker compose, vous décrivez l’ensemble (votre API, une base de données, un reverse proxy) dans un seul fichier compose.yaml lisible et versionné.

services:
  api:
    build: .
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://app:secret@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_USER=app
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=app
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Notez le volumes sur la base de données : sans lui, vos données disparaîtraient à chaque redémarrage du conteneur. Notez aussi restart: unless-stopped, qui relance automatiquement le service en cas de plantage ou de redémarrage du serveur.

Ne stockez jamais vos mots de passe en clair dans le fichier compose versionné. Utilisez un fichier .env (ignoré par Git) et référencez les variables avec la syntaxe ${DATABASE_URL}. Un secret poussé sur GitHub est un secret compromis, même après suppression.

Déployer sur le VPS

Louez un petit VPS (Hetzner, Contabo, DigitalOcean ou un hébergeur local). Une fois connecté en SSH, installez Docker via le script officiel, puis envoyez votre code et lancez tout :

# Sur le VPS, en SSH
curl -fsSL https://get.docker.com | sh

# Récupérez votre projet (Git est le plus propre)
git clone https://github.com/votre-compte/mon-api.git
cd mon-api

# Construisez et démarrez en arrière-plan
docker compose up -d --build

# Vérifiez que tout tourne
docker compose ps
docker compose logs -f api

Votre API répond désormais sur http://IP_DU_VPS:3000. Pour la production, ajoutez ensuite un reverse proxy comme Caddy ou Traefik afin d’obtenir un nom de domaine et le HTTPS automatique, mais ce premier déploiement est déjà pleinement fonctionnel.

Le piège fréquent à éviter

L’erreur la plus courante des débutants concerne le réseau interne. Dans le fichier compose ci-dessus, l’API se connecte à la base via l’hôte db, et non localhost. Pourquoi ? Parce que chaque conteneur a son propre localhost : si votre API cherche la base sur localhost:5432, elle se cherche elle-même et échoue. Docker compose crée un réseau privé où chaque service est joignable par le nom déclaré dans le fichier. Retenez la règle : entre conteneurs, on s’adresse par le nom du service, jamais par localhost.

Récapitulatif

Vous venez de parcourir la chaîne complète : un Dockerfile multi-stage pour une image légère, un .dockerignore pour ne pas l’alourdir, un compose.yaml pour orchestrer API et base de données, et un déploiement en trois commandes sur un VPS abordable. Les prochaines étapes naturelles seront le HTTPS via un reverse proxy, puis l’automatisation du déploiement avec un pipeline CI/CD. Mais l’essentiel est acquis : votre application ne dépend plus de votre machine, elle vit dans un conteneur reproductible, et « ça marche chez moi » devient enfin « ça marche partout ».

Pour aller plus loin

Malick Diallo

Rédaction SenTur

Contributeur SenTur — passionné de tech et de transmission.

Aucun commentaire pour l'instant — lancez la discussion !

Laisser un commentaire

Votre adresse email ne sera pas publiée. La discussion est modérée — restez courtois et constructif.