Lambda コンテナイメージで Puppeteer を使ってみた
追記:こちらの記事で掲載している nodejs コンテナイメージベースの Puppeteer を、実際の AWS Lambda 環境で動かしてみたところコアダンプ等のエラーが発生し動作しないことを確認しております。実際に AWS Lambda 環境で Puppeteer を利用する方法としては、下記の記事を参考に alixaxel/chrome-aws-lambda を利用されるのが良いかと思われます。
先日の re:Invent にて Lambda Container Support が発表されました。
注意:こちらの手順は、ローカル環境で Amazon ECR Public Gallery の nodejs コンテナイメージをベースに Puppeteer が動作することを検証した記事となっております。
検証環境について
筆者のローカル環境は、以下の構成です。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H15 $ docker -v Docker version 20.10.0, build 7287ab3 curl -V curl 7.64.1 (x86_64-apple-darwin19.0) libcurl/7.64.1 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.39.2 Release-Date: 2019-03-27 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS GSS-API HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL UnixSockets
やってみた
用意するファイルは、2つだけ
- app.js
- Dockerfile
Dockerfile は、以下のとおりです。
FROM public.ecr.aws/lambda/nodejs:12 LABEL example=lambda-container ARG LAMBDA_TASK_ROOT="/var/task" RUN yum install -y https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm RUN npm install puppeteer-core COPY app.js ${LAMBDA_TASK_ROOT} CMD [ "app.handler" ]
Amazon ECR Public Gallery の nodejs コンテナイメージをベースに google-chrome-stable と puppeteer-core をインストールしてソースコードを LAMBDA_TASK_ROOT(/var/task)にコピーしハンドラーを起動しています。
次に、app.js
const puppeteer = require('puppeteer-core'); exports.handler = async (event) => { const browser = await puppeteer.launch({ headless: true, executablePath: '/usr/bin/google-chrome-stable', args: [ '--no-sandbox', '--disable-setuid-sandbox' ] }); const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({path: 'example.png'}); await browser.close(); const response = { statusCode: 200, }; return response; };
yum インストールした Chrome をヘッドレスモードで起動し、https://example.com のスクリーンショットを example.png として保存するサンプルになります。
先の Dockerfile を利用して、コンテナイメージをビルドします。
$ docker build -t example . Sending build context to Docker daemon 32.26kB Step 1/7 : FROM public.ecr.aws/lambda/nodejs:12 ---> 80d7260f97c9 Step 2/7 : LABEL example=lambda-container ---> Running in 8a9ed315b107 Removing intermediate container 8a9ed315b107 ---> df5ef5d27555 Step 3/7 : ARG LAMBDA_TASK_ROOT="/var/task" ---> Running in 3866d4a3a2d7 Removing intermediate container 3866d4a3a2d7 ---> ecca97455032 Step 4/7 : RUN yum install -y https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm ---> Running in 9bdd12ea0473 Loaded plugins: ovl Examining /var/tmp/yum-root-_IfE9n/google-chrome-stable_current_x86_64.rpm: google-chrome-stable-87.0.4280.88-1.x86_64 Marking /var/tmp/yum-root-_IfE9n/google-chrome-stable_current_x86_64.rpm to be installed Resolving Dependencies --> Running transaction check ---> Package google-chrome-stable.x86_64 0:87.0.4280.88-1 will be installed : 略 : Installed: google-chrome-stable.x86_64 0:87.0.4280.88-1 Dependency Installed: acl.x86_64 0:2.2.51-14.amzn2 adwaita-cursor-theme.noarch 0:3.26.0-1.amzn2 adwaita-icon-theme.noarch 0:3.26.0-1.amzn2 alsa-lib.x86_64 0:1.1.4.1-2.amzn2 at-spi2-atk.x86_64 0:2.22.0-2.amzn2.0.2 at-spi2-core.x86_64 0:2.22.0-1.amzn2.0.2 atk.x86_64 0:2.22.0-3.amzn2.0.2 audit-libs.x86_64 0:2.8.1-3.amzn2.1 avahi-libs.x86_64 0:0.6.31-20.amzn2 cairo.x86_64 0:1.15.12-4.amzn2 cairo-gobject.x86_64 0:1.15.12-4.amzn2 colord-libs.x86_64 0:1.3.4-1.amzn2.0.2 cracklib.x86_64 0:2.9.0-11.amzn2.0.2 cracklib-dicts.x86_64 0:2.9.0-11.amzn2.0.2 cryptsetup-libs.x86_64 0:1.7.4-4.amzn2 cups-libs.x86_64 1:1.6.3-51.amzn2 dbus.x86_64 1:1.10.24-7.amzn2 dbus-libs.x86_64 1:1.10.24-7.amzn2 dconf.x86_64 0:0.28.0-4.amzn2 dejavu-fonts-common.noarch 0:2.33-6.amzn2 dejavu-sans-fonts.noarch 0:2.33-6.amzn2 desktop-file-utils.x86_64 0:0.23-2.amzn2 device-mapper.x86_64 7:1.02.146-4.amzn2.0.2 device-mapper-libs.x86_64 7:1.02.146-4.amzn2.0.2 elfutils-default-yama-scope.noarch 0:0.176-2.amzn2 elfutils-libs.x86_64 0:0.176-2.amzn2 emacs-filesystem.noarch 1:25.3-3.amzn2.0.2 fontconfig.x86_64 0:2.13.0-4.3.amzn2 fontpackages-filesystem.noarch 0:1.44-8.amzn2 freetype.x86_64 0:2.8-14.amzn2.1 fribidi.x86_64 0:1.0.2-1.amzn2.1 gdk-pixbuf2.x86_64 0:2.36.12-3.amzn2 glib-networking.x86_64 0:2.56.1-1.amzn2 gnutls.x86_64 0:3.3.29-9.amzn2 graphite2.x86_64 0:1.3.10-1.amzn2.0.2 gsettings-desktop-schemas.x86_64 0:3.28.0-3.amzn2.0.1 gtk-update-icon-cache.x86_64 0:3.22.30-3.amzn2 gtk3.x86_64 0:3.22.30-3.amzn2 gzip.x86_64 0:1.5-10.amzn2 harfbuzz.x86_64 0:1.7.5-2.amzn2 hicolor-icon-theme.noarch 0:0.12-7.amzn2 hwdata.x86_64 0:0.252-9.3.amzn2 jasper-libs.x86_64 0:1.900.1-33.amzn2 jbigkit-libs.x86_64 0:2.0-11.amzn2.0.2 json-glib.x86_64 0:1.4.2-2.amzn2 kmod.x86_64 0:25-3.amzn2.0.2 kmod-libs.x86_64 0:25-3.amzn2.0.2 lcms2.x86_64 0:2.6-3.amzn2.0.2 libX11.x86_64 0:1.6.7-3.amzn2 libX11-common.noarch 0:1.6.7-3.amzn2 libXau.x86_64 0:1.0.8-2.1.amzn2.0.2 libXcomposite.x86_64 0:0.4.4-4.1.amzn2.0.2 libXcursor.x86_64 0:1.1.15-1.amzn2 libXdamage.x86_64 0:1.1.4-4.1.amzn2.0.2 libXext.x86_64 0:1.3.3-3.amzn2.0.2 libXfixes.x86_64 0:5.0.3-1.amzn2.0.2 libXft.x86_64 0:2.3.2-2.amzn2.0.2 libXi.x86_64 0:1.7.9-1.amzn2.0.2 libXinerama.x86_64 0:1.1.3-2.1.amzn2.0.2 libXrandr.x86_64 0:1.5.1-2.amzn2.0.3 libXrender.x86_64 0:0.9.10-1.amzn2.0.2 libXtst.x86_64 0:1.2.3-1.amzn2.0.2 libXxf86vm.x86_64 0:1.1.4-1.amzn2.0.2 libcap-ng.x86_64 0:0.7.5-4.amzn2.0.4 libdrm.x86_64 0:2.4.97-2.amzn2 libepoxy.x86_64 0:1.3.1-2.amzn2 liberation-fonts.noarch 1:1.07.2-16.amzn2 liberation-fonts-common.noarch 1:1.07.2-16.amzn2 liberation-mono-fonts.noarch 1:1.07.2-16.amzn2 liberation-narrow-fonts.noarch 1:1.07.2-16.amzn2 liberation-sans-fonts.noarch 1:1.07.2-16.amzn2 liberation-serif-fonts.noarch 1:1.07.2-16.amzn2 libfdisk.x86_64 0:2.30.2-2.amzn2.0.4 libglvnd.x86_64 1:1.0.1-0.1.git5baa1e5.amzn2.0.1 libglvnd-egl.x86_64 1:1.0.1-0.1.git5baa1e5.amzn2.0.1 libglvnd-glx.x86_64 1:1.0.1-0.1.git5baa1e5.amzn2.0.1 libgusb.x86_64 0:0.2.9-1.amzn2.0.2 libidn.x86_64 0:1.28-4.amzn2.0.2 libjpeg-turbo.x86_64 0:1.2.90-6.amzn2.0.3 libmodman.x86_64 0:2.0.1-8.amzn2.0.2 libpciaccess.x86_64 0:0.14-1.amzn2 libpng.x86_64 2:1.5.13-8.amzn2 libproxy.x86_64 0:0.4.11-10.amzn2.0.3 libpwquality.x86_64 0:1.2.3-5.amzn2 libsemanage.x86_64 0:2.5-11.amzn2 libsmartcols.x86_64 0:2.30.2-2.amzn2.0.4 libsoup.x86_64 0:2.56.0-6.amzn2 libthai.x86_64 0:0.1.14-9.amzn2.0.2 libtiff.x86_64 0:4.0.3-35.amzn2 libusbx.x86_64 0:1.0.21-1.amzn2 libutempter.x86_64 0:1.1.6-4.amzn2.0.2 libwayland-client.x86_64 0:1.17.0-1.amzn2 libwayland-cursor.x86_64 0:1.17.0-1.amzn2 libwayland-egl.x86_64 0:1.17.0-1.amzn2 libwayland-server.x86_64 0:1.17.0-1.amzn2 libxcb.x86_64 0:1.12-1.amzn2.0.2 libxkbcommon.x86_64 0:0.7.1-3.amzn2 libxshmfence.x86_64 0:1.2-1.amzn2.0.2 lz4.x86_64 0:1.7.5-2.amzn2.0.1 mesa-libEGL.x86_64 0:18.3.4-5.amzn2.0.1 mesa-libGL.x86_64 0:18.3.4-5.amzn2.0.1 mesa-libgbm.x86_64 0:18.3.4-5.amzn2.0.1 mesa-libglapi.x86_64 0:18.3.4-5.amzn2.0.1 nettle.x86_64 0:2.7.1-8.amzn2.0.2 pam.x86_64 0:1.1.8-23.amzn2.0.1 pango.x86_64 0:1.42.4-4.amzn2 pixman.x86_64 0:0.34.0-1.amzn2.0.2 qrencode-libs.x86_64 0:3.4.1-3.amzn2.0.2 rest.x86_64 0:0.8.0-2.amzn2 shadow-utils.x86_64 2:4.1.5.1-24.amzn2.0.2 systemd.x86_64 0:219-57.amzn2.0.12 systemd-libs.x86_64 0:219-57.amzn2.0.12 trousers.x86_64 0:0.3.14-2.amzn2.0.2 ustr.x86_64 0:1.0.4-16.amzn2.0.3 util-linux.x86_64 0:2.30.2-2.amzn2.0.4 vulkan.x86_64 0:1.0.61.1-2.amzn2 vulkan-filesystem.noarch 0:1.0.61.1-2.amzn2 wget.x86_64 0:1.14-18.amzn2.1 which.x86_64 0:2.20-7.amzn2.0.2 xdg-utils.noarch 0:1.1.0-0.17.20120809git.amzn2 xkeyboard-config.noarch 0:2.20-1.amzn2 Complete! Removing intermediate container 9bdd12ea0473 ---> f4731c48c18d Step 5/7 : RUN npm install puppeteer-core ---> Running in 177559a5bc04 npm WARN saveError ENOENT: no such file or directory, open '/var/task/package.json' npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN enoent ENOENT: no such file or directory, open '/var/task/package.json' npm WARN task No description npm WARN task No repository field. npm WARN task No README data npm WARN task No license field. + puppeteer-core@5.5.0 added 54 packages from 75 contributors and audited 54 packages in 3.98s 8 packages are looking for funding run `npm fund` for details found 0 vulnerabilities Removing intermediate container 177559a5bc04 ---> 0810cea6a9f0 Step 6/7 : COPY app.js ${LAMBDA_TASK_ROOT} ---> f0a47cd52a53 Step 7/7 : CMD [ "app.handler" ] ---> Running in 0429754cc7a7 Removing intermediate container 0429754cc7a7 ---> eab9382dbeb3 Successfully built eab9382dbeb3 Successfully tagged example:latest
コンテナイメージがビルドできたら、ターミナルから docker コマンドを利用して、ローカル環境でコンテナを起動します。
$ docker run -it --name example -p 9000:8080 example INFO[0000] exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)
起動できました。
次に別のターミナルから、curl コマンドで POST リクエストを送信します。
$ curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}' {"statusCode":200}
Docker コンテナを起動しているターミナルには、ログが出力されます。
$ docker run -it --name example -p 9000:8080 example INFO[0000] exec '/var/runtime/bootstrap' (cwd=/var/task, handler=) INFO[0030] extensionsDisabledByLayer(/opt/disable-extensions-jwigqn8j) -> stat /opt/disable-extensions-jwigqn8j: no such file or directory WARN[0030] Cannot list external agents error="open /opt/extensions: no such file or directory" START RequestId: b3ed3890-c2ba-438b-a5a3-7f3d595a344a Version: $LATEST END RequestId: b3ed3890-c2ba-438b-a5a3-7f3d595a344a REPORT RequestId: b3ed3890-c2ba-438b-a5a3-7f3d595a344a Init Duration: 0.33 ms Duration: 1049.27 ms Billed Duration: 1100 ms Memory Size: 3008 MB Max Memory Used: 3008 MB
それでは、https://example.com のスクリーンショット(example.png)が保存されているか確認しましょう。
curl コマンドを実行したターミナルで、コンテナから画像ファイル(example.png)をコピーします。
$ docker cp example:/var/task/example.png .
コピーした画像は、以下のとおりです。
ちゃんとキャプチャできてますね。
さいごに
ローカル環境でのコンテナイメージサイズを確認すると、1.2GB 程度の規模でした。
$ docker images -f label=example REPOSITORY TAG IMAGE ID CREATED SIZE example latest 29df2f38a5f3 7 seconds ago 1.2GB
Lambda 関数は最大で 10GB のコンテナイメージ をサポートしているため、これまでよりも Lambda の活用シーンや利用機会が増えるのではないかと期待しております。
ではでは