Playwright を Lambdaで動かす
ちょっと苦労したのでポイントをまとめておく。
前提
- TypeScriptでPlaywrightを動かすコードを書きたい
- AWSが提供しているLambda用のAWSベースイメージはFedoraベース?(CentOSベース?)なのでPlaywrightの推奨ではない
- 自分でコンテナイメージを作成する
準備
独自でコンテナイメージを作る
基本的に以下のサイトのコンテナの項を参考に作成しました。
LambdaでPlaywrightを動かす(Lambdaレイヤー / コンテナ)
FROM node:20
ARG CHORME_VERSION=131.0.6778.86
# Chromeの依存ライブラリインストール
# https://pptr.dev/troubleshooting#chrome-doesnt-launch-on-linux
RUN apt-get clean && \
apt-get update && \
apt-get install -y ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils && \
apt-get install -y g++ make cmake unzip libcurl4-openssl-dev
# Chrome for Testingインストール
RUN npx -y @puppeteer/browsers install chrome@${CHORME_VERSION} --platform linux && \
mv chrome/linux-${CHORME_VERSION}/chrome-linux64 /browser && \
rm -r chrome
WORKDIR /function
ARG basedir="/tmp"
RUN npm install aws-lambda-ric
RUN npm install tsx @types/node typescript
RUN npm install -D @types/aws-lambda
RUN npm install playwright@latest
RUN npx playwright install
COPY /app/index.ts /function/index.ts
RUN npx tsc index.ts
ENTRYPOINT ["/usr/local/bin/npx", "aws-lambda-ric"]
CMD ["index.handler"]
動作させる index.ts は以下のような形にしています。 これを `npx tsc index.ts" で index.jsに変換して動作させます。
// main
export const handler:Handler = async (event: APIGatewayEvent, context:Context):Promise<APIGatewayProxyResult> => {
const body = JSON.parse(event.body ?? "{}");
//setup
const args = [
'--single-process',
'--window-size=1920,1080',
'--use-angle=swiftshader',
'--disable-setuid-sandbox',
'--no-sandbox',
'--no-zygote',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-extensions',
'--incognito',
'--enable-automation',
];
const browser = await chromium.launch({
args:args,
headless: true,
executablePath: "/browser/chrome"
});
try {
const ctx = await browser.newContext();
const page = await ctx.newPage();
// 何らかの処理
await anyFunction(page);
await page.close(); // ページを閉じる
await browser.close(); // ブラウザを閉じる
return {
statusCode: 200,
body: JSON.stringify({
message: 'OK',
}),
};
} catch(err) {
console.log(err);
return {
statusCode: 500,
body: JSON.stringify({
message: 'some error happened',
}),
};
}
};
chromiumのオプションについて
(chatgptに教えてもらいました)
–no-sandbox と –disable-setuid-sandbox コンテナ環境では、サンドボックスが不要または非対応のため、これを無効化します。
–disable-dev-shm-usage コンテナの共有メモリサイズ(/dev/shm)がデフォルトでは小さいため、このオプションで問題を回避します。特に、大きなDOMやグラフィカルな処理で必要です。
–disable-gpu ヘッドレス環境ではGPUが不要なため無効化します。
–no-zygote Zygoteプロセスを無効化することで、プロセスオーバーヘッドを軽減します。
–single-process マルチプロセスを無効化し、単一プロセスで動作させます(メモリ効率の向上)。
–lang=ja-JP 言語を日本語に設定します。日本語Webサイトの適切な表示を確保するためです。
–disable-extensions 拡張機能を無効化し、不要なリソース使用を防ぎます。
–incognito プライバシー保護のため、シークレットモードで起動します。
–enable-automation ブラウザが自動化モードで動作していることを明示し、安定性を向上させます。
ただし –no-sandbox はセキュリティを低下させる可能性があるため、必要最小限の環境で使用してください。
ポイント
page.waitForTimeoutは3秒以上あったほうがいい
Lambdaは1~2秒程度だとアクセス先のページをレンダリングしきれない場合がある(間に合わない) 多少時間がかかってもいいなら 5秒程度がおすすめ。
何かのファイルを出力したい場合
Lambdaのコンテナイメージは /tmp 以外全部リードオンリーの場所でマウントされる。よって何か処理の途中で一時的にファイルを吐き出したい場合は /tmp に書き込む必要がある。
LambdaのRAM量
1024MB程度は必要と思われる(chromium動作のため)