Lambda コンテナイメージで Puppeteer を使ってみた

Lambda コンテナイメージで Puppeteer を使ってみました。これからは、Lambda でヘッドレスモードの Chrome が気軽に利用できますね。
2020.12.25

追記:こちらの記事で掲載している 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 は、以下のとおりです。

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

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 .

コピーした画像は、以下のとおりです。

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 の活用シーンや利用機会が増えるのではないかと期待しております。

ではでは

参考文献