Retour aux articles

Playwright et Chromium en production Docker : le guide pratique

Playwright est devenu incontournable pour les tests E2E et le scraping. Mais le passage en production Docker est souvent un parcours du combattant : Chromium qui ne se lance pas, erreurs de permissions, crashes mémoire...

Cet article vous donne les clés pour une configuration robuste, testée en production.

Sommaire
  1. Le problème
  2. Construction de l'image Docker
  3. Configuration utilisateur non-root
  4. Configuration Playwright
  5. Gestion des ressources
  6. Dockerfile et docker-compose complets
  7. Debugging
  8. Checklist production

Le problème : pourquoi ça ne marche pas "out of the box"

Chromium n'est pas une simple librairie. C'est un navigateur complet avec des dépendances système lourdes :

En local, votre OS fournit tout ça. Dans un conteneur minimaliste, rien n'est présent.

Construction de l'image Docker

Choix de l'image de base

Évitez Alpine pour Playwright. Les dépendances musl vs glibc causent des incompatibilités. Préférez Debian ou Ubuntu.

# Recommandé : image officielle Playwright
FROM mcr.microsoft.com/playwright:v1.40.0-jammy

# Alternative : Debian slim + installation manuelle
FROM python:3.11-slim-bookworm

Installation des dépendances

Avec l'image officielle Playwright, tout est inclus. Sinon :

FROM python:3.11-slim-bookworm

# Dépendances système pour Chromium
RUN apt-get update && apt-get install -y --no-install-recommends \
    libnss3 \
    libnspr4 \
    libatk1.0-0 \
    libatk-bridge2.0-0 \
    libcups2 \
    libdrm2 \
    libxkbcommon0 \
    libxcomposite1 \
    libxdamage1 \
    libxfixes3 \
    libxrandr2 \
    libgbm1 \
    libasound2 \
    libpango-1.0-0 \
    libcairo2 \
    fonts-liberation \
    && rm -rf /var/lib/apt/lists/*

# Installation Playwright
RUN pip install playwright && playwright install chromium

Configuration utilisateur non-root

Ne jamais exécuter Chromium en root. C'est un risque de sécurité majeur et ça désactive le sandboxing.

# Créer un utilisateur dédié
RUN useradd -m -u 1000 pwuser

# Répertoire de travail avec bonnes permissions
WORKDIR /app
RUN chown -R pwuser:pwuser /app

# Installer Playwright EN TANT QUE l'utilisateur
USER pwuser
RUN playwright install chromium

# Le cache sera dans /home/pwuser/.cache/ms-playwright

Erreur classique : installer en root, exécuter en user

Mauvais

# Chromium installé en root
RUN pip install playwright
RUN playwright install chromium
USER pwuser
# Erreur : Chromium introuvable
# (installé dans /root/.cache)

Bon

# Chromium installé par l'user
RUN pip install playwright
USER pwuser
RUN playwright install chromium
# OK : dans /home/pwuser/.cache

Configuration Playwright pour Docker

Arguments Chromium essentiels

from playwright.sync_api import sync_playwright

def get_browser():
    playwright = sync_playwright().start()
    browser = playwright.chromium.launch(
        headless=True,
        args=[
            '--disable-dev-shm-usage',  # Évite les crashes mémoire
            '--no-sandbox',              # Seulement si user non-root impossible
            '--disable-setuid-sandbox',
            '--disable-gpu',             # Pas de GPU dans Docker
            '--disable-software-rasterizer',
        ]
    )
    return browser

Le piège du /dev/shm

Par défaut, Docker limite /dev/shm à 64MB. Chromium l'utilise pour le rendu et crashe si c'est insuffisant.

Solution 1 : Augmenter la taille (recommandé)

# docker-compose.yml
services:
  app:
    shm_size: '2gb'

Solution 2 : Désactiver l'utilisation de shm

args=['--disable-dev-shm-usage']

La solution 1 est préférable pour les performances.

Gestion des ressources

Limites mémoire

Chromium est gourmand. Prévoyez au minimum :

# docker-compose.yml
services:
  app:
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 512M

Éviter les processus zombies

Chromium spawne des sous-processus. Sans init system, ils deviennent zombies.

# docker-compose.yml
services:
  app:
    init: true  # Ajoute tini comme PID 1

Ou dans le Dockerfile :

RUN apt-get install -y tini
ENTRYPOINT ["/usr/bin/tini", "--"]

Dockerfile et docker-compose complets

Dockerfile

FROM python:3.11-slim-bookworm

# Dépendances système
RUN apt-get update && apt-get install -y --no-install-recommends \
    libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 \
    libcups2 libdrm2 libxkbcommon0 libxcomposite1 \
    libxdamage1 libxfixes3 libxrandr2 libgbm1 \
    libasound2 libpango-1.0-0 libcairo2 \
    fonts-liberation tini \
    && rm -rf /var/lib/apt/lists/*

# Utilisateur non-root
RUN useradd -m -u 1000 pwuser
WORKDIR /app

# Dépendances Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Installation Chromium en tant que pwuser
USER pwuser
RUN playwright install chromium

# Application
COPY --chown=pwuser:pwuser . .

ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["python", "app.py"]

docker-compose.yml

version: '3.8'

services:
  playwright-app:
    build: .
    shm_size: '2gb'
    init: true
    deploy:
      resources:
        limits:
          memory: 2G
          cpus: '2'
    environment:
      - PLAYWRIGHT_BROWSERS_PATH=/home/pwuser/.cache/ms-playwright
    healthcheck:
      test: ["CMD", "python", "-c", "import playwright; print('ok')"]
      interval: 30s
      timeout: 10s
      retries: 3

Debugging

"Browser closed unexpectedly"

Causes fréquentes :

  1. Mémoire insuffisante → Augmenter les limites
  2. /dev/shm trop petit → shm_size: '2gb'
  3. Dépendances manquantes → Vérifier les libs

"Failed to launch browser"

# Vérifier que Chromium est installé
docker exec -it container playwright install --dry-run

# Tester le lancement manuel
docker exec -it container python -c "
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
    browser = p.chromium.launch()
    print('OK')
    browser.close()
"

Logs détaillés

DEBUG=pw:* python app.py

Checklist production

Avant de déployer

  • Image basée sur Debian/Ubuntu (pas Alpine)
  • Utilisateur non-root
  • Chromium installé par l'utilisateur final
  • shm_size: '2gb' minimum
  • init: true pour éviter les zombies
  • Limites mémoire définies (2GB+ recommandé)
  • --disable-dev-shm-usage si shm_size impossible
  • Healthcheck configuré
  • Fonts installées si rendu texte nécessaire

Conclusion

Les erreurs Playwright en Docker viennent presque toujours de :

  1. Permissions : Chromium installé en root, exécuté en user
  2. Mémoire : /dev/shm trop petit ou limites Docker trop basses
  3. Dépendances : libs système manquantes

Avec la configuration de cet article, vous avez une base solide pour la production.

Ressources :

Vous avez des questions ou des retours d'expérience ? Contactez-moi ou retrouvez-moi sur LinkedIn.

Thomas Bourimech

Thomas Bourimech

Développeur & Intégrateur IA freelance

thomasbourimech.com