Lambda で puppeteerをDockerコンテナで動かします。
ネタ元
Lambda コンテナイメージで Puppeteer を使ってみた | DevelopersIO
こちらの記事ではLambda環境にデプロイしても実行できないとのことですが、実行できるように改良しました。
また、Lambdaにデプロイするために Serverless Framework を使用しています。あらかじめセットアップを完了しておいてください。
目次
まずはコード
ARG FUNCTION_DIR="/home/pptruser"
FROM node:18-buster as aws-lambda-ric-build-image
RUN apt-get update && \
apt-get install -y \
g++ \
make \
cmake \
unzip \
libcurl4-openssl-dev
RUN mkdir -p /ric
WORKDIR /ric
COPY aws-lambda-rie .
COPY entry.sh .
RUN npm install aws-lambda-ric
FROM ghcr.io/puppeteer/puppeteer:19.7.5
ARG FUNCTION_DIR
ENV PUPPETEER_CACHE_DIR ${FUNCTION_DIR}/.cache/puppeteer
USER root
RUN mkdir -p /ric
COPY --from=aws-lambda-ric-build-image /ric /ric
WORKDIR ${FUNCTION_DIR}
COPY app.js ./
ENTRYPOINT ["/ric/entry.sh"]
CMD ["app.handler"]
"use strict";
const puppeteer = require("puppeteer");
module.exports.handler = async (event) => {
const url = event.url || "";
if (!url) {
return {
statusCode: 404,
body: "nothing url parameter",
event,
};
}
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",
],
});
const page = await browser.newPage();
await page.goto(url, { waitUntil: "load", timeout: 0 });
const content = await page.evaluate(() => document.body.innerHTML);
await browser.close();
return {
statusCode: 200,
body: JSON.stringify(content),
};
};
#!/bin/sh
if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
exec /ric/aws-lambda-rie /ric/node_modules/.bin/aws-lambda-ric $1
else
exec /ric/node_modules/.bin/aws-lambda-ric $1
fi
aws-lambda-rie ファイルも必要で、あらかじめこちらからダウンロードしてください https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
service: example-puppeteer
frameworkVersion: '3'
provider:
name: aws
region: ap-northeast-1
memorySize: 1536
# timeout: 30 # API Gateway の上限が30秒
ecr:
images:
fetchimage:
path: .
functions:
fetch:
timeout: 60
image:
name: fetchimage
実行
$ sls deploy
$ sls invoke -f fetch -d '{"url": "http://example.com"}'
{
"statusCode": 200,
"body": "\"\\n<div>\\n <h1>Example Domain</h1>\\n <p>This domain is for use in illustrative examples in documents. You may use this\\n domain in literature without prior coordination or asking for permission.</p>\\n <p><a href=\\\"https://www.iana.org/domains/example\\\">More information...</a></p>\\n</div>\\n\\n\\n\""
}
URLを渡せばHTMLコードが返却されます。JavaScriptレンダリングされるサイトなどに活用できます。
解説
基本的にはLambda公式のDockerコンテナが存在しますが、puppeteer公式のDockerコンテナをLambdaで動かす方針です。puppeteerのバージョン管理などがしやすいかなと。
puppeteerのコンテナはこちらを使います。 https://github.com/puppeteer/puppeteer/pkgs/container/puppeteer
コンテナの数字を変えればバージョンが変えられます。package.jsonを含めていないので、Dockerコンテナの中にあらかじめ入っているpuppeteerを使います。
Lambda環境にアップするとコンテナ内のgoogle-chrome-stableを使えない(?)ようでpuppeteerインストールした際にダウンロードされるchromiumを使うようにします。puppeteerのバージョン19からはchromiumが格納されるディレクトリが変わるので環境変数が必要です。参考 https://www.zachleat.com/web/chromium-missing/
ENV PUPPETEER_CACHE_DIR ${FUNCTION_DIR}/.cache/puppeteer
puppeteerの起動はこちらの記事のオプションを参考にしました。 https://qiita.com/moritalous/items/133bb2c132abce6530e7
通常のDockerコンテナをLambda対応にさせるにはこちらの記事を参考にしました。 https://github.com/aws/aws-lambda-nodejs-runtime-interface-client/issues/15#issuecomment-1168968457 ざっくりとaws-lambda-rieのバイナリファイルと npm install aws-lambda-ric
した結果や entry.sh 等々があればOKです。
Lambda対応のDockerコンテナイメージが作成できたらブラウザからアップロードしても良いですが、自分はServerless Frameworkを使用しました。 https://www.serverless.com/blog/container-support-for-lambda
最後に
以上、Lambdaでpuppeteerを動かす方法でした。
元々は起動していたLambda関数がpuppeteerアップデートによって動かなくなった原因調査をしていました。(今思えば PUPPETEER_CACHE_DIR を指定すれば動くようになっていたかもしれません。)
Lambda環境での原因調査もしづらく、どうせならとDockerコンテナにまとめてしまおうという流れで設定しました。
こちらの記事でレンタルサーバーでpuppeteerを動かすようにしていましたが
puppeteerやchromiumのバージョン管理の手間がそれなりに厳しかったのでDockerでまとめてみました。Dockerもapt-get installで作成しすぎるとbuild時間が長くなったりバージョン管理できなかったりするのでpuppeteer自体は公式のイメージをそのまま使用するようにしました。
基本的にはレンタルサーバーの旨みを活用しつつ、足りないものはHomebrewでインストールしたり、環境整備の手間が多いのはDockerにまとめてLambda実行していきたいと思います。
結構時間かけましたがやりたかった事が出来たので概ね満足です。
お疲れ様でした。
コメントを残す