1. 简介

DevOps 流水线 中,浏览器自动化常用于执行如 运行测试爬取动态内容生成 PDF 等任务。在这些场景中,使用 Google Chrome 的 无头模式(headless) 可以让我们在没有图形界面的情况下执行浏览器操作,使自动化流程更高效、资源消耗更低。

然而,在 Docker 这类容器化环境 中运行 Chrome 并不像启动一个普通 CLI 工具那么简单。Chrome 依赖较多系统组件,在沙箱或精简环境中行为也有所不同,这使得其容器化部署更具挑战性。

本教程中,我们将介绍一种 在 Docker 容器中运行无头 Chrome 的实用方法,涵盖基础镜像选择、依赖配置、Dockerfile 编写以及常见问题处理。无论你是用于 CI/CD 的自动化测试,还是需要一个最小化的浏览器实例,本文都旨在让整个过程简单且可复现。


2. 前提条件与基础镜像选择

在 Docker 中安装 Chrome 时,选择合适的基础镜像至关重要。常见的选择包括基于 Debian 的镜像(兼容性好)或 Alpine(轻量级)。也可以使用预配置镜像(如 Chrome 或 Puppeteer)来避免手动配置。

本教程中,我们使用官方 debian:bullseye 作为基础镜像。Debian 能很好地满足 Chrome 的系统依赖,是浏览器自动化任务的理想基础。

请确保你本地已安装 Docker,并已拉取相关基础镜像,以便顺利进行后续操作。


3. 编写 Dockerfile 以运行无头 Chrome

要让 Chrome 在 Docker 中无头运行,需要正确配置 系统依赖、字体、非 root 用户权限以及 Chrome 启动参数。通过自定义 Dockerfile,我们可以精确控制镜像内容,使其干净、可控、适合自动化任务。

以下是一个基于 Debian 的基础 Dockerfile 示例:

# Dockerfile
FROM debian:bullseye

# 安装必要的系统依赖
RUN apt-get update && apt-get install -y \
    wget \
    curl \
    gnupg \
    ca-certificates \
    unzip \
    fonts-liberation \
    libappindicator3-1 \
    libasound2 \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libcups2 \
    libdbus-1-3 \
    libgdk-pixbuf2.0-0 \
    libnspr4 \
    libnss3 \
    libx11-xcb1 \
    libxcomposite1 \
    libxdamage1 \
    libxrandr2 \
    xdg-utils \
    --no-install-recommends && \
    rm -rf /var/lib/apt/lists/*

# 添加 Google Chrome 官方源并安装
RUN curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-linux-keyring.gpg && \
    echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-linux-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \
    apt-get update && apt-get install -y google-chrome-stable && \
    rm -rf /var/lib/apt/lists/*

# 创建非 root 用户
RUN useradd -m chromeuser

# 切换到非 root 用户
USER chromeuser

# 设置无头模式启动命令
ENTRYPOINT ["google-chrome", "--headless", "--no-sandbox", "--disable-gpu", "--remote-debugging-port=9222", "--disable-dev-shm-usage"]

构建并运行容器:

# 构建镜像
$ docker build -t headless-chrome .

# 启动容器
$ docker run --rm headless-chrome

✅ 常用 Chrome 无头参数说明:

  • --no-sandbox:避免容器中沙箱机制带来的兼容问题
  • --disable-dev-shm-usage:使用 /tmp 而非 /dev/shm 避免共享内存不足导致的崩溃
  • --remote-debugging-port=9222:开启远程调试端口,便于调试

4. 在容器中运行并测试无头 Chrome

构建完成后,我们可以通过截图测试验证 Chrome 是否正常运行:

docker run --rm \
  -v $PWD:/screenshots \
  headless-chrome \
  --headless \
  --disable-gpu \
  --no-sandbox \
  --screenshot=/screenshots/example.png \
  https://google.com

📌 参数说明:

  • -v $PWD:/screenshots:将当前目录挂载到容器内的 /screenshots
  • --screenshot=...:指定截图输出路径
  • https://google.com:截图目标网页

该测试验证了 Chrome 是否成功加载页面并写入文件,确保其在容器中运行正常。


5. 集成到 CI/CD 流水线

Chrome 能在 Docker 中稳定运行后,下一步是将其集成到 CI/CD 流水线 中,用于自动化测试、截图、前端验证等任务。大多数 CI 工具(如 GitHub Actions)都支持 Docker,集成非常方便。

✅ GitHub Actions 示例

# .github/workflows/chrome-test.yml
name: Run Chrome Headless Test

on: [push]

jobs:
  headless-test:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
        
      - name: Set up Docker
        run: sudo apt-get update && sudo apt-get install -y docker.io
        
      - name: Build Chrome Docker image
        run: docker build -t headless-chrome .
        
      - name: Run screenshot test
        run: |
          mkdir screenshots
          docker run --rm \
            -v ${{ github.workspace }}/screenshots:/screenshots \
            headless-chrome \
            --headless \
            --disable-gpu \
            --no-sandbox \
            --screenshot=/screenshots/test.png \
            https://google.com
            
      - name: Upload screenshot artifact
        uses: actions/upload-artifact@v3
        with:
          name: screenshot
          path: screenshots/test.png

该流程会自动构建镜像、运行截图测试,并将截图上传为构建产物,便于后续分析。


6. 总结

本文介绍了如何在 Docker 容器中运行无头模式的 Google Chrome,涵盖了基础镜像选择、依赖配置、Dockerfile 编写以及在 CI/CD 中的集成方法。

通过合理的配置,我们可以在容器中稳定运行 Chrome,避免常见依赖问题,并将其无缝集成到自动化流程中。无论是前端测试、截图验证还是爬虫任务,该方案都能带来更高的灵活性与效率。

完整代码可参考 GitHub 仓库:headless-google-chrome 示例(示例地址,请根据实际项目替换)


原始标题:Run Google Chrome headless in Docker