Edited at

Dockerを使ってHeadless Chromeを動かしてみる

Chrome 59からChromeをヘッドレス環境で実行するHeadless Chromeが搭載されました。

自動テスト等でこの機能を使えると便利そうな気がしたので、DockerでHeadless Chrome

が使える環境を整えてみます。


Docker Imageの作成

alpine linuxにはgoogle chromeのパッケージはありません。chromeの元となるオープンソース実装のchromiumのpackageを検索してみると、最新版のchromiumが59.0.3071.86-r0

なっています。

これを利用すればHeadlessで動かすことが出来そうなので、今回はこのパッケージを

利用してみました。Branchがedgeとなっていますので、alpine linuxのイメージを

edgeのものを使用しました。


Dockerfile

From alpine:edge

RUN apk add --update chromium

ENTRYPOINT tail -f /dev/null


まずはchromiumをインストールしたImageを作成します。

$ docker build -t chromium_headless ./

Sending build context to Docker daemon 2.048 kB
Step 1/3 : FROM alpine:edge
---> 1673780955f9
Step 2/3 : RUN apk add --update chromium
---> Running in de86344e5110
fetch http://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/edge/community/x86_64/APKINDEX.tar.gz
(1/78) Installing libxau (1.0.8-r1)
(2/78) Installing libbsd (0.8.3-r3)
...
(78/78) Installing chromium (59.0.3071.86-r0)
Executing busybox-1.26.2-r4.trigger
Executing glib-2.52.1-r0.trigger
Executing shared-mime-info-1.8-r0.trigger
Executing gdk-pixbuf-2.36.6-r0.trigger
Executing gtk-update-icon-cache-2.24.31-r0.trigger
OK: 260 MiB in 89 packages
---> 2e0a5a6babb5
Removing intermediate container 92491faa6417
Step 3/3 : ENTRYPOINT tail -f /dev/null
---> Running in 87ea1b256a97
---> 2772165613b3
Removing intermediate container 87ea1b256a97
Successfully built 2772165613b3


動作確認

イメージの作成が完了したので、コンテナを起動して、chromiumの動作を確認します。

$ docker run -d chromium_headless

b839da3b3b34964390a50c0747df475204977979e3d5192ccc98ec7d3643d66d
$ docker exec -it b83 ash
/ # chromium-browser --version
Chromium 59.0.3071.86
/ # chromium-browser --headless --disable-gpu --dump-dom --no-sandbox https://www.chromestatus.com/
[0613/121607.247566:WARNING:dns_config_service_posix.cc(326)] Failed to read DnsConfig.
[0613/121607.257087:FATAL:udev_loader.cc(38)] Check failed: false.
Received signal 6
r8: 0000000000000061 r9: 00007fcf9c22a066 r10: 0000000000000008 r11: 0000000000000246
r12: 00007fcf9c229ed0 r13: 00007fcf9c229e80 r14: 0000000000000000 r15: 0000000000000000
di: 0000000000000002 si: 00007fcf9c229da0 bp: 00007fcf9c229da0 bx: 0000000000000006
dx: 0000000000000000 ax: 0000000000000000 cx: 00007fcfb09e86bf sp: 00007fcf9c229d88
ip: 00007fcfb09e86bf efl: 0000000000000246 cgf: 002b000000000033 erf: 0000000000000000
trp: 0000000000000000 msk: 0000000000000000 cr2: 0000000000000000
[end of stack trace]
Calling _exit(1). Core file will not be generated.

chromiumのバージョンまでは表示することが出来て、無事にインストールされていることが確認出来ましたが、

Headlessで起動すると上記のようなエラーが出てしまいました。このエラーを確認する限りudevのパッケージの必要なようです。

最終的にttf-freefontも必要で、以下のようなDockerfileになりました。


Dockerfile

From alpine:edge

RUN apk add --update \
udev \
ttf-freefont \
chromium

ENTRYPOINT tail -f /dev/null


イメージをビルドして、もう動作を確認すると以下のような結果になり、Headlessで動くことが確認できました。

/ # chromium-browser --headless --disable-gpu --dump-dom --no-sandbox https://www.chromestatus.com/

[0613/124631.067381:WARNING:dns_config_service_posix.cc(326)] Failed to read DnsConfig.
<body class="loading">

<!--<div id="site-banner">
<a href="https://www.youtube.com/watch?v=Rd0plknSPYU" target="_blank">
<iron-icon icon="chromestatus:ondemand-video"></iron-icon> How we built it</a>
</div>-->
...
// End Google Analytics

lazyLoadWCPolyfillsIfNecessary();
</script>

</body>

pdfの出力とスクリーンショットの取得も試してみましたが、正常に動作していることが確認出来ました。

/ # mkdir outputs && cd outputs

/outputs # chromium-browser --headless --no-sandbox --disable-gpu --print-to-pdf https://www.chromestatus.com
[0613/125229.869694:WARNING:dns_config_service_posix.cc(326)] Failed to read DnsConfig.
[0613/125231.380375:INFO:headless_shell.cc(436)] Written to file output.pdf.
/outputs # chromium-browser --headless --no-sandbox --disable-gpu --screenshot https://www.chromestatus.com
[0613/125243.355846:WARNING:dns_config_service_posix.cc(326)] Failed to read DnsConfig.
[0613/125244.919023:INFO:headless_shell.cc(436)] Written to file screenshot.png.
/outputs # ls
output.pdf screenshot.png


日本語フォントの追加

前段までの手順でスクリーンショットを取ることは出来ましたが、このままですと

日本語が表示されているサイトのスクリーンショットをとっても日本語の部分が

文字化けした状態でスクリーンショットになってしまいます。

Google Noto Fontsを入れることで日本語を含むサイトでも、文字化けせずに

スクリーンショットが取れるようになります。


Dockerfile

From alpine:edge

RUN apk add --update \
udev \
ttf-freefont \
chromium

RUN mkdir /noto

ADD https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip /noto

WORKDIR /noto

RUN unzip NotoSansCJKjp-hinted.zip && \
mkdir -p /usr/share/fonts/noto && \
cp *.otf /usr/share/fonts/noto && \
chmod 644 -R /usr/share/fonts/noto/ && \
fc-cache -fv

WORKDIR /
RUN rm -rf /noto

ENTRYPOINT tail -f /dev/null


Google Noto Fontsを入れたDockerfileは上記のようになります。これで、日本語を含む

サイトでも文字化けせずにスクリーンショットが取れるようになりました。