Skip to content

Configuration Docker

Exécuter Artisan dans Docker nécessite un binaire Chrome ou Chromium dans le conteneur. Ce guide couvre les patterns Dockerfile prêts pour la production, configuration Compose, considérations de sécurité et support de polices.

Dockerfile

Minimal (basé Debian)

dockerfile
FROM php:8.3-cli

# Installer Chromium et bibliothèques requises
RUN apt-get update && apt-get install -y --no-install-recommends \
    chromium \
    fonts-liberation \
    libappindicator3-1 \
    libasound2 \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libgbm1 \
    libnspr4 \
    libnss3 \
    libx11-xcb1 \
    libxcomposite1 \
    libxdamage1 \
    libxrandr2 \
    xdg-utils \
    && rm -rf /var/lib/apt/lists/*

# Définir chemin Chrome pour auto-détection Artisan
ENV CHROME_PATH=/usr/bin/chromium

# Installer dépendances Composer
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader

COPY . .

Basé Alpine (image plus petite)

dockerfile
FROM php:8.3-cli-alpine

RUN apk add --no-cache \
    chromium \
    nss \
    freetype \
    harfbuzz \
    ca-certificates \
    ttf-freefont \
    font-noto-cjk

ENV CHROME_PATH=/usr/bin/chromium-browser

COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader

COPY . .

Docker Compose

yaml
services:
  app:
    build: .
    volumes:
      - ./output:/app/output
    environment:
      CHROME_PATH: /usr/bin/chromium
    deploy:
      resources:
        limits:
          memory: 1G
        reservations:
          memory: 512M
    # Requis pour sandboxing Chrome dans Docker
    security_opt:
      - seccomp=unconfined
    cap_add:
      - SYS_ADMIN

Drapeaux Chrome pour Docker

Chrome dans un conteneur nécessite des drapeaux spécifiques pour fonctionner de manière fiable. Passez-les lors de la création du renderer.

php
use Yeeefang\TcpdfNext\Artisan\HtmlRenderer;

$renderer = HtmlRenderer::create(
    chromeFlags: [
        '--no-sandbox',              // requis sauf si vous configurez seccomp
        '--disable-setuid-sandbox',  // contournement sandbox secondaire
        '--disable-gpu',             // pas de GPU dans conteneurs
        '--disable-dev-shm-usage',   // écrire dans /tmp au lieu de /dev/shm
        '--disable-software-rasterizer',
        '--single-process',          // réduire mémoire pour rendus simples
    ],
);

WARNING

Le drapeau --no-sandbox désactive le sandbox processus de Chrome. En production, préférez garder le sandbox activé et accorder la capacité SYS_ADMIN au conteneur ou utiliser un profil seccomp personnalisé à la place.

Considérations de sécurité

Option A : Garder le Sandbox (Recommandé)

Ajouter SYS_ADMIN au conteneur et omettre --no-sandbox.

yaml
services:
  app:
    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp=chrome-seccomp.json

Vous pouvez trouver le profil seccomp minimal pour Chrome dans la documentation du projet Chromium.

Option B : Utilisateur non-root

Exécuter Chrome comme utilisateur dédié non privilégié dans le conteneur.

dockerfile
RUN groupadd -r artisan && useradd -r -g artisan -G audio,video artisan \
    && mkdir -p /home/artisan/Downloads \
    && chown -R artisan:artisan /home/artisan

USER artisan

Option C : Système de fichiers en lecture seule

Monter le système de fichiers racine en lecture seule et fournir tmpfs modifiable pour Chrome.

yaml
services:
  app:
    read_only: true
    tmpfs:
      - /tmp
      - /home/artisan/.config

Limites mémoire

Chrome peut consommer beaucoup de mémoire, surtout lors du rendu de pages complexes. Définir des limites de conteneur et surveiller l'utilisation.

Complexité pageMémoire recommandée
Texte simple (1-5 pages)256 MB
Tableaux et images (5-20 pages)512 MB
Layouts complexes, graphiques, JS (20+ pages)1 GB+

Si Chrome manque de mémoire, il sort avec code 137 (tué OOM). La RenderException Artisan encapsule ceci avec un message descriptif.

php
// Échouer rapidement avec timeout serré pour éviter emballement mémoire
$options = RenderOptions::create()->setTimeout(15000);

Installation de polices

Les images Docker sont fournies avec polices minimales. Installer des polices supplémentaires pour rendu correct des scripts non-latins et typographie de marque.

Polices système

dockerfile
# Polices CJK (Chinois, Japonais, Coréen)
RUN apt-get update && apt-get install -y \
    fonts-noto-cjk \
    fonts-noto-cjk-extra

# Arabe, Hébreu, Devanagari
RUN apt-get install -y \
    fonts-noto-core \
    fonts-noto-extra

# Google Fonts (ex., Inter, Roboto)
RUN apt-get install -y fonts-inter

Polices personnalisées

Copier fichiers de polices dans le conteneur et les enregistrer avec fontconfig.

dockerfile
COPY ./fonts/*.ttf /usr/share/fonts/custom/
RUN fc-cache -fv

Polices web

Chrome dans Artisan peut récupérer des polices web @font-face au moment du rendu, comme un navigateur normal. Aucune configuration supplémentaire n'est nécessaire, mais assurez-vous que le conteneur a accès réseau au CDN de polices.

css
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');

body {
    font-family: 'Inter', sans-serif;
}

Health Check

Ajouter un health check qui vérifie que Chrome est opérationnel.

dockerfile
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
    CMD chromium --headless=new --disable-gpu --no-sandbox \
        --dump-dom about:blank > /dev/null 2>&1 || exit 1

Exemple production complet

dockerfile
FROM php:8.3-cli-bookworm AS base

# Dépendances système + Chromium
RUN apt-get update && apt-get install -y --no-install-recommends \
    chromium \
    fonts-liberation \
    fonts-noto-cjk \
    libnss3 libgbm1 libatk-bridge2.0-0 \
    && rm -rf /var/lib/apt/lists/*

ENV CHROME_PATH=/usr/bin/chromium

# Utilisateur non-root
RUN groupadd -r artisan && useradd -r -g artisan artisan \
    && mkdir -p /home/artisan && chown artisan:artisan /home/artisan

WORKDIR /app

COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader

COPY --chown=artisan:artisan . .

USER artisan

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
    CMD chromium --headless=new --no-sandbox --dump-dom about:blank > /dev/null 2>&1

CMD ["php", "artisan", "render:process"]

Prochaines étapes

Distribué sous licence LGPL-3.0-or-later.