0%
Déployer une application React avec Docker

Docker Deployment

Containerisation et déploiement avec Docker

10-15 min

Déployer une application React avec Docker

Docker révolutionne la façon dont nous déployons les applications en permettant de créer des conteneurs légers et portables. Dans ce tutoriel, nous allons apprendre à containeriser une application React et la déployer efficacement.

Introduction à Docker

Qu’est-ce que Docker ?

Docker est une plateforme de containerisation qui permet d’empaqueter une application et ses dépendances dans un conteneur léger et portable. Cela garantit que l’application fonctionne de manière identique sur tous les environnements.

Avantages de Docker pour React

  • Cohérence : L’application fonctionne identiquement partout
  • Isolation : Chaque conteneur est isolé des autres
  • Scalabilité : Facilite la montée en charge
  • Déploiement : Processus de déploiement simplifié
  • Versioning : Gestion des versions facilitée

Installation de Docker

Sur Windows

  1. Téléchargez Docker Desktop depuis le site officiel
  2. Installez et redémarrez votre machine
  3. Vérifiez l’installation :
docker --version
docker-compose --version

Sur macOS

# Avec Homebrew
brew install --cask docker

# Ou téléchargez Docker Desktop

Sur Linux (Ubuntu)

# Mise à jour des paquets
sudo apt update

# Installation des dépendances
sudo apt install apt-transport-https ca-certificates curl software-properties-common

# Ajout de la clé GPG Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# Ajout du repository Docker
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"

# Installation de Docker
sudo apt update
sudo apt install docker-ce

# Vérification
sudo systemctl status docker

Création d’une application React

Initialisation du projet

npx create-react-app react-docker-app
cd react-docker-app

Structure du projet

react-docker-app/
├── public/
├── src/
├── package.json
├── Dockerfile
├── .dockerignore
└── docker-compose.yml

Configuration Docker

Création du Dockerfile

Créez un fichier Dockerfile à la racine du projet :

# Étape 1: Build de l'application
FROM node:18-alpine as build

# Définir le répertoire de travail
WORKDIR /app

# Copier les fichiers de dépendances
COPY package*.json ./

# Installer les dépendances
RUN npm ci --only=production

# Copier le code source
COPY . .

# Build de l'application
RUN npm run build

# Étape 2: Servir l'application avec Nginx
FROM nginx:alpine

# Copier les fichiers buildés vers Nginx
COPY --from=build /app/build /usr/share/nginx/html

# Copier la configuration Nginx personnalisée
COPY nginx.conf /etc/nginx/nginx.conf

# Exposer le port 80
EXPOSE 80

# Commande par défaut
CMD ["nginx", "-g", "daemon off;"]

Configuration Nginx

Créez un fichier nginx.conf :

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    # Configuration pour les applications React (SPA)
    server {
        listen       80;
        server_name  localhost;
        root         /usr/share/nginx/html;
        index        index.html;

        # Gestion des routes React Router
        location / {
            try_files $uri $uri/ /index.html;
        }

        # Cache pour les assets statiques
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }

        # Sécurité
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;

        # Compression
        gzip on;
        gzip_vary on;
        gzip_min_length 1024;
        gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
    }
}

Fichier .dockerignore

Créez un fichier .dockerignore :

node_modules
npm-debug.log
build
.dockerignore
Dockerfile
Dockerfile.prod
.git
.gitignore
README.md
.env
.nyc_output
coverage
.nyc_output
.coverage
.coverage/

Build et exécution

Construction de l’image Docker

# Build de l'image
docker build -t react-docker-app .

# Vérifier que l'image a été créée
docker images

Exécution du conteneur

# Lancer le conteneur
docker run -d -p 3000:80 --name react-app react-docker-app

# Vérifier que le conteneur fonctionne
docker ps

# Voir les logs
docker logs react-app

# Arrêter le conteneur
docker stop react-app

# Supprimer le conteneur
docker rm react-app

Docker Compose

Configuration docker-compose.yml

Créez un fichier docker-compose.yml :

version: '3.8'

services:
  react-app:
    build: .
    ports:
      - "3000:80"
    environment:
      - NODE_ENV=production
    restart: unless-stopped
    
  # Service optionnel : Base de données
  database:
    image: postgres:13
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  # Service optionnel : Redis pour le cache
  redis:
    image: redis:alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

Utilisation de Docker Compose

# Lancer tous les services
docker-compose up -d

# Voir les logs
docker-compose logs -f

# Arrêter tous les services
docker-compose down

# Rebuild et relancer
docker-compose up --build -d

Optimisations avancées

Dockerfile multi-stage optimisé

# Étape 1: Build
FROM node:18-alpine as dependencies
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

FROM node:18-alpine as build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Étape 2: Production
FROM nginx:alpine as production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# Copier les fichiers buildés
COPY --from=build --chown=nextjs:nodejs /app/build /usr/share/nginx/html

# Configuration Nginx
COPY nginx.conf /etc/nginx/nginx.conf

# Sécurité
RUN chown -R nextjs:nodejs /usr/share/nginx/html
USER nextjs

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Variables d’environnement

# Dans le Dockerfile
ARG REACT_APP_API_URL
ARG REACT_APP_VERSION
ENV REACT_APP_API_URL=$REACT_APP_API_URL
ENV REACT_APP_VERSION=$REACT_APP_VERSION
# Build avec des variables
docker build --build-arg REACT_APP_API_URL=https://api.production.com -t react-app .

Fichier .env pour Docker Compose

Créez un fichier .env :

# Application
REACT_APP_API_URL=https://api.example.com
REACT_APP_VERSION=1.0.0

# Base de données
POSTGRES_DB=myapp
POSTGRES_USER=user
POSTGRES_PASSWORD=securepassword

# Ports
APP_PORT=3000
DB_PORT=5432

Déploiement en production

Avec Docker Swarm

# Initialiser Swarm
docker swarm init

# Déployer la stack
docker stack deploy -c docker-compose.yml react-stack

# Voir les services
docker service ls

# Scaler le service
docker service scale react-stack_react-app=3

Avec Kubernetes

Créez un fichier k8s-deployment.yaml :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: react-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: react-app
  template:
    metadata:
      labels:
        app: react-app
    spec:
      containers:
      - name: react-app
        image: react-docker-app:latest
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  name: react-app-service
spec:
  selector:
    app: react-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: LoadBalancer
# Déployer sur Kubernetes
kubectl apply -f k8s-deployment.yaml

# Voir les pods
kubectl get pods

# Voir les services
kubectl get services

Monitoring et logs

Configuration des logs

# Dans le Dockerfile
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

Health checks

# Ajout d'un health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost/ || exit 1

Monitoring avec Docker Compose

version: '3.8'

services:
  react-app:
    build: .
    ports:
      - "3000:80"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/"]
      interval: 30s
      timeout: 10s
      retries: 3
      
  # Monitoring
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      
  grafana:
    image: grafana/grafana
    ports:
      - "3001:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin

Sécurité

Bonnes pratiques de sécurité

# Utiliser des images officielles
FROM node:18-alpine

# Créer un utilisateur non-root
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# Mettre à jour les paquets
RUN apk update && apk upgrade

# Utiliser l'utilisateur non-root
USER nextjs

# Scanner les vulnérabilités
RUN npm audit fix

Configuration Nginx sécurisée

# Masquer la version Nginx
server_tokens off;

# Headers de sécurité
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;

# Limiter la taille des uploads
client_max_body_size 10M;

# Timeout
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;

CI/CD avec Docker

GitHub Actions

Créez .github/workflows/docker.yml :

name: Docker Build and Deploy

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v1
    
    - name: Login to DockerHub
      uses: docker/login-action@v1
      with:
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_TOKEN }}
    
    - name: Build and push
      uses: docker/build-push-action@v2
      with:
        context: .
        push: true
        tags: |
          myusername/react-app:latest
          myusername/react-app:${{ github.sha }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

GitLab CI

Créez .gitlab-ci.yml :

stages:
  - build
  - test
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE

deploy:
  stage: deploy
  image: alpine:latest
  script:
    - apk add --no-cache curl
    - curl -X POST $WEBHOOK_URL
  only:
    - main

Troubleshooting

Problèmes courants

  1. Erreur de permissions :
# Changer les permissions
sudo chown -R $USER:$USER /path/to/project
  1. Port déjà utilisé :
# Trouver le processus utilisant le port
sudo lsof -i :3000
# Tuer le processus
sudo kill -9 PID
  1. Problème de cache :
# Nettoyer le cache Docker
docker system prune -a
  1. Erreur de build :
# Build sans cache
docker build --no-cache -t react-app .

Debugging

# Entrer dans le conteneur
docker exec -it react-app sh

# Voir les logs en temps réel
docker logs -f react-app

# Inspecter le conteneur
docker inspect react-app

Conclusion

Docker transforme la façon dont nous déployons les applications React en offrant :

  • Cohérence entre les environnements
  • Facilité de déploiement et de mise à l’échelle
  • Isolation des dépendances
  • Portabilité sur différentes plateformes

En maîtrisant Docker, vous pouvez déployer vos applications React de manière plus fiable et efficace, que ce soit en développement, en test ou en production.

Prochaines étapes

  • Explorez Kubernetes pour l’orchestration
  • Implémentez le monitoring avec Prometheus
  • Optimisez les performances avec des CDN
  • Mettez en place des pipelines CI/CD avancés

Commentaires

Les commentaires sont alimentés par GitHub Discussions

Connectez-vous avec GitHub pour participer à la discussion

Lien copié !