頭の中で翻訳しても忘れる & 記述を一つ一つ追うために、メモとして残す。
NodeイメージのAlpineは今回使用しないので省略する。
Githubの当該ページ
以下、本文翻訳
DockerでPuppeteerを実行する
v3.0.xまでは、DockerコンテナでPuppeteerのテストを実行するのにCirrus Ciを使用した。 参照するには、Dockerfile.linux(v3.0.1)の履歴をみてね。
ヘッドレスChromeを起動・実行するのは難しいことがある。PuppeteerがインストールするバンドルされたChromiumには、必要な共有ライブラリの依存関係がない。
修正するには、不足している依存関係と、最新のChomiumパッケージをあなたのDockerfileにインストールする必要がある。
↓ 以下、Dockerfileの記述。コメントは訳す。
FROM node:12-slim
# 主要な文字コード(中国語、日本語、アラビア語、ヘブライ語、タイ語他)をサポートするため、最新のChrome Devパッケージとフォントをインストールしてね。
# 注:これは、PuppeteerがインストールするバンドルされたChromiumのバージョンを動かすため、必要なライブラリをインストールするよ。 RUN apt-get update \ && apt-get install -y wget gnupg \ && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ && apt-get update \ && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \ --no-install-recommends \ && rm -rf /var/lib/apt/lists/*
# Dockerが1.13.0以上のバージョンを実行している場合は、ゾンビプロセスを刈り取るため、docker runコマンドの--init引数を使用してね。もしくは、PID 1として'dumb-init'を持つため、次の行のコメントアウトを外してね。
# ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_x86_64 /usr/local/bin/dumb-init
# RUN chmod +x /usr/local/bin/dumb-init
# ENTRYPOINT ["dumb-init", "--"] # Puppeteerをインストールするとき、Chromiumのダウンロードをスキップするにはコメントアウトを外してね。もしそれをするなら、下記コマンド(browser.~)でPuppeteerを起動する必要があるよ。
# browser.launch({executablePath: 'google-chrome-stable'})
# ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
# Puppeteerをインストールして、コンテナで使用できるようにする。 RUN npm i puppeteer \
# --no-sandboxオプションが必要ないようユーザーを追加してね。
# npm installと同じレイヤーで、ユーザー権限が再変更されたファイルが、数百MB以上のスペースを使い尽くないようにする。 && groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ && mkdir -p /home/pptruser/Downloads \ && chown -R pptruser:pptruser /home/pptruser \ && chown -R pptruser:pptruser /node_modules
# 非特権ユーザーとしてすべてを実行する。 USER pptruser CMD ["google-chrome-stable"]
↑Dockerfileここまで
コンテナをビルドする:
docker build -t puppeteer-chrome-linux .
コマンドとしてnode -e "<yourscript.js content as a string>"を渡して、コンテナを実行する(yourscript.jsは任意のファイル):
docker run -i --init --rm --cap-add=SYS_ADMIN \ --name puppeteer-chrome puppeteer-chrome-linux \ node -e "`cat yourscript.js`"
https://github.com/ebidel/try-puppeteerに完全な例があり、App Engine Flex (Node)上で実行しているウェブサーバーから、どうやってこのDockerfileを実行するかを示している。
翻訳は以上。次はDockerfileの中身を逐一読み下していく。
Dockerfileと実行コマンドの内容
FROM node:12-slim
Nodeイメージのバージョン指定。例は12のslim(軽量版)。
RUN apt-get update \
&& apt-get install -y wget gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \ --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
インストール可能なパッケージの一覧を更新。
↓
wget(指定したURIに存在するファイルをダウンロードするコマンド)と gnupg(暗号化ソフト)をインストール。
-yオプション:インストール中の質問にすべてYes。
↓
-qオプション:処理結果の表示を行わない。
-O(の後の - はファイル名)オプション:標準出力(ここでは|(パイプ)以下)に出力。
つまり、https://dl-ssl.google.com/linux/linux_signing_key.pubからファイル(公開鍵)をダウンロードして、パッケージを認証するのに使用するkeyの一覧にそれを追加。
↓
シェルで’ ’の中のコマンドを実行。
' 'の中身:"deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main"を表示して、/etc/apt/sources.list.dディレクトリのgoogle.listに追記。
つまり、Chromeをインストール可能パッケージの一覧に追加している。
↓
インストール可能なパッケージの一覧を更新。
↓
google-chrome-stableとフォント関連パッケージとlibxss1をインストール。--no-install-recommendsオプション:OS推奨パッケージのインストールを抑制。
↓
/var/lib/apt/listsディレクトリ以下のディレクトリをすべて削除。
長い…。要は、Chrome上でPuppeteerを使ってテストするために、必要な最新のChromeとフォントとXウィンドウ関連パッケージをインストールしている、ということか。
# Dockerが1.13.0以上のバージョンを実行している場合は、ゾンビプロセスを刈り取るため、docker runコマンドの--init引数を使用してね。もしくは、PID 1として'dumb-init'を持つため、次の行のコメントアウトを外してね。
# ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_x86_64 /usr/local/bin/dumb-init
# RUN chmod +x /usr/local/bin/dumb-init
# ENTRYPOINT ["dumb-init", "--"]
使用しているDcokerのバージョンによって対応が違うと。1.13は2017年1月リリースのため、2021年現在であればこのコメントアウトを外す必要はないはず。後ほど出てくるdocker runコマンドで--initを引数に書けばいい。
# Puppeteerをインストールするとき、Chromiumのダウンロードをスキップするにはコメントアウト(ENV ~)を外してね。もしそれをするなら、下記コマンド(browser.~)でPuppeteerを起動する必要があるよ。
# browser.launch({executablePath: 'google-chrome-stable'})# ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
ChromiumはChromeの元となっているオープンソースプロジェクト。 正確には分からないが、コメントアウトしてあるということは、わざわざ外す必要はない → Chromiumをダウンロードする必要がある、ということだろう。
# Puppeteerをインストールして、コンテナで使用できるようにする。
RUN npm i puppeteer \
# --no-sandboxオプションが必要ないようユーザーを追加してね。
# npm installと同じレイヤーで、ユーザー権限が再変更されたファイルが、数百MB以上のスペースを使い尽くないようにする。&& groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /node_modules
npmでPuppeteerをインストール(package.jsonが存在するディレクトリで)。
↓
システムアカウントとグループ(pptruser)を作成し、新規ユーザー(pptruser)を作成しpptruserグループ(プライマリグループ)に所属させ、audio,videoのセカンダリグループに所属させる。
↓
-pオプションついてるので、/home, /home/pptruser, /home/pptruser/Downloadsの各ディレクトリを作成する。
↓
/home/pptruserディレクトリ以下の所有権を、ユーザーpptruser:グループpptruserに再帰的(そのディレクトリ以下のディレクトリ以下のディレクトリ以下の…)に変更。
↓
/node_modulesディレクトリ以下の所有権を、ユーザーpptruser:グループpptruserに再帰的に変更。
Linux系のユーザー権限まわりの理解が不足しているので細かいことが分からないが、Puppeteerインストール後、Puppeteer用にユーザーを作成してファイル所有権を移しているみたい。コメントにあるように、容量を過剰に使わないようにするための処置?
翌日追記:
root権限ではChromeを実行できないらしい。root権限で実行するには、Chromeの実行コマンドに--no-sandboxが必要。なるほど。
# 非特権ユーザーとしてすべてを実行する。
USER pptruser
pptruserを実行ユーザーに指定。
→ Chromeを実行。
以上がDockerfileの中身。次のコマンドを実行することにより、コンテナ上でPuppeteerを実行できるようになる。
イメージ名をpuppeteer-chrome-linuxとし、カレントディレクトリ( . )でDockerイメージを作成。
docker run -i --init --rm --cap-add=SYS_ADMIN \ --name puppeteer-chrome puppeteer-chrome-linux \ node -e "`cat yourscript.js`"
ややこしいのでオプションを一つずつ見ていく。
-i:コンテナに操作端末(キーボード)を繋ぐ
--init:上のDockerfileで付けてねって出てたやつ。PID1が/dev/initになる。UNIXプロセスの問題で必要。
--rm:実行後、コンテナを削除。
--cap-add=SYS_ADMIN:コンテナにシステム管理権限を許可。
--name puppeteer-chrome puppeteer-chrome-linux:さきほどbuildしたpuppeteer-chrome-linuxイメージを指定、puppeteer-chromeという名前を付ける。
node -e "`cat yourscript.js`":Node.jsでcat yourscript.jsを実行(yourscript.jsの中身を出力)
となる。docker runでコンテナを稼働させ、Node.jsで任意のコマンド・スクリプトファイルを実行、その後コンテナを削除している。
以上、Dockerコマンドの内容を確認した。これらにより、任意のJSファイルをコンテナ上のPuppeteerで実行できる。
ということで、適当なsample.jsで動作確認。
これで先ほどのdocker run ~ のファイル名をsample.jsに変更して実行
$ docker run -i --init --rm --cap-add=SYS_ADMIN \
--name puppeteer-chrome puppeteer-chrome-linux \
node -e "`cat sample.js`"
↓
Google と表示された!
イメージのバージョンを上げてみる
今回は公式の記述通りnodeイメージのバージョンを「12」と指定したが、古い気がするので、2021年5月現在の最新版の「16」に上げるとどうなるか。
=> ERROR [3/3] RUN npm i puppeteer && groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruse 2.6s
------
> [3/3] RUN npm i puppeteer && groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser && mkdir -p /home/pptruser/Downloads && chown -R pptruser:pptruser /home/pptruser && chown -R pptruser:pptruser /node_modules:
#6 2.498 npm notice
#6 2.498 npm notice New minor version of npm available! 7.13.0 -> 7.14.0
#6 2.498 npm notice Changelog: <https://github.com/npm/cli/releases/tag/v7.14.0>
#6 2.498 npm notice Run `npm install -g npm@7.14.0` to update!
#6 2.498 npm notice
#6 2.517 npm ERR! Tracker "idealTree" already exists
#6 2.535
#6 2.535 npm ERR! A complete log of this run can be found in:
#6 2.535 npm ERR! /root/.npm/_logs/2021-05-25T05_31_07_057Z-debug.log
------
executor failed running [/bin/sh -c npm i puppeteer && groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser && mkdir -p /home/pptruser/Downloads && chown -R pptruser:pptruser /home/pptruser && chown -R pptruser:pptruser /node_modules]: exit code: 1
とエラーが出る。「npm ERR! Tracker "idealTree" already exists」が原因。ググると、ルートディレクトリでnpm installが実行されるのが問題みたい。
かといって、WORKDIRを指定(適当に/appとか)してからdocker run ~ してもスクリプトファイルの応答なし。
ここから色々調べたけど解決できなかった。解決方法が分かれば追記したい。
とりあえず、nodeイメージのバージョン指定は14までにしておけば実行はできる。