koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

AWS Lambda上のChromeでHTMLをレンダリングしてS3やEFSに保存した

Twitterのタイムラインを動画にしたいと思ったのでしてみた - koudenpaのブログ からの流れでHTMLをレンダリングして画像を取得することをいくらか試している。

先には.NET FrameworkWindowsのローカルマシンで試したので、次はクラウドでと考えてAzure Functions上で何かしら試そうとしていたのだけれど、触り始めたライブラリ.NET Core3サポートがまだ完了していなくてFunctions上で動かすのは難しそうだったのでとりあえず匙を放ってしまった。

じゃぁ幾らでも事例が転がっていそうなAWSのLambdaをたしなんでおこうかと思った次第。

実際試す分には簡単で、やりたいと思ったことを非常に平易に行えた。流石にやっている人が多い行為はこなれている。

試しているリポジトリ。もうしばらく気になったことを更新するかもしれない。

github.com

ヘッドレスクロームを使ってHTMLをレンダリングしてS3にPut

何も考えないで出来る。

ブログ記事やpuppeteerのAPIを参照して適当にLambda関数を書いた

ただ、Chromeの立ち上げには結構時間がかかるので、FaaSでも一度立ち上げたChromeは立ち上げっぱなしにできるのならしておいた方が応答時間(≒コスト)の削減になってよいと思う。そうなるようにしてみたけれど、手法として合っているかは分からない。Node.jsとLambdaに詳しい人が試しているか探した方が良いと思う。

  // 立ち上げに時間がかかる(1024MBメモリで3秒ほど)ので実行毎ではなく1回立ち上げる。
  if (!browser) {
    console.log("Start launch browser.");
    browser = await chromium.puppeteer.launch({
      args: chromium.args,
      defaultViewport: chromium.defaultViewport,
      executablePath: await chromium.executablePath,
      headless: chromium.headless,
    });
    console.log("End launch browser.");
  }

f:id:koudenpa:20200826002432p:plain
二度目以降の呼び出しは立ち上げ時間分実行時間が短くなっている。

主に参照したページ。

EFSに保存してみる

登場当初夢のファイルシステムに思えたEFS、日本リージョンに全然来なかったEFS、そのうち使ってみたかったEFS、への保存も試してみた。

構成自体はリリース記事やブログ記事を参照すれば迷わなかった。

まずEFS自体とそこへのアクセスポイントを作って、そのアクセスポイントを介してLambda関数にマウントする形だ。素直でわかりやすい。

が、AWSを使うとセキュリティ設定まわりが素直に行ったことはない。

今回はアクセスポイントにEFSのルートディレクトリをマウントしていたら書き込み権限がなくてエラーしてしまった。ルートではないディレクトリをマウントすることで動作するようになったけれど、なんでルートだとダメだったのか、ルートをマウントしたい時にはどう設定すればいいのかは分かっていない。本格的にEFSを使うとなったら気にしないといけないかな、と思う。

追記:ルートをマウントしたい時にはどう設定すればいいのかは分かっていない。 コードにもコメントしたけれど、NFSとしてマウントした後にrootユーザーで設定を変更すればよい様子だった。AWSのマネージドリソースとしては、まだないディレクトリをマウントしようとしたときにそのディレクトリを生成するユーザーのみを設定できる(CreateAcl)だけなようだった。他はNFSとして処理してやる形。EFSはあくまでもNFSマウントできるファイルシステムを作るもの、と捉えて扱うのが良いように思えた。

この辺の設定

            var efsAccessPoint = new EFS.AccessPoint(this, "EfsAccessPoint", new EFS.AccessPointProps()
            {
                FileSystem = efs,
                // 他の設定そのままで "/" では書き込み権限が得られていなかった。
                Path = "/lambda",
                // ファイルIOに用いるユーザーとディレクトリ作成時権限の設定は必須である様子。
                // CDKが既定のユーザーを構成してくれるようなことはない。
                PosixUser = new PosixUser()
                {
                    Gid = "1001",
                    Uid = "1001",
                },
                CreateAcl = new Acl()
                {
                    OwnerGid = "1001",
                    OwnerUid = "1001",
                    Permissions = "755",
                },
            });

ただ、今回CDKでリソースを作成したのだけれど、EFSにLambdaからアクセスするためのセキュリティグループやロールの設定は1行も書かずに必要な権限が構成されていた。これは凄いなと思った。

f:id:koudenpa:20200826002534p:plain
このようなロールが構成される(S3周りはCDKで権限付与してる)。

もちろんしっかりそれらを設定する場合は明示的にセキュリティグループやロールを宣言すべきなのだけれど、最低限は構成してくれるのは非常にありがたい。

主に参照したページ。

オチ

特になし。

簡単なLambda関数はCDKでさっと構成できて便利だけれど、HTTPで叩けるようにするにはひと手間ある(なのでやっていない)その点Azure Functionsはちょっと試す分に必要な機能がフルにあって楽だなと強く感じたひと時だった。

この辺とかも。

ある環境に慣れていると、他の類似環境を見るときに足らない部分ばかり見てしまってどうにもよくない。気を付けよう。

(と言いつつこの項は消さない)