14 KiB
Docker 与容器
使用场景:在容器中运行 Playwright 测试,以获得可复现的环境、用于 CI 流水线,或使用一致的浏览器版本进行本地开发。当团队需要在不同机器上拥有相同的测试环境时,此模式必不可少。
快速参考
# 官方 Playwright Docker 镜像
docker pull mcr.microsoft.com/playwright:v1.52.0-noble # Ubuntu 24.04,包含所有浏览器
docker pull mcr.microsoft.com/playwright:v1.52.0-jammy # Ubuntu 22.04,包含所有浏览器
# 在容器中运行测试
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/playwright:v1.52.0-noble \
npx playwright test
# 检查你的 Playwright 版本(必须与镜像标签一致)
npx playwright --version
模式
模式 1:在官方镜像中运行测试
适用场景:快速、可复现的测试运行,无需构建自定义镜像。 不适用场景:需要应用服务(数据库、API)同时运行——改用 docker-compose。
# 运行所有测试
docker run --rm \
-v $(pwd):/app \
-w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"
# 使用环境变量运行
docker run --rm \
-v $(pwd):/app \
-w /app \
-e CI=true \
-e BASE_URL=http://host.docker.internal:3000 \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"
# 运行并提取报告
docker run --rm \
-v $(pwd):/app \
-w /app \
-v $(pwd)/playwright-report:/app/playwright-report \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"
模式 2:自定义 Dockerfile
适用场景:需要额外的系统依赖、预装的 npm 包,或仅包含特定浏览器的更小镜像。 不适用场景:官方镜像开箱即用。
# Dockerfile.playwright
FROM mcr.microsoft.com/playwright:v1.52.0-noble
WORKDIR /app
# 先复制包文件,以便更好地利用层缓存
COPY package.json package-lock.json ./
RUN npm ci
# 复制项目其余部分
COPY . .
# 默认命令
CMD ["npx", "playwright", "test"]
# 构建并运行
docker build -f Dockerfile.playwright -t my-e2e-tests .
docker run --rm my-e2e-tests
# 使用特定选项运行
docker run --rm my-e2e-tests npx playwright test --project=chromium
# 提取报告
docker run --rm -v $(pwd)/reports:/app/playwright-report my-e2e-tests
仅含 Chromium 的精简镜像:
# Dockerfile.playwright-chromium
FROM node:20-slim
# 仅安装 Chromium 依赖
RUN npx playwright install --with-deps chromium
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["npx", "playwright", "test", "--project=chromium"]
模式 3:Docker Compose 与应用栈
适用场景:测试需要完整的应用栈——Web 服务器、数据库、缓存以及 Playwright 一起运行。 不适用场景:测试针对远程环境(预发布/生产环境)运行——不需要本地服务。
# docker-compose.yml
services:
# 被测应用
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=test
- DATABASE_URL=postgresql://postgres:postgres@db:5432/test
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
# 数据库
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
tmpfs:
- /var/lib/postgresql/data # 使用内存盘提升速度
# 缓存
cache:
image: redis:7-alpine
# Playwright 测试运行器
e2e:
image: mcr.microsoft.com/playwright:v1.52.0-noble
working_dir: /app
volumes:
- .:/app
- /app/node_modules # 阻止宿主机的 node_modules 覆盖容器内的
environment:
- CI=true
- BASE_URL=http://app:3000
depends_on:
- app
command: bash -c "npm ci && npx playwright test"
profiles:
- test # 仅通过以下命令启动:docker compose --profile test up
# 启动完整栈并运行测试
docker compose --profile test up --abort-on-container-exit --exit-code-from e2e
# 仅启动应用(用于本地开发)
docker compose up app
# 对已运行的服务栈运行测试
docker compose --profile test run --rm e2e npx playwright test
# 拆除所有资源
docker compose --profile test down -v
模式 4:从容器的容器中提取报告与 Trace
适用场景:容器测试完成后,需要在宿主机上获取测试产物(HTML 报告、trace、截图)。 不适用场景:CI 原生负责产物收集(GitHub Actions、GitLab 制品)。
# 方法 1:绑定挂载输出目录
docker run --rm \
-v $(pwd):/app \
-v $(pwd)/playwright-report:/app/playwright-report \
-v $(pwd)/test-results:/app/test-results \
-w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"
# 方法 2:从已停止的容器中复制产物
docker run --name e2e-run \
-v $(pwd):/app \
-w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test" || true
docker cp e2e-run:/app/playwright-report ./playwright-report
docker cp e2e-run:/app/test-results ./test-results
docker rm e2e-run
# 查看报告
npx playwright show-report ./playwright-report
Docker Compose 报告提取:
# docker-compose.yml(添加到 e2e 服务)
services:
e2e:
image: mcr.microsoft.com/playwright:v1.52.0-noble
working_dir: /app
volumes:
- .:/app
- ./playwright-report:/app/playwright-report
- ./test-results:/app/test-results
# ... 其余配置
模式 5:CI 容器策略
适用场景:你的 CI 环境受益于容器化的测试执行。
GitHub Actions —— 容器作业:
# .github/workflows/playwright.yml
jobs:
test:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.52.0-noble
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright test
env:
HOME: /root
GitLab CI —— image 指令:
# .gitlab-ci.yml
test:
image: mcr.microsoft.com/playwright:v1.52.0-noble
script:
- npm ci
- npx playwright test
Jenkins —— Docker 代理:
// Jenkinsfile
pipeline {
agent {
docker {
image 'mcr.microsoft.com/playwright:v1.52.0-noble'
args '-u root'
}
}
stages {
stage('Test') {
steps {
sh 'npm ci'
sh 'npx playwright test'
}
}
}
}
模式 6:开发容器(devcontainer)
适用场景:你的团队使用 VS Code 开发容器或 GitHub Codespaces,并且需要在开发环境中使用 Playwright。 不适用场景:每个人都在本地安装 Playwright,且版本差异不会引发问题。
// .devcontainer/devcontainer.json
{
"name": "Playwright Dev",
"image": "mcr.microsoft.com/playwright:v1.52.0-noble",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
}
},
"postCreateCommand": "npm ci",
"customizations": {
"vscode": {
"extensions": ["ms-playwright.playwright"]
}
},
"forwardPorts": [3000, 9323],
"remoteUser": "root"
}
决策指南
| 场景 | 方案 | 原因 |
|---|---|---|
| 简单 CI 流水线 | 将官方 Playwright 镜像作为 CI 镜像 | 浏览器已预装;零浏览器安装时间 |
| 测试需要数据库 + 缓存 | 使用 Docker Compose 提供 app、db、cache、e2e 服务 | 完整服务栈在隔离容器中运行 |
| 团队需要相同的环境 | 开发容器或自定义 Dockerfile | 消除"在我机器上能跑"的问题 |
| 仅测试 Chromium | 精简镜像:node:20-slim + install --with-deps chromium |
镜像更小,拉取更快 |
| 跨浏览器测试 | 官方 Playwright 镜像(包含所有浏览器) | 三大引擎已预装 |
| 本地开发 | 直接在宿主机上运行,不在容器中 | 迭代更快,调试更方便 |
| 需要提取产物的 CI | 绑定挂载报告/结果目录,或使用 CI 制品上传 | 容器退出后报告仍可访问 |
| 镜像 | 大小 | 浏览器 | 基础操作系统 |
|---|---|---|---|
mcr.microsoft.com/playwright:v1.52.0-noble |
~2 GB | Chromium, Firefox, WebKit | Ubuntu 24.04 |
mcr.microsoft.com/playwright:v1.52.0-jammy |
~2 GB | Chromium, Firefox, WebKit | Ubuntu 22.04 |
| 自定义精简版(仅 Chromium) | ~800 MB | Chromium | 取决于基础镜像 |
反模式
| 反模式 | 问题 | 正确做法 |
|---|---|---|
镜像标签与 @playwright/test 版本不匹配 |
浏览器二进制文件与 Playwright 库不兼容 | 始终匹配:v1.52.0 镜像对应 @playwright/test@1.52.0 |
使用 latest 标签 |
不可预测;镜像更新可能破坏测试 | 锁定到确切版本:v1.52.0-noble |
| 在容器运行时安装浏览器 | 每次运行浪费 60-90 秒 | 使用官方镜像(浏览器预装)或构建预装浏览器的自定义镜像 |
| 以非 root 用户运行且未配置沙箱 | Chromium 沙箱因权限错误失败 | 以 root 运行(-u root)或在启动参数中禁用沙箱(--no-sandbox) |
从宿主机绑定挂载 node_modules |
平台相关二进制文件(macOS vs Linux)导致崩溃 | 使用匿名卷:-v /app/node_modules |
| 依赖服务没有健康检查 | 数据库就绪前测试就已启动 | 为 db 服务添加 healthcheck;使用 depends_on: condition: service_healthy |
| 在 Playwright 容器内部构建应用 | 镜像庞大、构建缓慢、基础镜像不适合你的应用 | 在 docker-compose 中将应用和 e2e 容器分离 |
故障排除
容器中报错 "browserType.launch: Executable doesn't exist"
原因:package.json 中的 Playwright 版本与 Docker 镜像版本不匹配。
修复:确保版本精确匹配:
# 检查你的版本
npm ls @playwright/test
# @playwright/test@1.52.0
# 使用匹配的镜像
docker pull mcr.microsoft.com/playwright:v1.52.0-noble
docker-compose 中测试失败,报错 "net::ERR_CONNECTION_REFUSED"
原因:测试尝试访问 localhost:3000,但应用在另一个容器中。
修复:使用服务名称作为主机名,并配置 baseURL:
// playwright.config.ts
import { defineConfig } from "@playwright/test"
export default defineConfig({
use: {
baseURL: process.env.BASE_URL || "http://localhost:3000",
},
// 在 Docker 中禁用 webServer——应用由 docker-compose 管理
...(process.env.CI
? {}
: {
webServer: {
command: "npm run dev",
url: "http://localhost:3000",
reuseExistingServer: true,
},
}),
})
# docker-compose.yml
e2e:
environment:
- BASE_URL=http://app:3000 # "app" 是服务名称
挂载卷权限被拒绝
原因:容器以 root 运行,但宿主机文件归你的用户所有,或反之。
修复:匹配用户 ID 或以 root 运行:
# 以宿主机用户身份运行
docker run --rm -u $(id -u):$(id -g) \
-v $(pwd):/app -w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
npx playwright test
# 或以 root 运行(更简单,CI 中适用)
docker run --rm \
-v $(pwd):/app -w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
npx playwright test
容器测试比本地慢得多
原因:macOS/Windows 上的 Docker Desktop 对绑定挂载卷存在 I/O 开销。
修复:将文件复制到容器内部,而非挂载:
# Dockerfile.playwright
FROM mcr.microsoft.com/playwright:v1.52.0-noble
WORKDIR /app
COPY . .
RUN npm ci
CMD ["npx", "playwright", "test"]
或在 macOS 上使用 delegated 挂载:
docker run --rm \
-v $(pwd):/app:delegated \
-w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"
相关文档
- ci/ci-github-actions.md —— GitHub Actions 中的容器作业
- ci/ci-gitlab.md —— GitLab CI 中的 Docker 镜像
- ci/ci-other.md —— Jenkins、CircleCI 中的 Docker 代理
- ci/parallel-and-sharding.md —— 容器内的分片
- ci/reporting-and-artifacts.md —— 从容器的容器中提取报告