PlaywrightをDockerで動かすときは、公式イメージ mcr.microsoft.com/playwright を土台にし、タグの版をプロジェクトの @playwright/test とそろえ、--ipc=host と --init を付けて起動するのが基本形です。この記事では、手元での docker run、Dockerfileとcompose.yamlによる固定、GitHub Actionsのcontainer指定までをコピーして動かせる形で示し、日本語フォントやスクリーンショット差分で詰まる場面の対処も扱います。版と仕様は1.65系(2026年11月時点・npmの最新は1.65.1)の公式ドキュメントとイメージで確かめました。
まとめ:Playwright Dockerは公式イメージ・版の一致・起動フラグで決まる
- イメージ:公式の
mcr.microsoft.com/playwright:v1.65.1-nobleにはChromium・Firefox・WebKitとOS依存パッケージ、Node.js 26が入っている。Playwright本体(npmパッケージ)は入っていないのでnpm ciで入れる。 - 版の一致:タグの版と
@playwright/testの版がずれるとブラウザが見つからず起動しない。package.jsonは^を付けずに版を固定する。 - 起動フラグ:
--ipc=hostでChromiumのメモリ不足クラッシュを防ぎ、--initでゾンビプロセスを残さない。 - CI:GitHub Actionsでは
jobs.<id>.containerに公式イメージを指定すれば、毎回のplaywright install --with-depsが要らなくなる。 - 詰まり所:スクリーンショット比較の基準画像はコンテナ内で作る。明朝体はイメージに無い。Alpineは非対応。
- コンテナ化はスクリーンショット比較を使う案件と、開発者のOSがばらばらな案件で効く。Chromiumで機能テストを流すだけなら、ランナーへ直接入れる方式で足りる。
Playwright公式Dockerイメージの中身と版に合わせたタグの選び方
公式イメージはMicrosoftのコンテナレジストリ(MCR)から配布され、Docker Hubの配布ページも同じイメージを案内しています。Playwright自体の仕組みはPlaywright(プレイライト)とは?仕組み・できること・Seleniumとの違いで解説しています。
イメージに入っているブラウザとNode.js 26・OS依存パッケージの範囲
GitHubで公開されているDockerfile.nobleを読むと、ベースは ubuntu:noble(Ubuntu 24.04)で、ブラウザは環境変数 PLAYWRIGHT_BROWSERS_PATH=/ms-playwright の下にChromium・Firefox・WebKitの3種が入ります。Node.jsはNodeSourceのリポジトリから入れたものです。1.65のリリースノートには、同梱のNode.jsが24から26に上がったと書かれています。
入っていないものは2つあります。1つはPlaywrightのnpmパッケージそのもので、公式のDockerページも別途インストールが必要だと明記しています。もう1つはGoogle ChromeやMicrosoft Edgeのブランド版で、channel: 'chrome' を指定したプロジェクトはそのままでは動きません。
noble・jammy・resoluteのタグとプロジェクトの版をそろえる理由
MCRのタグ一覧(2026-11-14取得)には、1.65.1について次のタグがそろっています。
| タグ | ベースOS | 選ぶ場面 |
|---|---|---|
| v1.65.1/v1.65.1-noble | Ubuntu 24.04 LTS | 迷ったらこれ |
| v1.65.1-jammy | Ubuntu 22.04 LTS | 既存基盤が22.04 |
| v1.65.1-resolute | Ubuntu 26.04 LTS | 26.04へ移行済み |
| 末尾に-amd64/-arm64 | アーキ固定 | マルチアーキ不可の環境 |
公式ドキュメントは、イメージの版をプロジェクトのPlaywrightの版に合わせるよう求めています。ずれると、テストランナーが期待するビルド番号のブラウザが /ms-playwright に無く、実行ファイルが見つからないエラーで止まるからです。なお公式Dockerページのコマンド例は2026-11-14時点でv1.64.1のままなので、写すときは自分の版へ置き換えてください。版の確かめ方と更新手順はPlaywrightの最新バージョンの確認・更新方法で扱っています。
docker runで手元のテストをコンテナ内で実行する手順と推奨フラグ
最初の作業は、手元のプロジェクトをマウントしてコンテナの中で npx playwright test を流すことです。テストそのものの書き方や設定ファイルの作り方はPlaywrightの使い方入門:E2Eテストを初期化から実行・CIまで書く手順にまとめているので、ここでは動かす側だけを扱います。
–ipc=hostと–initを付けてコンテナ内でテストを流す
# 1. プロジェクトの版を確かめる(例:Version 1.65.1)
npx playwright --version
# 2. 同じ版のイメージでテストを実行する
docker run --rm --init --ipc=host \
-v "$(pwd)":/work \
-v /work/node_modules \
-w /work \
mcr.microsoft.com/playwright:v1.65.1-noble \
/bin/bash -c "npm ci && npx playwright test"
公式Dockerページが推奨する設定は2つです。--ipc=host を付けないとChromiumが共有メモリを使い切ってクラッシュすることがあり、--init はPID 1のプロセスが特別扱いされることによるゾンビプロセスの滞留を防ぎます。原因の分からない起動エラーが出たときは、手元の開発に限って --cap-add=SYS_ADMIN を試す手順も示されています。
3行目の -v /work/node_modules は匿名ボリュームで、ホストの node_modules をコンテナ側から隠すための指定です。これが無いと、コンテナ内の npm ci がMacやWindowsで入れた node_modules をLinux向けに上書きし、ホストに戻ったときにネイティブモジュールが動かなくなります。
ホストの開発サーバーに届かないときのhost-gateway指定とwebServer設定
playwright.config.ts の baseURL が http://localhost:3000 のままだと、コンテナ内の localhost はコンテナ自身を指すため、ホストで動かしている開発サーバーには届きません。公式Dockerページは --add-host=hostmachine:host-gateway を付け、テスト側では localhost の代わりに hostmachine を使う方法を示しています。
// playwright.config.ts(抜粋)
use: {
baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
},
# ホストのサーバーをコンテナから叩く
docker run --rm --init --ipc=host --add-host=hostmachine:host-gateway \
-e BASE_URL=http://hostmachine:3000 \
-v "$(pwd)":/work -v /work/node_modules -w /work \
mcr.microsoft.com/playwright:v1.65.1-noble \
/bin/bash -c "npm ci && npx playwright test"
設定の webServer でアプリを同じコンテナ内に起動する構成なら、この指定は要りません。
run-serverでブラウザだけをコンテナに置きホストのテストから接続
テストはホストで書きながら、描画だけLinuxのブラウザで行いたい場面もあります。公式Dockerページは、コンテナでPlaywright Serverを起動し、ホスト側のテストからWebSocketで接続する方式を案内しています。
# コンテナ側:Playwright Serverを3000番で待ち受ける
docker run -p 3000:3000 --rm --init -it --workdir /home/pwuser --user pwuser \
mcr.microsoft.com/playwright:v1.65.1-noble \
/bin/sh -c "npx -y [email protected] run-server --port 3000 --host 0.0.0.0"
# ホスト側:接続先を環境変数で渡してテストを流す
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:3000/ npx playwright test
ホストとコンテナのPlaywrightの版は、この方式でも一致が必要です。MacやWindowsの開発者が、UIモードを手元で使いつつLinux基準の描画を確かめる用途に向きます。
root実行とpwuser+seccompの使い分けはアクセス先を信頼できるかで決める
イメージの既定ユーザーはrootです。公式ドキュメントによると、rootではChromiumのサンドボックスが使えないため無効になります。自社のアプリだけを開くE2Eテストならこれで問題ありません。
外部サイトを巡回するクローラーやスクレイピングに使う場合は話が変わります。公式は、イメージ内に用意された pwuser で実行し、Dockerの既定プロファイルに clone・setns・unshare を足したseccompプロファイルを --security-opt seccomp=seccomp_profile.json で渡す構成を示しています。そもそもこのイメージはテストと開発用で、信頼できないサイトへのアクセスは推奨されていません。取得先の利用規約やrobots.txtの扱いはスクレイピングとは?クローリング・APIとの違いと実務・法務の判断で整理しています。コンテナ内で動かすPythonのスクレイピングコード(描画待ち・ページ送り・通信の直接取得)はPlaywrightスクレイピング実装ガイド:Pythonで待機・ページ送り・通信取得【1.65対応】にまとめています。
Dockerfileとcompose.yamlでテスト用コンテナを固定する構成例
毎回 npm ci を走らせる方式は手軽ですが、依存のダウンロードで毎回待たされるのが難点です。チームで使うなら、依存まで焼き込んだテスト用イメージを作り、アプリと一緒にcomposeで起動する形に固めると再現性が上がります。composeの基礎はdocker-composeとは?複数コンテナをymlで定義し一括管理する仕組みで説明しています。
公式イメージを土台にnpm ciまで焼き込むDockerfile.e2eの書き方
# Dockerfile.e2e
FROM mcr.microsoft.com/playwright:v1.65.1-noble
WORKDIR /work
COPY package.json package-lock.json ./
RUN npm ci
# 明朝体の画面を検証する場合だけ追加する
RUN apt-get update \
&& apt-get install -y --no-install-recommends fonts-ipafont-mincho \
&& rm -rf /var/lib/apt/lists/*
COPY . .
CMD ["npx", "playwright", "test"]
# .dockerignore
node_modules
playwright-report
test-results
package.jsonは "@playwright/test": "1.65.1" のように ^ を外して固定します。^1.65.1 のままだと、lockファイルを更新した時点で1.66系が入り、FROMの版とずれて起動しなくなります。版を上げるときは、FROMの行とpackage.jsonを同じコミットで変える運用にしてください。
compose.yamlでアプリとテストを同じネットワークに置きレポートを回収
# compose.yaml
services:
app:
build: .
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3000').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 5s
retries: 20
e2e:
build:
context: .
dockerfile: Dockerfile.e2e
depends_on:
app:
condition: service_healthy
environment:
BASE_URL: http://app:3000
CI: "true"
ipc: host
init: true
volumes:
- ./playwright-report:/work/playwright-report
- ./test-results:/work/test-results
# テストを流し、e2eの終了コードをそのまま返す
docker compose up --build --abort-on-container-exit --exit-code-from e2e
ipc: host と init: true が docker run のフラグに当たります。depends_on だけでは起動順しか保証されないため、healthcheckで応答を待たせました(例はアプリ側にNode.js 18以降がある前提)。レポートとトレースはボリュームでホストに戻り、npx playwright show-report で開けます。
GitHub Actionsのcontainer指定で公式イメージを使うCI組み込み
CIでは、ジョブ全体を公式イメージの中で動かす方法も選択肢です。公式のContinuous Integrationページは、ホストの環境に左右されずOSをまたいだスクリーンショット比較がそろう点を利点に挙げています。ジョブを丸ごとコンテナで動かす仕様はGitHub Docsのコンテナでジョブを実行するページで定義されています。
jobs.containerと–user 1001を指定するワークフローの全体例
# .github/workflows/playwright.yml
name: Playwright Tests (container)
on:
push:
branches: [ main ]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.65.1-noble
options: --user 1001
steps:
- uses: actions/checkout@v6
- run: npm ci
- run: npx playwright test
- uses: actions/upload-artifact@v5
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
ランナーへ直接入れる方式と比べると、actions/setup-node と npx playwright install --with-deps の2ステップが消えます。Node.jsもブラウザもイメージに入っているためです。options: --user 1001 は公式例のとおりに付けておきます。テストが落ちてもレポートを残すため、アップロードの条件は !cancelled() にしてください。
アプリのDBやRedisを同じジョブで立てたい場合は、container指定と並べて services を書けます。起動待ちの設計を含めた書き方はGitHub Actionsのサービスコンテナ(services)|DB・Redisを立てる結合テストと起動待ちの設計で扱っています。
シャード分割でワーカー1のまま実行時間を縮めるmatrix設定
公式はCIでのworkersを1にするよう勧めており、安定性と再現性を優先する立場です。テストが増えて1ジョブで終わらなくなったら、ワーカーを増やすのではなくシャード分割でジョブを横に並べます。
jobs:
test:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.65.1-noble
options: --user 1001
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v6
- run: npm ci
- run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
ブラウザのキャッシュは仕込みません。復元時間がダウンロードとほぼ同じで、LinuxではOS依存パッケージをキャッシュできないとして、公式は非推奨としています。シャードごとのレポートを1つにまとめる手順はPlaywright CLIコマンド一覧の merge-reports の項にあります。
日本語フォント・スクリーンショット差分・ARMとAlpineで詰まる場面の対処
コンテナでは、手元で起きなかった失敗が出ます。インストール自体で止まる場合はPlaywrightのインストール方法とできない時の対処の切り分けが先です。
日本語はIPAゴシックとWenQuanYiが入り明朝体は入らないフォント構成
Ubuntu 24.04向けにどのパッケージを入れるかは、nativeDeps.tsに列挙されています。フォントは fonts-ipafont-gothic・fonts-wqy-zenhei・fonts-noto-color-emoji・fonts-liberation などで、日本語のゴシック体と絵文字は描画されます。
一方で明朝体のパッケージは含まれていません。帳票やPDFのプレビューなど font-family: serif の画面は別のフォントで描かれ、文字幅が変わって折り返し位置がずれます。見た目の検証が必要な画面があるときだけ、先のDockerfile.e2eのように fonts-ipafont-mincho を足してください。ブラウザを自作イメージで入れる場合も、install に --with-deps を付けないとこれらのフォントが入らず、日本語が豆腐(□)になります。
スクリーンショット比較の基準画像をコンテナ内で生成して更新する手順
公式のVisual comparisonsページは、描画がホストのOS・版・設定・ハードウェアで変わると述べ、基準画像を生成したのと同じ環境でテストするよう求めています。基準画像のファイル名にはプラットフォーム名が入り、Macで作れば -chromium-darwin.png、コンテナなら -chromium-linux.png になります。Macで作った画像をCIのLinuxで比べても一致しません。
# 基準画像はCIと同じイメージの中で作り直す
docker run --rm --init --ipc=host \
-v "$(pwd)":/work -v /work/node_modules -w /work \
mcr.microsoft.com/playwright:v1.65.1-noble \
/bin/bash -c "npm ci && npx playwright test --update-snapshots"
生成した *-linux.png をコミットし、CIも同じタグのイメージで比べます。イメージの版を上げるとブラウザも上がり、アンチエイリアスの差で画像比較が落ちる場合があるため注意が必要です。版上げのプルリクエストでは、基準画像の更新も同時に行う運用にしておきます。
Apple SiliconのarmイメージとAlpineで起きるブラウザ起動エラー
公式イメージはamd64とarm64のマルチアーキで、Apple SiliconのMacではarm64版が使われます。CIがamd64ならブラウザのビルドが別物になるので、基準画像の作成先はCI側と同じアーキです。--platform linux/amd64 でエミュレーション実行もできますが、ネイティブより遅くなります。
Alpineなどmusl系のディストリビューションは公式に非対応です。FirefoxとWebKitがglibc向けにビルドされているためで、イメージを軽くしようとAlpineへ載せ替えると起動段階で失敗します。サイズを削りたい場合も、Ubuntu系のタグから選んでください。
コンテナで回すか直接installするか:E2E基盤の採用条件と見送る場面
すべての案件でコンテナ化が得をするわけではありません。E2Eテストの基盤を組む側から、判断の線を引いておきます。
スクリーンショット比較と開発者のOS差がある案件はコンテナ化する
コンテナ化を選ぶ条件ははっきりしています。1つ目は、toHaveScreenshot による画像比較をテストに含める案件です。基準画像を同じ環境で作るという公式の要件を満たすには、手元もCIも同じタグのイメージで動かすほかありません。2つ目は、MacとWindowsとLinuxの開発者が混在し、「手元では通るのにCIで落ちる」が週に何度も起きている案件。3つ目は、GitLab CIやJenkinsのように、Playwright公式のセットアップ手順がコンテナ前提で書かれている基盤です。
この3つのどれかに当てはまるなら、最初からDockerfile.e2eとcompose.yamlを用意し、版上げをFROMの1行に集約しておくと保守が楽になります。E2Eで守る導線の選び方はE2Eテストとは?結合テストとの違いとベストプラクティスを参照してください。
GitHub ActionsでChromiumだけを流すなら直接installで足りる
逆に、GitHub Actionsでブラウザは主にChromium、画像比較は使わず機能テストだけ、という構成ならコンテナ化は見送ります。npx playwright install --with-deps chromium で必要なものは入り、ワークフローの見通しも保てます。コンテナ内でジョブを動かすとファイルの所有者やHOMEの扱いが変わり、他のActionと組み合わせたときの切り分けが1段増えるからです。
アプリ自体をDockerで動かしていないチームも見送り側です。テストだけをコンテナに入れても、host-gatewayの設定が増えるだけで得るものが少ないからです。CIの構成からテストの運用まで外部と組む場合は、DevOps・CI/CD導入支援のように、パイプライン設計とテスト自動化をまとめて扱える体制を選ぶと、コンテナ化するかどうかの判断も含めて設計できます。アプリのイメージをCIでビルドする側の設計はGitHub ActionsでDockerイメージをビルドする方法で扱っています。
よくある質問
PlaywrightをDockerで動かすときに出やすい疑問をまとめました。
公式イメージにPlaywright本体は入っていますか?
入っていません。公式イメージに含まれるのはブラウザ(Chromium・Firefox・WebKit)とOS依存パッケージ、Node.jsで、@playwright/test などのnpmパッケージはプロジェクト側で npm ci して入れます。このとき入る版とイメージのタグの版が一致していないとブラウザが見つからないので、package.jsonの版は ^ を外して固定してください。
PythonやJavaのPlaywrightでも同じイメージを使えますか?
Node.js向けのイメージを流用するより、言語に合ったイメージを使うほうが確実です。MCRにはPython版用の mcr.microsoft.com/playwright/python も配布されており、2026-11-14時点で v1.65.0-noble などのタグがあります。Pythonで書く場合はこちらを土台にし、pipで入れるPlaywrightの版をタグに合わせます。いずれの言語でも、ライブラリの版とブラウザの版を一致させる原則は変わりません。
ヘッドありモード(headed)でコンテナ内のブラウザを表示できますか?
公式イメージにはXvfb(仮想ディスプレイ)が入っており、xvfb-run npx playwright test --headed で実行自体はできます。ただし描画先は仮想ディスプレイで、目では見えません。動きを確かめたいなら、トレースビューアで記録を開くか、run-serverの構成でホスト側のUIモードを使ってください。
コンテナで動かすとテストが遅くなりませんか?
遅くなりやすいのは2つの場面です。MacやWindowsでホストのディレクトリをマウントし、node_modulesのような小さなファイルの大量読み書きが共有ボリューム越しに起きる場合と、arm64のMacでamd64イメージをエミュレーションする場合です。依存をDockerfileに焼き込み、マウントはテストコードとレポートの出力先だけに絞ると負担が減ります。CIでは、毎回のブラウザとOS依存パッケージの導入ステップが無くなる分だけ、ジョブの前半が短くなります。
イメージの版はどのタイミングで上げればよいですか?
@playwright/testを上げるときに、Dockerfileやワークフローのタグも同じコミットで上げます。2026年11月時点の最新は1.65.1です。npmの公開直後はイメージが未配布のこともあるので、MCRに同じ版のタグがあるのを確かめてから上げてください。版の確認手順はPlaywrightの最新バージョンの確認方法にまとめています。
関連記事
- Playwrightの使い方入門:E2Eテストを初期化から実行・CIまで書く手順【1.65対応】:コンテナで流す前のテストの書き方と設定ファイルの作り方
- Playwright(プレイライト)とは?仕組み・できること・Seleniumとの違いを解説:ブラウザとテストランナーの関係を押さえる前提知識
- Playwrightのインストール方法とできない時の対処|バージョン確認・Windows・Python:コンテナを使わず直接入れる場合の導入と切り分け
- GitHub Actionsのサービスコンテナ(services)|DB・Redisを立てる結合テストと起動待ちの設計:E2EジョブにDBやRedisを並べて立てる構成
- Playwright CLIコマンド一覧|test・codegen・installと1.63の新オプション:シャードやレポート結合などコンテナ内で使うオプションの全体像