Retour au Centre de connaissances
Déploiement

Navigateur automatisé dans Docker : déploiement et mise à l'échelle

Déployez l'automatisation de navigateur dans Docker avec un Dockerfile, la mise à l'échelle Compose, des volumes montés et de bonnes pratiques de production.

BotBrowser Team

Documentation

Vous préférez la doc produit maintenue ?

Cet article a une page équivalente dans le centre de documentation. Utilisez les docs pour le flux canonique, les flags à jour et la référence durable.

Docker offre à un déploiement de navigateur une image reproductible, un système de fichiers privé, son propre espace de noms réseau et des limites de ressources. Chaque conteneur démarre du même état connu, une politique de redémarrage peut relancer un worker tombé en panne, et un problème de mémoire dans un conteneur reste confiné à ce conteneur. Ce sont de vrais avantages d'exploitation pour les flottes BotBrowser, et c'est pourquoi la plupart des équipes passent de serveurs montés à la main à des images.

TL;DR

  • Augmentez d'abord la mémoire partagée : un conteneur reçoit 64 MB de /dev/shm par défaut, donc passez --shm-size=2g ou shm_size: 2gb avant que les onglets commencent à planter.
  • Lancez Xvfb dans l'entrypoint et exportez DISPLAY=:10.0 avant le navigateur, sinon le conteneur sort avec "Cannot open display".
  • Partez d'une base Ubuntu 22.04 ou Debian : les binaires basés sur Chrome exigent glibc, et une image Alpine avec musl ne les démarre pas.
  • Passez --init ou init: true pour que Docker récupère les processus orphelins du navigateur, et donnez à chaque conteneur son propre volume de données utilisateur.
  • Publiez le port de débogage en -p 127.0.0.1:9222:9222, jamais avec un -p 9222:9222 nu, car quiconque atteint ce port contrôle le navigateur.

Sommaire

Prérequis du conteneur avant le premier démarrage

Docker ne décide pas si un déploiement réussit face à un site précis, et il ne fait pas se comporter tous les hôtes de la même façon. Il isole des processus et limite des ressources. Le navigateur a toujours besoin des bibliothèques système, de l'affichage, de la mémoire partagée et de la route réseau qu'exige n'importe quel navigateur basé sur Chrome. Réussir ces cinq prérequis dans l'image distingue un déploiement qui démarre à chaque fois d'un déploiement qui échoue au bout d'une heure.

La mémoire partagée vient en premier. Chrome utilise /dev/shm pour la communication entre ses processus, et un conteneur Docker reçoit un /dev/shm de 64 Mo sauf si vous le modifiez. C'est très insuffisant pour un navigateur avec de vraies pages chargées, et les symptômes habituels sont des onglets qui plantent, des pages blanches ou un message de mémoire insuffisante alors que l'hôte dispose de beaucoup de RAM libre. Commencez avec --shm-size=2g sur docker run, ou shm_size: 2gb dans un fichier Compose, et considérez toute valeur inférieure à 1 Go comme un risque. La taille que vous conservez finalement doit venir de la mesure de vos propres pages.

Le deuxième prérequis est un affichage virtuel. BotBrowser a besoin d'un affichage X11 même en mode headless, donc le conteneur doit démarrer Xvfb avant le navigateur et exporter DISPLAY avec la valeur correspondante. Si l'entrypoint lance d'abord le navigateur, le conteneur s'arrête aussitôt avec le message « Cannot open display ». Une courte attente après le démarrage de Xvfb est la solution la plus simple, et un contrôle de santé qui confirme l'existence du socket d'affichage est la plus rigoureuse.

Le troisième est l'image de base. Les navigateurs basés sur Chrome dépendent de glibc, utilisez donc une base Debian ou Ubuntu. Alpine utilise musl et n'exécute pas ces binaires. L'image documentée utilise Ubuntu 22.04 avec les bibliothèques partagées listées dans le Dockerfile ci-dessous. Une bibliothèque manquante se manifeste par un échec de démarrage, alors conservez la liste des paquets sous contrôle de version et reconstruisez l'image plutôt que de corriger un conteneur en cours d'exécution.

Le quatrième est un processus init. Un navigateur crée des processus enfants et, quand l'un d'eux devient orphelin, personne ne le récupère. Au fil d'une longue exécution, ces processus zombies s'accumulent. Passez --init à docker run, ou définissez init: true dans Compose, pour que l'init propre à Docker devienne le PID 1 et les nettoie.

Le cinquième est un répertoire de données utilisateur distinct pour chaque processus du navigateur. Dans un conteneur, ce répertoire se trouve dans la couche inscriptible du conteneur et disparaît quand celui-ci est supprimé, donc montez un volume sur ce chemin si vous voulez que les cookies et le stockage survivent à un redémarrage. Ne laissez pas deux conteneurs en cours d'exécution partager un répertoire, car deux navigateurs qui écrivent dans le même répertoire de profil corrompent mutuellement leur état.

PrérequisRéglage DockerCe que vous observez sans lui
Mémoire partagée d'au moins 1 à 2 Go--shm-size=2g ou shm_size: 2gbPlantages et pages blanches sous charge
Affichage virtuel avant le lancementXvfb dans l'entrypoint, DISPLAY=:10.0« Cannot open display » au démarrage
Image de base avec glibcDebian ou Ubuntu, pas AlpineLe binaire ne démarre pas
Processus init--init ou init: trueLes processus zombies s'accumulent
Répertoire de données utilisateur distinctUn volume par instance dans /app/dataSessions perdues, ou état corrompu en cas de partage

Organisation d'un conteneur Docker avec BotBrowser : affichage Xvfb, le navigateur avec un profil monté, un port de débogage en loopback uniquement, des limites de ressources, un volume de profils en lecture seule et un volume de données utilisateur par instance.

Les binaires Ubuntu et Linux nécessitent un forfait BotBrowser éligible. La documentation de déploiement Docker indique ENT Tier 1 ou supérieur pour eux, confirmez donc votre forfait avant de construire une image autour du paquet .deb.

Construisez l'image et démarrez un conteneur

Le Dockerfile ci-dessous suit la documentation Docker de BotBrowser. Il installe les bibliothèques partagées et Xvfb, installe le paquet .deb de BotBrowser que vous avez téléchargé pour votre forfait, et crée les deux répertoires que le conteneur utilise pour les profils et les données utilisateur. L'option --platform=linux/amd64 fixe l'architecture afin qu'une image construite sur un hôte se construise de la même façon sur un autre.

FROM --platform=linux/amd64 ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
ENV DISPLAY=:10.0
RUN apt-get update && apt-get install -y \
    libnss3 libatk1.0-0 libatk-bridge2.0-0 \
    libcups2 libdrm2 libxcomposite1 libxdamage1 \
    libxrandr2 libgbm1 libxkbcommon0 libgtk-3-0 \
    libpangocairo-1.0-0 libpango-1.0-0 \
    libwayland-client0 libwayland-server0 \
    libdbus-1-3 libatspi2.0-0 libasound2 libxss1 \
    fonts-liberation libcurl4 libvulkan1 \
    xvfb curl ca-certificates \
    && rm -rf /var/lib/apt/lists/*
COPY botbrowser_*.deb /tmp/
RUN dpkg -i /tmp/botbrowser_*.deb || apt-get install -f -y \
    && rm /tmp/botbrowser_*.deb
RUN mkdir -p /app/profiles /app/data
WORKDIR /app
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]

L'entrypoint démarre l'affichage virtuel puis se remplace par le navigateur grâce à exec, de sorte que les signaux de docker stop atteignent directement le navigateur. Tout ce que vous passez après le nom de l'image arrive sous la forme "$@", ce qui permet d'exécuter la même image avec différents profils et proxys sans la reconstruire.

#!/bin/bash
Xvfb :10 -screen 0 1920x1080x24 -ac &
sleep 1
exec chromium-browser \
    --headless \
    --no-sandbox \
    --disable-dev-shm-usage \
    --user-data-dir=/app/data \
    --remote-debugging-port=9222 \
    --remote-debugging-address=0.0.0.0 \
    "$@"

Deux options de ce script méritent un commentaire. --disable-dev-shm-usage indique à Chrome d'écrire ses fichiers de mémoire partagée dans /tmp au lieu de /dev/shm. C'est une mesure alternative contre un petit /dev/shm. Une fois activée, Chrome n'utilise plus /dev/shm, donc --shm-size compte surtout lorsque l'option est absente, et conserver les deux est une précaution. --no-sandbox est utilisé parce que les conteneurs s'exécutent couramment sans les privilèges que demande le bac à sable de Chrome. Ce choix déplace la frontière d'isolation vers le conteneur : exécutez donc le conteneur avec un utilisateur limité quand votre image le permet, conservez les limites de ressources de Docker et ne montez jamais de chemins de l'hôte que vous ne confieriez pas au navigateur.

Construisez l'image, puis démarrez un seul conteneur avec la taille de mémoire partagée, le processus init, un montage de profils en lecture seule, un volume de données utilisateur et le port de débogage lié à l'adresse de loopback de l'hôte.

docker build -t botbrowser:latest .
docker run -d --name botbrowser --init --shm-size=2g \
  -v "$PWD/profiles:/app/profiles:ro" \
  -v bb-data:/app/data \
  -p 127.0.0.1:9222:9222 \
  botbrowser:latest \
  --bot-profile=/app/profiles/profile.enc \
  --proxy-server=socks5://user:[email protected]:1080

La forme -p 127.0.0.1:9222:9222 compte. Un simple -p 9222:9222 publie le port sur toutes les interfaces de l'hôte, et le port de débogage à distance donne le contrôle complet du navigateur à qui l'atteint. Le lier au loopback le rend accessible depuis l'hôte uniquement, et un tunnel SSH ou un réseau interne permet de l'atteindre depuis ailleurs. La référence de docker run décrit en détail la syntaxe de publication, l'option --shm-size et --init.

L'arrêt d'un conteneur fait aussi partie de la conception. docker stop envoie SIGTERM et attend dix secondes avant d'envoyer SIGKILL. Comme l'entrypoint passe la main au navigateur avec exec, le navigateur reçoit le signal et peut fermer ses pages et écrire les données utilisateur. Si vos sessions ont besoin de plus de temps pour se terminer, augmentez le délai avec --stop-timeout ou stop_grace_period dans Compose, et étiquetez vos images avec une version plutôt que latest afin qu'un retour en arrière se résume à un changement d'étiquette.

Les identifiants du proxy dans l'exemple sont des valeurs d'exemple. Transmettez les vraies valeurs à l'exécution via votre gestionnaire de secrets, un fichier d'environnement ou les secrets Compose, et gardez-les hors de l'image et du contrôle de version.

Montez les profils et gardez les données utilisateur par instance

BotBrowser charge sa configuration depuis un fichier de profil. Dans un conteneur, la façon propre de fournir ce fichier est un montage en lecture seule, comme dans la commande ci-dessus. L'image reste la même, le profil vit sur l'hôte, et remplacer un profil revient à modifier un fichier et à redémarrer le conteneur. Personne ne reconstruit quoi que ce soit, et personne ne peut modifier le fichier depuis l'intérieur du conteneur puisque le montage est en lecture seule.

Utilisez --bot-profile quand chaque conteneur doit démarrer avec un profil précis. C'est la bonne forme pour une flotte où un conteneur a un proxy, une région et un profil choisis délibérément. Le chemin que vous passez doit correspondre au chemin dans le conteneur, et une différence entre la cible du montage et l'option est la cause la plus fréquente d'une erreur de démarrage « profil introuvable ».

Utilisez --bot-profile-dir quand un conteneur doit choisir lui-même un profil dans un répertoire. BotBrowser sélectionne un fichier .enc du répertoire à chaque démarrage. Les deux options ne peuvent pas être combinées, et si vous passez les deux, le répertoire est prioritaire. Choisissez la forme répertoire quand la variété des profils compte plus qu'un appariement fixe, et la forme fichier unique quand le profil d'un conteneur doit être connu à l'avance.

Faites correspondre le paquet de profils à la version majeure de BotBrowser. Associer un paquet de profils à une autre version majeure n'est pas ce que décrit la documentation, conservez donc un répertoire de profils par version et montez celui qui correspond à l'image. Comme les fichiers de profil sont montés et non intégrés à l'image, mettre à jour le navigateur et mettre à jour les profils sont deux étapes distinctes et réversibles.

Le fichier de profil monté, et non l'hôte du conteneur, contrôle le comportement défini par le profil. C'est une propriété utile pour l'exploitation, mais ne la lisez pas comme une promesse que toute image de base, tout noyau, tout hôte, tout proxy et tout site cible produisent le même résultat. Testez la combinaison que vous exécutez réellement et consignez dans votre dossier de déploiement l'étiquette de l'image, la version de BotBrowser et le nom du fichier de profil.

Les données utilisateur méritent le même soin. Un volume nommé par instance, comme bb-data ou bb1-data dans les exemples, conserve les cookies, le stockage local et les autres états de session entre les redémarrages tout en gardant chaque instance indépendante. Supprimez le volume seulement quand vous voulez que cette instance démarre à neuf. Pour des exécutions courtes et jetables, évitez le volume et laissez la couche inscriptible du conteneur disparaître avec lui.

Mettez à l'échelle avec Docker Compose

Compose décrit chaque instance comme un service et regroupe ports, montages, limites et comportement de redémarrage dans un seul fichier relisible. La version ci-dessous exécute deux conteneurs à partir de la même image. Chacun a son propre fichier de profil, son propre proxy, son propre volume de données utilisateur et son propre port de débogage sur l'hôte.

services:
  bb-1:
    image: botbrowser:latest
    init: true
    shm_size: 2gb
    mem_limit: 4g
    cpus: 2
    ports:
      - '127.0.0.1:9222:9222'
    volumes:
      - ./profiles:/app/profiles:ro
      - bb1-data:/app/data
    command:
      - --bot-profile=/app/profiles/profile-1.enc
      - --proxy-server=socks5://user:[email protected]:1080
    restart: unless-stopped
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:9222/json/version']
      interval: 30s
      timeout: 10s
      retries: 3
  bb-2:
    image: botbrowser:latest
    init: true
    shm_size: 2gb
    mem_limit: 4g
    cpus: 2
    ports:
      - '127.0.0.1:9223:9222'
    volumes:
      - ./profiles:/app/profiles:ro
      - bb2-data:/app/data
    command:
      - --bot-profile=/app/profiles/profile-2.enc
      - --proxy-server=socks5://user:[email protected]:1080
    restart: unless-stopped
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:9222/json/version']
      interval: 30s
      timeout: 10s
      retries: 3
volumes:
  bb1-data:
  bb2-data:

Les limites de mémoire et de CPU empêchent un conteneur incontrôlé de consommer tout l'hôte, et le contrôle de santé appelle le point de terminaison de débogage à l'intérieur du conteneur afin que Docker puisse marquer comme défaillante une instance qui ne répond plus. La politique restart: unless-stopped relance une instance tombée en panne sans que personne ne la surveille. Le pilote de journalisation par défaut de Docker conserve les journaux des conteneurs sans plafond de taille, définissez donc les options de journalisation max-size et max-file sur les services de longue durée avant qu'une instance très active ne remplisse le disque. Des limites trop serrées provoqueront les mêmes plantages qu'un petit /dev/shm, dimensionnez-les donc à partir de mesures de vos propres pages et attendez-vous à ce que les chiffres diffèrent selon les charges.

Les correspondances de ports fixes conviennent à quelques services nommés et sont mal adaptées aux réplicas. Quand vous voulez plusieurs conteneurs identiques qui choisissent chacun leur profil, supprimez le port fixe de l'hôte et laissez Docker en choisir un.

services:
  botbrowser:
    image: botbrowser:latest
    init: true
    shm_size: 2gb
    ports:
      - '127.0.0.1::9222'
    volumes:
      - ./profiles:/app/profiles:ro
    command:
      - --bot-profile-dir=/app/profiles
    restart: unless-stopped

La forme 127.0.0.1::9222 publie sur le loopback un port libre aléatoire de l'hôte pour chaque réplica. Démarrez les réplicas et listez les ports attribués avec les commandes ci-dessous. Chaque réplica a son propre système de fichiers de conteneur, ses données utilisateur lui sont donc propres et disparaissent avec lui. Si un réplica a besoin d'un état de session durable, donnez-lui un service nommé et un volume nommé comme dans le premier fichier.

docker compose up -d --scale botbrowser=3
docker compose ps

La capacité dépend de l'hôte, des pages que vous chargez et des proxys que vous utilisez. Augmentez le nombre de réplicas par paliers, surveillez la mémoire, le CPU et les redémarrages sur l'hôte, et arrêtez-vous quand la marge devient mince. Le guide d'optimisation des performances traite de la mesure, et l'article sur la configuration d'un serveur headless décrit les mêmes exigences d'affichage et de bibliothèques sur un hôte sans conteneur, ce qui aide à comparer un conteneur avec un serveur qui fonctionne déjà.

Vérifiez le conteneur et lisez les échecs courants

Un déploiement est prêt quand le navigateur démarre, que le point de terminaison de débogage répond, qu'une navigation aboutit et que les journaux ne contiennent aucune erreur de chargeur. Commencez par les journaux et le point de terminaison.

docker logs botbrowser
curl http://127.0.0.1:9222/json/version

Une bibliothèque partagée manquante apparaît dans le journal du conteneur au démarrage sous la forme d'une erreur du chargeur qui nomme le fichier, et un conteneur qui s'arrête aussitôt est presque toujours dans ce cas, ou face à un mauvais chemin de profil, ou sans affichage. Si le point de terminaison renvoie un document JSON avec la version du navigateur, le processus tourne et écoute. Lancez ensuite une navigation de test depuis l'hôte. L'extrait ci-dessous se connecte par le port de loopback et charge une page neutre.

import { chromium } from 'playwright-core';
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
const context = browser.contexts()[0];
const page = await context.newPage();
await page.goto('https://example.com');
console.log(await page.title());
await browser.close();

Afficher le titre de la page suffit. Cela prouve que l'affichage, les bibliothèques, le montage du profil et la route réseau fonctionnent ensemble, et cela vous donne une commande à répéter après chaque changement d'image. Gardez ce contrôle petit. Un test de déploiement doit confirmer que le conteneur fonctionne, et il ne doit pas chercher à mesurer le comportement d'un site tiers. Pour une vérification visuelle depuis un conteneur, Captures fiables avec un navigateur headless explique comment réaliser des captures de façon cohérente.

ProblèmeCe qu'il faut vérifier
Le conteneur s'arrête aussitôtExécutez docker logs et cherchez une bibliothèque manquante, un chemin de profil illisible ou un affichage absent
« Cannot open display »Démarrez Xvfb avant le navigateur et confirmez que DISPLAY=:10.0 est défini dans l'image
« Out of memory » ou pages qui plantentAugmentez --shm-size, puis la limite de mémoire si le conteneur lui-même est plafonné
Port 9222 inaccessible depuis l'hôteGardez --remote-debugging-address=0.0.0.0 dans le conteneur et publiez le port sur le loopback
Les processus zombies s'accumulentAjoutez --init ou init: true
Profil introuvableComparez la cible du montage au chemin de --bot-profile et utilisez docker exec pour lister le répertoire
Premier démarrage lentLe premier lancement avec un répertoire de données utilisateur vide est plus long, et les suivants le réutilisent

Considérez le port de débogage comme un risque de production. Quiconque peut s'y connecter peut lire les pages, exécuter des scripts et contrôler le navigateur : ne le publiez donc jamais sur une interface publique, placez devant lui une règle de pare-feu ou un réseau privé, et donnez à chaque conteneur son propre port. Les journaux sont l'autre endroit où la prudence s'impose. Supprimez les identifiants du proxy et les identifiants de compte avant de partager un journal hors de l'équipe.

Ce que couvre BotBrowser et ce qui reste à votre charge

BotBrowser permet de charger un fichier de profil depuis un volume monté en lecture seule avec --bot-profile, ou d'en choisir un par conteneur avec --bot-profile-dir, de sorte que chaque conteneur démarre avec la configuration définie par son profil monté et que les profils peuvent changer sans reconstruire l'image. BotBrowser ne peut pas fournir la mémoire partagée, l'affichage virtuel, les bibliothèques système, la qualité du proxy ni l'orchestration du conteneur, et il ne garantit pas qu'un site cible accepte le trafic ni que des binaires Linux soient disponibles sans forfait éligible.

Le partage ci-dessous garde les responsabilités claires quand quelque chose échoue. La première colonne indique ce que fait le navigateur avec un fichier monté. La seconde est la partie que votre équipe exploite.

Couvert par BotBrowserExploité par votre équipe
Charger un fichier de profil passé avec --bot-profileMémoire partagée, limites de CPU et de mémoire, et l'hôte
Choisir un profil dans --bot-profile-dir au démarrageL'affichage virtuel, les bibliothèques système et l'image de base
Appliquer les réglages de proxy donnés avec --proxy-serverQualité du proxy, rotation et route réseau
S'exécuter avec le répertoire de données utilisateur que vous fournissezVolumes, sauvegardes et nettoyage de l'état de session
Démarrer depuis le profil monté, sans reconstruire l'imageExposition du port de débogage, politique réseau, contrôle d'accès et orchestration

Utilisez ce tableau comme liste de contrôle pendant un incident. Un plantage qui mentionne la mémoire relève d'une limite du conteneur. Une erreur de démarrage qui nomme une bibliothèque relève de l'image. Une erreur de chemin de profil relève du montage. Aucun de ces cas n'est une question de profil de navigateur, et aucun ne se règle en changeant de profil. Laissez les résultats sur des sites précis hors de la définition de terminé du déploiement, car ils dépendent des règles du site lui-même et du trafic que vous êtes autorisé à envoyer.

Quand vous êtes prêt à construire, téléchargez BotBrowser et vérifiez que votre forfait inclut les binaires Linux. Pour une flotte plus importante, la page entreprise décrit les options de forfait. Les recettes CLI recensent les options utilisées ici et leurs combinaisons, ce qui sert quand vous étendez l'entrypoint.

Sources

Conclusion pratique

Inscrivez les cinq réglages du conteneur dans l'image et dans la commande de démarrage, pas dans un manuel que personne ne consulte : la valeur de --shm-size, l'étape Xvfb avec DISPLAY=:10.0, la base Ubuntu 22.04, --init et un volume de données utilisateur par instance. Démarrez ensuite un conteneur, montez le profil avec --bot-profile et vérifiez que le port 9222 publié sur la boucle locale répond avant de mettre le même fichier à l'échelle avec Compose.

#Docker#déploiement#serveur#automatisation#Devops

Cet article fait partie du guide : Déploiement et livraison du navigateur : carte opérationnelle

Faites passer BotBrowser de la recherche à la production

Utilisez ces guides pour comprendre le modèle, puis passez à la validation multi-plateforme, aux contextes isolés et au déploiement navigateur prêt pour l'échelle.