返回博客
部署

BotBrowser 的 Docker 部署指南

在 Docker 容器中部署 BotBrowser 的最佳实践:Dockerfile 示例、Compose 扩容、卷挂载与生产环境加固。

介绍

Docker 提供了生产级 BotBrowser 部署所需的可重复性、隔离与扩展原语。每个容器从已知状态启动,独立运行,并且可以在支持 Docker 的任何基础设施上复制。这样就消除了“在我机器上可以运行”的问题。

本指南涵盖完整的 Docker 部署工作流:构建镜像、通过卷挂载管理配置文件与脚本、配置共享内存、使用 Docker Compose 扩展以及应用生产硬化。无论是在本地运行单容器,还是在云端编排数十个工作进程,这些模式均适用。

为什么需要 Docker 部署

BotBrowser 依赖特定的系统库、虚拟显示服务以及谨慎的环境配置。在裸机上,每台新服务器都需要相同的手动设置:安装依赖、配置 Xvfb、设置环境变量并验证安装。Docker 将这些打包到单个镜像中,保证在各处部署一致。

Docker 还提供进程隔离。每个容器运行独立的 BotBrowser 实例并拥有自己的文件系统、网络命名空间和资源限制。单个容器的内存泄漏不会影响其他容器。崩溃的工作进程可由 Docker 的重启策略自动重启,无需人工干预。

对于需要不同配置文件和代理的多实例团队,Docker Compose 或容器编排平台可以通过单一配置文件方便地定义、扩展和管理整个集群。

技术背景

Chrome 与共享内存

Chrome 大量使用 /dev/shm(共享内存)在浏览器进程、GPU 进程和渲染进程间进行 IPC。Docker 默认的 /dev/shm 分配为 64 MB,远远不足。Chrome 在没有至少 1-2 GB 共享内存的情况下会崩溃或行为异常。

解决办法很简单:在 docker run 添加 --shm-size=2g,或在 Docker Compose 中设置 shm_size: '2g'

容器中的显示服务器

与裸机服务器类似,容器内的 BotBrowser 需要 Xvfb 来初始化显示。容器必须在启动 Chrome 之前启动 Xvfb,并设置 DISPLAY 环境变量。

用户数据目录

每个 BotBrowser 实例都需要自己的 --user-data-dir。在 Docker 中,默认该目录位于容器内,容器停止时会丢失。若需持久会话,请挂载主机卷以在容器重启间保留浏览器状态。

镜像体积考量

包含所有依赖的 BotBrowser Docker 镜像通常在 500-800 MB 之间。使用多阶段构建或精简包列表可以减小体积,但缺失的库可能在运行时导致失败。

Docker Container Xvfb :10 Virtual Display BotBrowser Chrome + Profile Node.js Automation Script /dev/shm 2 GB Shared Mem Volume: /opt/profiles (host mounted) Volume: /data/sessions (persistent)

常见方法及局限

单一单体容器

在一个容器中运行所有组件(Xvfb、BotBrowser、自动化脚本与监控)是最简单的方法,但限制了可扩展性。无法独立扩展自动化脚本,且任何组件的问题都会导致整个容器停止。

每浏览器一个容器

为每个 BotBrowser 实例运行一个容器提供了最佳隔离。每个容器有自己的配置文件、代理和用户数据目录。开销更高(每个容器包含完整的系统库),但隔离让调试与扩展更容易。

Sidecar 模式

某些部署使用运行 Xvfb 的 sidecar 容器供多个浏览器容器共享。这减少了资源使用,但增加了网络复杂性并引入单点故障。

基于 Chromium 官方镜像构建

使用 Google 的 Chromium 官方 Docker 镜像作为基础可以减少搭建工作,但这些镜像可能缺少 BotBrowser 需要的所有库。从 Ubuntu 构建可对依赖列表有更精细的控制。

BotBrowser 的方法

BotBrowser 的跨平台配置文件系统非常适合 Docker 部署。相同的配置文件无论容器基础镜像、内核版本或主机机器如何,都会产生相同的指纹,消除了容器化浏览器部署中常见的不一致来源。

推荐的容器化策略使用 Ubuntu 22.04 作为基础,安装所有所需依赖,将 BotBrowser 二进制和配置文件复制进镜像,并在自动化脚本之前启动 Xvfb。该方案经过测试,可靠并在不同云提供商间产生一致结果。

配置与使用

基础 Dockerfile

FROM ubuntu:22.04

# Install system dependencies
RUN apt-get update && apt-get install -y \
    wget ca-certificates fonts-liberation \
    libasound2 libatk-bridge2.0-0 libatk1.0-0 \
    libcups2 libdbus-1-3 libdrm2 libgbm1 \
    libgtk-3-0 libnspr4 libnss3 \
    libxcomposite1 libxdamage1 libxrandr2 \
    xdg-utils xvfb curl \
    && rm -rf /var/lib/apt/lists/*

# Install Node.js
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
    && apt-get install -y nodejs \
    && rm -rf /var/lib/apt/lists/*

# Set display environment
ENV DISPLAY=:10.0

# Copy BotBrowser binary
COPY botbrowser/ /opt/botbrowser/
RUN chmod +x /opt/botbrowser/chrome

# Copy profiles
COPY profiles/ /opt/profiles/

# Copy automation scripts
WORKDIR /opt/app
COPY package.json package-lock.json ./
RUN npm ci --production
COPY scripts/ ./scripts/

# Health check
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
  CMD pgrep -x Xvfb && pgrep -f "chrome" || exit 1

# Start Xvfb and run the automation script
CMD Xvfb :10 -screen 0 1920x1080x24 -ac & \
    sleep 1 && \
    node scripts/main.js

构建与运行

docker build -t botbrowser-worker .
docker run --rm --shm-size=2g botbrowser-worker

需要 --shm-size=2g 标志;没有该设置,Chrome 会因共享内存不足而崩溃或行为异常。

自动化脚本

// scripts/main.js
const { chromium } = require('playwright-core');

const PROFILE = process.env.PROFILE || '/opt/profiles/profile.enc';
const PROXY = process.env.PROXY || '';

async function main() {
  const args = [
    '--disable-setuid-sandbox',
    `--bot-profile=${PROFILE}`,
  ];

  if (PROXY) {
    args.push(`--proxy-server=${PROXY}`);
  }

  const browser = await chromium.launch({
    executablePath: '/opt/botbrowser/chrome',
    args: args,
    headless: true,
  });

  try {
    const context = await browser.newContext();
    const page = await context.newPage();
    await page.goto('https://example.com');
    console.log('Title:', await page.title());

    // Your automation logic here

  } finally {
    await browser.close();
  }
}

// Handle graceful shutdown
process.on('SIGTERM', async () => {
  console.log('Received SIGTERM, shutting down...');
  process.exit(0);
});

process.on('SIGINT', async () => {
  console.log('Received SIGINT, shutting down...');
  process.exit(0);
});

main().catch(console.error);

用于多个工作进程的 Docker Compose

version: '3.8'

services:
  worker-us:
    build: .
    shm_size: '2g'
    environment:
      - PROFILE=/opt/profiles/windows-chrome-131.enc
      - PROXY=socks5://user:pass@us-proxy.example.com:1080
    volumes:
      - ./profiles:/opt/profiles:ro
      - session-us:/data/session
    deploy:
      resources:
        limits:
          memory: 4g
          cpus: '2'
    restart: unless-stopped

  worker-eu:
    build: .
    shm_size: '2g'
    environment:
      - PROFILE=/opt/profiles/windows-chrome-132.enc
      - PROXY=socks5://user:pass@eu-proxy.example.com:1080
    volumes:
      - ./profiles:/opt/profiles:ro
      - session-eu:/data/session
    deploy:
      resources:
        limits:
          memory: 4g
          cpus: '2'
    restart: unless-stopped

volumes:
  session-us:
  session-eu:

启动集群:

docker compose up -d
docker compose logs -f

扩展特定 worker:

docker compose up -d --scale worker-us=3

卷挂载

将配置文件挂载为只读卷,以便无需重建镜像即可更新:

docker run --rm --shm-size=2g \
  -v /host/profiles:/opt/profiles:ro \
  -v /host/sessions/worker-1:/data/session \
  -e PROFILE=/opt/profiles/profile.enc \
  -e PROXY=socks5://user:pass@proxy:1080 \
  botbrowser-worker

环境变量

在容器中使用环境变量进行按容器配置:

变量描述示例
PROFILE容器内配置文件路径/opt/profiles/win-chrome-131.enc
PROXY带凭证的代理 URLsocks5://user:pass@proxy:1080
DISPLAYX 显示(在 Dockerfile 中设置):10.0

Entrypoint 脚本

对于更复杂的启动逻辑,使用 entrypoint 脚本:

#!/bin/bash
# entrypoint.sh

# Start Xvfb
Xvfb :10 -screen 0 1920x1080x24 -ac &
XVFB_PID=$!

# Wait for Xvfb to be ready
for i in $(seq 1 10); do
  if xdpyinfo -display :10 > /dev/null 2>&1; then
    break
  fi
  sleep 0.5
done

# Run the main script
exec node /opt/app/scripts/main.js

更新 Dockerfile:

COPY entrypoint.sh /opt/app/
RUN chmod +x /opt/app/entrypoint.sh
ENTRYPOINT ["/opt/app/entrypoint.sh"]

验证

验证你的 Docker 设置:

# Build the image
docker build -t botbrowser-worker .

# Run with interactive shell for debugging
docker run --rm --shm-size=2g -it botbrowser-worker bash

# Inside the container:
Xvfb :10 -screen 0 1920x1080x24 &
export DISPLAY=:10.0
/opt/botbrowser/chrome --version
ldd /opt/botbrowser/chrome | grep "not found"

不应出现 "not found" 行。运行一次测试导航:

docker run --rm --shm-size=2g botbrowser-worker

检查输出是否包含预期的页面标题且无错误信息。

最佳实践

始终设置 --shm-size=2g 或更高。 这是 Docker + Chrome 最常见的问题,默认 64 MB 不足。

在容器中使用 --disable-setuid-sandbox Docker 容器通常缺少 Chrome 沙箱所需的内核能力。

将配置文件挂载为只读卷。 将配置文件的更新从镜像构建中分离,防止意外修改。

设置资源限制。 使用 Docker 的 --memory--cpus 标志防止单个容器耗尽主机资源。

处理 SIGTERM 实现优雅关闭。 Docker 停止容器时会发送 SIGTERM,脚本应关闭浏览器并清理资源。

使用 .dockerignore 在构建上下文中排除 node_modules.git 与本地开发文件以减小镜像与构建时间。

为镜像打标签版本号。 使用 botbrowser-worker:1.2.0 而非 :latest 来实现可重现的部署。

常见问题

为什么 Chrome 在 Docker 中报 "out of memory"?

最常见原因是 /dev/shm 大小不足。为容器添加 --shm-size=2g。如果容器本身受到内存限制,请使用 --memory=4g 提高内存限制。

我能用 Alpine 替代 Ubuntu 吗?

Chrome 依赖基于 glibc 的库,而 Alpine 使用 musl libc,这通常不兼容。请使用 Debian/Ubuntu 系列镜像。

如何在不重建镜像的情况下更新配置文件?

将配置文件目录挂载为卷:-v /host/profiles:/opt/profiles:ro,在主机上更新文件并重启容器。

我可以暴露远程调试端口吗?

可以。使用 -p 9222:9222 并在 Chrome 启动参数中添加 --remote-debugging-port=9222。生产环境中务必谨慎,因为调试端口可完全控制浏览器。

如何查看容器日志?

使用 docker logs <container-id>docker compose logs <service-name>。脚本中的 console.log 输出会显示在这里。

我应使用哪个基础镜像?

Ubuntu 22.04 LTS 是最常测试且可靠的选择。Ubuntu 24.04 亦可,但需调整软件包名称。Debian 12(Bookworm)也是稳健的选择。

我可以在一个容器中运行多个 BotBrowser 实例吗?

可以,但单独容器能提供更好的隔离和资源管理。如果在一个容器中运行多个实例,确保每个实例使用独立的 --user-data-dir--remote-debugging-port

如何处理 Chrome 僵尸进程?

docker run 添加 --init 以使用 Docker 的 init 进程回收孤儿子进程;或在 Dockerfile 中使用 dumb-inittini

总结

Docker 提供了在生产中部署 BotBrowser 最可靠且可重复的方式。一次构建镜像,使用卷挂载保存配置与持久数据,并通过 Docker Compose 或编排工具进行扩展。关键配置要求是足够的共享内存(--shm-size=2g)。

有关裸机部署,请参见 Headless Server Setup。有关性能调优,请参见 Optimizing BotBrowser Performance。有关 CLI 标志参考,请参见 CLI Recipes

title: "BotBrowser Docker 部署指南" description: "在 Docker 容器中部署 BotBrowser,实现可复现、隔离的大规模浏览器自动化。" date: "2026-01-07" locale: zh category: deployment tags: ["docker", "deployment", "server", "automation", "devops"] published: true

概述

Docker 为 BotBrowser 部署提供可复现的环境、进程隔离和便捷的扩展能力。每个容器从干净状态启动,独立运行。

Dockerfile

FROM ubuntu:22.04

RUN apt-get update && apt-get install -y \
    wget ca-certificates fonts-liberation \
    libasound2 libatk-bridge2.0-0 libatk1.0-0 \
    libcups2 libdbus-1-3 libdrm2 libgbm1 \
    libgtk-3-0 libnspr4 libnss3 \
    libxcomposite1 libxdamage1 libxrandr2 \
    xdg-utils xvfb \
    && rm -rf /var/lib/apt/lists/*

ENV DISPLAY=:10.0

COPY botbrowser/ /opt/botbrowser/
COPY profiles/ /opt/profiles/
RUN chmod +x /opt/botbrowser/chrome

COPY scripts/ /opt/scripts/

CMD Xvfb :10 -screen 0 1920x1080x24 & \
    sleep 1 && \
    node /opt/scripts/main.js

构建和运行

docker build -t botbrowser-worker .
docker run --rm --shm-size=2g botbrowser-worker

--shm-size=2g 参数很重要。Chrome 使用 /dev/shm 做共享内存,Docker 默认分配(64MB)太小。

自动化脚本

// /opt/scripts/main.js
const { chromium } = require('playwright-core');

(async () => {
  const browser = await chromium.launch({
    executablePath: '/opt/botbrowser/chrome',
    args: [
      '--disable-setuid-sandbox',
      '--bot-profile=/opt/profiles/profile.enc',
    ],
    headless: true,
    defaultViewport: null,
  });

  const page = await (await browser.newContext()).newPage();
  await page.goto('https://example.com');
  console.log(await page.title());
  await browser.close();
})();

Docker Compose 扩展

version: '3.8'
services:
  worker-1:
    build: .
    shm_size: '2g'
    environment:
      - PROFILE=/opt/profiles/profile-1.enc
      - PROXY=socks5://proxy1:1080
  worker-2:
    build: .
    shm_size: '2g'
    environment:
      - PROFILE=/opt/profiles/profile-2.enc
      - PROXY=socks5://proxy2:1080

生产最佳实践

资源限制。 docker run --memory=4g --cpus=2 --shm-size=2g botbrowser-worker

健康检查。 添加到 Dockerfile:HEALTHCHECK --interval=30s --timeout=10s --retries=3 CMD pgrep chrome || exit 1

优雅关闭。 在脚本中处理 SIGTERM:

process.on('SIGTERM', async () => {
  await browser.close();
  process.exit(0);
});

故障排除

"Out of memory" 崩溃:将 --shm-size 增加到至少 2g。

"Cannot open display":确保 Xvfb 正在运行且 DISPLAY 已设置。

"Permission denied":使用 --disable-setuid-sandbox

开始使用

  1. GitHub 下载 BotBrowser
  2. 使用上述 Dockerfile 构建 Docker 镜像
  3. 为每个容器挂载配置文件并配置代理
#docker#deployment#server#automation#devops