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
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 :
- Bibliothèques graphiques (libX11, libXcomposite, libXdamage...)
- Fonts système
- Shared memory (/dev/shm)
- Sandboxing Linux (namespaces, seccomp)
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 :
- 512MB pour une page simple
- 1-2GB pour du scraping intensif
- 4GB+ pour plusieurs onglets parallèles
# 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 :
- Mémoire insuffisante → Augmenter les limites
- /dev/shm trop petit →
shm_size: '2gb' - 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'minimuminit: truepour éviter les zombies- Limites mémoire définies (2GB+ recommandé)
--disable-dev-shm-usagesi shm_size impossible- Healthcheck configuré
- Fonts installées si rendu texte nécessaire
Conclusion
Les erreurs Playwright en Docker viennent presque toujours de :
- Permissions : Chromium installé en root, exécuté en user
- Mémoire : /dev/shm trop petit ou limites Docker trop basses
- 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.