ChromeやChromiumをNode.jsから操作できるライブラリとしてPuppetterがあります。
これを使うと、Chromeでできるさまざまな事柄が自動化できます。
一方で、PuppetterはChromeを内蔵しており、Lambda関数化したとしてもそのサイズは非常に大きくなります。 Lambdaのパッケージサイズ制限は以下の通り(Lambda quotas)であり、通常Lambda関数化できません。
- 50 MB (zipped, for direct upload)
- 250 MB (unzipped)
- 3 MB (console editor)
この問題を解決するために、AWS Lambda用の別ライブラリも存在しています。
ただ、Lambda関数をコンテナ化すると、そのサイズ制限は10GBとなり、自由度が大きくなります。
Container image code package size: 10 GB
それであれば、Puppetterを組み込んだアプリをコンテナ化すれば良いのでは?という発想に至りました。
アプリ
例えば以下のようなコードを作ります。
Lambda関数として構成するので、exports.handler
を定義します。
launch
のargs
にはさまざまな初期化オプションを与えていますが、
これはAWS LambdaがコンテナイメージをサポートしたのでPuppeteerしてみたを参考にさせていただきました。
コマンドラインスイッチについてはList of Chromium Command Line Switchesあたりを参照。
const puppeteer = require("puppeteer"); exports.handler = async (event, context, callback) => { const browser = await puppeteer.launch({ headless: true, args: [ "--no-sandbox", "--disable-setuid-sandbox", "-–disable-dev-shm-usage", "--disable-gpu", "--no-first-run", "--no-zygote", "--single-process", ], defaultViewport: { width: 1366, height: 768, }, }); const page = await browser.newPage(); await page.goto(process.env.TARGET_URL); }
Puppetterはv13.5.2を組み込んでいます。
"dependencies": { "puppeteer": "^13.5.2", "puppeteer-core": "^10.4.0" },
コンテナ化
上記アプリをコンテナ化します。以下の様なDockerfileを用意しました。
FROM public.ecr.aws/lambda/nodejs:14.2022.03.23.16 RUN yum -y install \ libX11 \ libXcomposite \ libXcursor \ libXdamage \ libXext \ libXi \ libXtst \ cups-libs \ libXScrnSaver \ libXrandr \ alsa-lib \ pango \ atk \ at-spi2-atk \ gtk3 \ google-noto-sans-japanese-fonts \ WORKDIR ${LAMBDA_TASK_ROOT} COPY app.js package*.json ${LAMBDA_TASK_ROOT} RUN npm install CMD [ "app.handler" ]
これをコンテナ化し、ECRにPUSHします。
$ docker build -t sandbox . $ docker tag sandbox:latest xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sandbox:latest $ docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sandbox:latest
これでLambda関数が正常に起動できることが確認できました。ちないにコンテナ化したときのサイズは624MBでした。