AWS Lambdaがコンテナをサポートしたのでちょっと試してみた

現在開催中のre:InventでAWS Lambdaがコンテナのサポートをするという発表がありましたね。

aws.amazon.com

というわけでちょっと試してみました。

素材はここにあげてあります。

github.com

流れとしては、

  1. 普通にファンクション書く
  2. Dockerfile作る
  3. イメージをビルドする
  4. イメージをECRにプッシュする
  5. Lambdaファンクションを作るときにECR上のイメージを指定する

という感じです。3,4のコマンド実行例はReadmeに記載しています。

イメージに関してはRuntime APIを実装する必要があるんですが、現在Lambdaがサポートしている各言語向けには既に用意されていてリリースされています。例えばNode.jsであればnpm install aws-lambda-ricでインストールできます。

加えて、これを組み込み済のベースイメージが既に用意されているのでこれを使うのが楽かもです。僕が試したサンプルも用意されているベースイメージを使ってます。きっとLambdaがサポートしていない言語の場合はカスタムランタイムを作るのと同じような感じでやればいいんじゃないかと思うんだけど確証はない。

サンプルではaxiosを使ってGoogleのトップページをリクエストしてその結果を出力しているだけです。超絶雑なコード。

"use strict";
const axios = require("axios");

exports.lambdaHandler = async (event, context, callback) => {
  const url = "https://google.com/";
  const res = await axios.get(url).then((res) =>
    callback(null, {
      statusCode: res.status,
      body: res.data,
      headers: {
        "Content-Type": "text/html",
      },
    })
  );
};

axiosはpackage.jsonに書いておいてイメージをビルドする際にnpm installしてます。ま、自前のコンテナイメージを用意できる利点はこのあたりにあるのかもしれない。

Dockerファイルはこんな感じ。

FROM amazon/aws-lambda-nodejs:12
COPY app.js package*.json ./
RUN npm install
CMD [ "app.lambdaHandler" ]

Runtime Interface Emulaterなるものもあるので自前でがっつりイメージ作る人は使うといいのかもしれない。

Lambdaファンクションの作成はこんな感じで。 f:id:Keisuke69:20201202050223p:plain

コンテナイメージを使う場合の選択が増えてるのでそれを選択して、先程ECRにプッシュしたイメージを指定するだけです。

作成してから、実行できるようになるまで少し時間がかかるようでその間はテスト実行のボタンが無効になってました。準備完了したらボタンが押せるように。というわけでテスト実行もできます。

f:id:Keisuke69:20201202050655p:plain

組み込みのコードエディタは当然のことながら使えませんでした。ま、コンテナイメージだしあたりまえよね。それ以外は普通のファンクションと同じ。ちなみに同じくre:InventでLambdaの課金単位がこれまでの100ms単位から1ms単位へと粒度が細かくなりました。

という感じですが、Dockerイメージがサポートされるからといって何でも自由にできるというよりは、あくまでもLambdaの実行モデルであるファンクションモデルはそのままにランタイムの自由度が増したって感じですね。

必要な人にはとってもいいエンハンスだと思いますが、過度な期待は禁物です。

追記:

これローカルでも簡単に実行できるのでローカルテストしたい場合にはいいかもですね。ローカル実行するには作ったイメージをdocker runでローカルで起動した上でLambdaのAPIlocalhostに対して実行するだけです。

docker run -p 3000:8080 lambda-container-support-sample:latest

こんな感じでローカルで起動して別ターミナルから以下のようにAPIをリクエストするだけです。

curl -XPOST "http://localhost:3000/2015-03-31/functions/function/invocations" -d '{}'

Monthly AWS Serverless Update 202011

2020年11月のサーバーレス関連まとめです。こちらのイベントで取り上げる内容です。

serverless-newworld.connpass.com

2020年11月のリリース

11月30日からAWSの年次グローバルカンファレンスであるre:Inventが開催されることから細かいアップデートが多めですね。ていうか数が多すぎるのでS3とか割愛しましたw タイトルだけで内容がわかるようなものは特にコメントしていません。

Amazon Kinesis Data Streams は、最大 1 年間のデータストリームの保持が可能に

  • データ保存期間がこれまでの最大7日から最大1年に
  • デフォルトは24時間

Amazon MQ for RabbitMQ の発表

  • Amazon MQがRabbitMQをサポート
  • RabbitMQは広く使われているOSSのメッセージブローカー
  • 複数のプロトコルに対応、軽量といった特徴

AWS Lambda が、イベントソースとして Amazon MQ for Apache ActiveMQ をサポート開始

AWS Fargate for Amazon ECS launches features focused on configuration and metrics

  • 設定とメトリクスを改善
  • 複数の環境変数を1つのファイルに保存してコンテナ全体から参照
  • ネットワークの送受信量のメトリクス
  • launch type、ARNといったメタデータが利用可能に

Amazon SQS introduces new console experience in AWS GovCloud (US) regions

暗号化キーを使用して Amazon DynamoDB グローバルテーブルの暗号化が可能に

  • グローバルテーブルのカスタマーマネージドキーを選択できるように
  • KMS でカスタマーマネージドカスタマーマスターキー (CMK) を使用して DynamoDB グローバルテーブルのデータを保護

Amazon CodeGuru Profiler が、AWS Lambda 関数のプロファイリングを簡素化

  • Amazon CodeGuru Profilerを簡単に有効にできるようになり、コード変更や再デプロイが不要に
  • Amazon Corretto を使用するすべての AWS Lambda 関数に適用

Amazon DynamoDB テーブルデータを Amazon S3 のデータレイクにエクスポートして、あらゆる規模での分析を実現

  • S3にデータをエクスポートできるように
  • つまりAmazon Athena、Amazon SageMaker、AWS Lake Formationとかとの連携がやりやすく

Amazon Neptune がイベント通知のサポートを開始

  • Amazon Simple Notification Service経由で通知可能
  • つまりLambdaで処理することもできる

AWS AppSync がアジアパシフィック (香港) 、中東 (バーレーン)、および中国 (寧夏) リージョンでご利用可能に

欧州 (ミラノ)、中東 (バーレーン)、およびアジアパシフィック (香港) の各リージョンで、AWS Amplify Hosting の一般提供を開始

AWS Lambda でカスタムの送信先へのログ送信が簡単に

  • Lambda Extentionsで新たにRuntime Logs APIが追加
  • Lambda 実行環境から直接、ログストリームをサブスクライブできる
  • つまり任意の送信先へ送信可能に

AWS Step Functions が Amazon EKS サービスとの統合のサポートを開始

  • Amazon EKS でタスクを起動し、その完了を待つステップを含むワークフローが構築できるように

AWS Step Functions が Amazon API Gateway サービスとの統合サポートを開始

  • これ地味によい
  • Lambdaで外部API呼び出しとかしなくてよくなった
  • つまりAPIコールして戻ってくるまでの無駄な待ち時間のLambda課金もなくなる

Amazon Cognito が、欧州 (ストックホルム) および欧州 (パリ) リージョンで利用可能に

Amazon EventBridge がイベントバスのリソースポリシーの改善を発表

  • クロスアカウントアクセスが簡単に

AWS Pricing Calculator now supports Amazon DynamoDB

You now can restore Amazon DynamoDB tables even faster when recovering from data loss or corruption

  • DynamoDBのレストアが改善されてより速くなった

Now you can use Amazon Kinesis Data Streams to capture item-level changes in your Amazon DynamoDB tables

  • DynamoDBテーブルのアイテムレベルの変更をKinesisデータストリームとして取り込めるように

You now can use a SQL-compatible query language to query, insert, update, and delete table data in Amazon DynamoDB

  • PartiQLというのはSQLコンパチのクエリ言語
    • RDBだけでなくNoSQLデータベースやCSVファイルなどのデータソースを横断的に問い合わせ可能

AWS Copilot CLI is now Generally Available

Announcing Code Signing, a trust and integrity control for AWS Lambda

  • より信頼性高くLambdaを利用できるように
  • コードに署名することで信頼され検証されたコードのみがデプロイされるように
  • 署名付きのコードをデプロイすると、チェックしてコードが改ざんされていないことを確認する
  • フルマネージドなコード署名サービスであるAWS Signerを利用

AWS Lambda now supports batch windows of up to 5 minutes for functions with Amazon SQS as an event source

  • メッセージの待機時間を設定可能に
  • すぐに処理しなければいけないようなワークロードではない場合に、待たせることで呼び出し回数が減るのでコストの最適化ができる
  • 最大300秒

AWS Lambda now supports Advanced Vector Extensions 2 (AVX2)

  • 機械学習推論とか科学シミュレーションといったCPU負荷の高いワークロード向け
  • AVX2 がサポートされるライブラリとか使ったりフラグを設定して再コンパイルするとかで利用可能
  • 追加コストなし

AWS Step Functions now supports Synchronous Express Workflows

  • Express Workflowsの同期実行
  • API Gatewayの背後にあるマイクロサービスのオーケストレーションみたいな大量かつ短時間の同期ワークフローを管理するのに最適

Amazon EventBridge adds Server-Side Encryption (SSE) and increases default quotas

Amazon Cognito is now available in the South America (Sao Paulo) and US West (N. California) Regions

Introducing Amazon Managed Workflows for Apache Airflow (MWAA)

  • Apache Airflowのマネージドサービス
    • Airflowはワークフロー管理のOSS
    • 機械学習のパイプライン作ったりとか
  • これまでオンプレでAirflowを運用していた人がAWS移行する場合などに

その他ブログなど

User State Driven System with Amazon EventBridge & KARTE について話してきました | PLAID engineer blog

  • EventBridgeのSaaS PartnerであるPLAIDさんによるEventBridgeを使ったKARTEの連携例

mackerel-lambda-agent を作ってみた話 - pyto86のブログ

  • Lambda Extensionsを使ってMackerelのエージェントをGoで実装

シングルバイナリにこだわる - AWS Lambda編 / Nature Bath vol.6 - Speaker Deck

  • Lambdaファンクションのデプロイにのみ特化したデプロイツールであるlambrollの作者の方の資料
  • LambdaとCLI、どちらで実行しても動くものを1つのバイナリで作る
  • Go

はじめてのサーバーレス ~ サーバーレスな会員制サイトを作ってみよう ~ 第 1 回 - builders.flash☆ - 変化を求めるデベロッパーを応援するウェブマガジン | AWS

  • サーバーレスな会員制サイトを作るハンズオン
  • 作るものはAPI Gateway、Lambda、DynamoDB、Cognitoを使ったオーソドックスなもの
  • ハンズオンでは開発環境としてCloud9を利用

物流支援サービスを支えるAWSサーバーレスアーキテクチャ戦略 - ZOZO Technologies TECH BLOG

  • FBZという、ZOZOTOWNと出店ブランドの自社ECサイトでの在庫の一元管理を実現するAPIサービス
  • マスタであるZOZOTOWNの在庫情報を素早く自社ECサイトへ連携できるかが重要な要素の1つ
  • AWSのフルマネージドサービスを最大限に活用
  • ファンクションの数は約500!!!

フロントエンド開発者も知っておきたい AWS Lambda とサーバーレス / Serverless for frontend developers - Speaker Deck

  • 11/9のFrontend Studyで僕が講演した際の資料です

マイクロサービスにおける性能異常の迅速な診断に向いた時系列データの次元削減手法 - ゆううきブログ

  • AWSのサーバーレスは直接関係ないけど、分散システムにおける異常の特定について
  • 『異常発生時に観測されたすべてのメトリックから診断に有用なメトリックを高速に抽出可能な次元削減手法であるTSifter』の研究と提案

AWS Lambdaのデプロイパッケージをどの範囲で構築すべきか | Developers.IO

  • みんな悩んでるデプロイパッケージの単位に関する考察
  • Lambda Layerについても

FBZにおけるドメイン駆動設計(DDD)とサーバーレスアーキテクチャを組み合わせた設計戦術 - ZOZO Technologies TECH BLOG

  • ZOZOの話の続き
  • ここでは主に設計面の話
  • 設計していく上での具体的な課題とそれに対してどう対応していったか

AWS DevDay Online Japanに登壇しました | TECH | NRI digital

  • エンタープライズに多い自社の複数サービスにおけるエンドユーザーの認証の統合
  • 既存の共通認証基盤や3rd PartyのID管理サービスとの認証連携・認可機能を実装することは大変
  • AmplifyとCognitoでこれらを実装する場合の話

Next.jsをサーバーレスでやっていくためのServerless Next.js Component - Sweet Escape

  • 11/27のイベント資料

[AWS Black Belt Online Seminar] 形で考えるサーバーレス設計 サーバーレスユースケースパターン解説 資料及び QA 公開 | Amazon Web Services ブログ

AWS LambdaでAPI開発するときのパターン集 - Qiita

  • API開発するときのLambdaファンクションの切り方に関する考察
  • 個人的には新たに作る場合は2と3のパターンはもったいない気もする。。。
  • コードストレージも考慮するといいかもしれない

Application integration patterns for microservices: Running distributed RFQs | AWS Compute Blog

Understanding asynchronous messaging for microservices | AWS Compute Blog

Application integration patterns for microservices: Fan-out strategies | AWS Compute Blog

Application integration patterns for microservices: Orchestration and coordination | AWS Compute Blog

  • マイクロサービスのためのインテグレーションパターンに関するシリーズ
  • scatter-gatherパターンの紹介やファンアウトにおけるパターンとか
  • 英語

Serverless Architecture Patterns in #AWS - DEV

  • 7パターンがシンプルに整理されている
  • 一目瞭然のアーキテクチャ図の掲載のみ
  • 実際にはこのパターンの組み合わせで作られてることがほとんどだと思う

Next.jsをサーバーレスでやっていくためのServerless Next.js Component

今回は最近その存在感がますます上がっているNext.jsとサーバーレスの話です。

はじめに

この投稿は2020年11月27の21時から開催予定のイベント(ライブストリーミング)で話す内容です。

serverless-newworld.connpass.com

もし間に合えば、かつ時間があればぜひライブ配信のほうにも参加ください。

さて、今回は11/9に登壇させていただいたFront-End Studyでの話でも少し紹介したServerless Next.js Componentについて取り上げます。

僕は昨今のフロントエンドWeb周りの技術では最近は一番Next.jsが好きなんですが、そのNext.jsで作ったアプリケーションをAWSのサーバーレスで動かしていくって話です。Static Site Generation(SSG)したものをS3などで配信していくというのはよくある話ですが、もちろんServer Side Rendering(SSR)も可能です。

さて、SSRとサーバーレスと言えば過去に一度やっていて、そのときはNuxt.jsを使って説明しました。そのあたりはこちらにまとまっています。

www.keisuke69.net

前回のNuxt.jsの際にも言及したように、aws-serverless-expressを使ってサーバーレスでSSRやるのは簡単ではあるものの、一方で無駄も多いです。そこで、本来であればその無駄を最適化するために自分で手を動かしていく必要があったりするのですが、Next.jsを使っている場合はServerless FrameworkのプラグインであるServerless Next.js Componentを使うとこの辺をうまいことやってくれます。しかもちょっとやるだけなら超絶簡単

というわけでやっていきます。今回の環境は以下を前提とします。

Lambdaのランタイム: Node.js 12.x
Next.js 10.0.3

では早速やっていきます。

(2020.11.27 Update)

上記ライブ配信アーカイブが公開されています。3:25あたりから始まります。

https://www.youtube.com/watch?v=r0OdiKoMmig


サーバーレスアンチパターン今昔物語 第七夜

チャンネル登録してくれると更新通知も飛ぶのでどうぞ。

サンプルアプリ

今回もデプロイするためのサンプルアプリを用意しています。ソースコード一式はこちらにおいておきました。

Nuxt.jsのときと同様に簡単なブログです。コンテンツについても前回同様はてなブログでやっている別のブログWordPressにインポートしてWordPressAPIを叩く感じになっています。

使うWordPress自体は今回は新たに作成せずに前回作ったものがまだWordPress.com上で動いていますのでそれをそのまま使っています。

Next.jsで作ったアプリそのものについてもNuxt.jsのときと同様に大したものではないので詳細は割愛します。構成としては投稿をリストするトップページとそのページからリンククリックで遷移する個別のページです。URLとしては以下のような感じです。

  • / - トップページ兼一覧ページです。個別の記事へのリンクを一覧表示します。(SSR
  • /posts/[id] - 個別の投稿ページです(SSG)
  • /about - SSGとSSRの確認テスト用

今回は全部SSGでもいいようなアプリケーションなのですが、それでは話が微妙なのでトップページの/SSRで処理しています。あと、実際のところSSGとSSRのどっちで動いてんのかわからん!とか挙動を確認してみたい!って目的のために/aboutというページを用意しています。残りは全てSSGです。

さて、以前にSSRをLambdaでやったときには大きく以下のような手順を踏むという話をしました。

  1. Nuxt.js / Next.jsで作ったアプリをExpressで動かす
  2. Expressで作ったアプリをLambdaで動かす

今回はこういった手順を踏まずにServerless Next.js Componentでやっていきます。

ちなみにこのアプリケーションをyarn buildするとこんな感じになっています。 f:id:Keisuke69:20201127082318p:plain

これを見ておわかりのように//api/helloSSRされ、/posts/以下はSSGで各IDごとにPre-Renderingされています。

Serverless Next.js Component

AWSを始めとするサーバーレス環境のデプロイやプロビジョニングツールであるServerless Frameworkの関連機能であるServerless Componentの一つです。 Serverless Componentっていうのは超絶簡単に説明するとServerless Frameworkという仕組みを通じてユースケースを意識したServerless Applicationをデプロイできるというものですが、正直に言うとあまり詳しく知らないです。 今回利用するServerless Next.js ComponentはNext.jsをサーバーレス環境にいい感じでデプロイしてくれるServerless Componentです。

github.com

このServerless Next.js Componentの特徴としては、ざっくり言うとNext.jsのSSRをLambda@Edgeで実現してくれるというものです。Nuxt.jsでやったときのようにaws-serverless-expressを使ってAmazon API GatewayAWS Lambdaを使って実現するのではなく、AWSCDNであるCloudFrontのエッジサーバ上で稼働するLambda@Edgeを利用します。

また、aws-serverless-expressでやる場合、そのままだとリソースの観点で無駄が多いという話をしましたが、Serverless Next.js Componentでデプロイすると静的なアセットや静的ファイルとして生成されたものはS3でホスティングするようにデプロイした上でCloudFrontを使って配信されるようになります。

また、Lambda@Edgeで静的ページへのリクエストをハンドリングしてSSRしないリクエストはS3へとフォワードしてくれます。またいわゆるルーティングもやってくれるんですが、Dynamic Routingもサポートされています。

こういったことを、Next.jsが標榜するのと同じZero Configでできます。まじでめっちゃ簡単です。しかも今回はCloudFormationベースでのdeployではないこともあってデプロイ自体が速いですね。

さて、Lambda@Edgeを使うってこともさることながら、静的アセットや静的ファイルのみS3とCloudFrontを使ってサービスするというのは口で言うのは簡単ですが想像以上に面倒だと思います。プロダクション用にビルドしてできあがったもののうち、静的なもののみS3にデプロイするってのはCI/CDのようなパイプラインで考慮する必要があり多少作り込む必要もあります。ビルドしたものを何も考えずにごそっとデプロイするってわけにはいかないんですね。

また、Lambda@EdgeでルーティングやSSG、SSRのハンドリングといったことを自前で実装するのは結構たいへんです。

このあたりをまるっとやってくれるServerless Next.js ComponentはNext.jsを使ってる人にはとてもいいものだと思います。というかNext.jsをサーバーレスでSSRやるにはこれ一択と言ってもいいんじゃないかなと思ってます、個人的には。

デプロイ

実際のところ前回やったNuxt.jsのときのようにサーバーレスで動かすために実装しなければいけないこと、設定とかを特に必要としません。今回のサンプルアプリも実際には普通のサーバーとかでも動きます。

Serverless Frameworkベースなのでserverless.yamlを用意します。クレデンシャルなどのServerless Framework使う上で必要な設定はやっておいてください。serverless.yamlの中身は以下のように。これはデフォルトでカスタムドメインはCloudFront周りの設定などもう少し細かく設定することも可能ですが、これだけでも十分問題なく動きます。まさにZero Config。

myNextApplication:
  component: "@sls-next/serverless-component@1.18.0"

myNextApplicationの部分は好きに定義して大丈夫です。一点注意があるとするとバージョン番号(今回であれば1.18.0)を指定すること、そして必ず最新版を入れたほうがいいです。使い始めてからもなるべく最新版を使い続けるようにしたほうがいいです。自分の経験では少し古いバージョンでも動かないことがありました。

あとは同じServerless FrameworkといってもこちらはComponentということもあってかオリジナルとは微妙にフォーマットが違うそうです。

ファイルを用意したらシンプルに、

$ serverless

と実行してください。通常のServerless Frameworkを使うときのようにserverless deployやsls deployではなくserverless`とだけ実行してください。実行完了までにかかる時間は恐らく生成されるページの数などによって左右されると思います。また初回実行時はCloudFrontのディストリビューション作成を伴うため、有効になるまで少し時間がかかります。

実行が完了するとこんな出力がされます。

serverless

  myNextApplication: 
    appUrl:         https://<abcdefghijklm>.cloudfront.net
    bucketName:     abcdfeg-abcdefg
    distributionId: XXXXXXXXXXXXX

  ******************************************************************************************************************************************************************
  Warning: You are using the beta version of Serverless Components. Please migrate to the GA version for enhanced features: https://github.com/serverless/components
  ******************************************************************************************************************************************************************


  162s › myNextApplication › done

このときは初回だったので162秒かかったようです。ここにあるappUrlというのがCloudFrontで配信されているエンドポイントですね。なのでこちらにブラウザでアクセスしていきます。なお、カスタムドメインを利用することももちろん可能です。

今回はブログということで全部SSGにしてしまっていたのですが、無理やりindexのページだけSSRをするようにしています。

なのでアクセスしてみるとわかるのですが各ページへのアクセスは速いです。一方でトップページへのアクセスはSSRが実行されているので他と比べると多少遅いはずです。

なお、ドキュメントではgetInitialPropsを使っている場合にSSRするとなっていますが、9.3以降で推奨のgetServerSidePropsにも対応しています。もちろんgetStaticPropsgetStaticPathsにも対応。

また、serverlessを実行すると以下の内容のnext.config.jsが一時的に生成されます。

module.exports = { target: 'serverless' };

注目はターゲットがserverlessであるということです。これは何かというとNext.js8からサポートされたもので、ページごとに出力します。このファイルは実行完了時に自動的に削除されます。

作成されるリソース

実際にデプロイすると以下のようなリソースが作成されています。御覧のようにサーバーレスでWebっていうと出てくることが多いAmazon API Gatewayの姿がありません。

CloudFrontのディストリビューション

オリジンとして一緒に作成されたS3のバケットが指定されています。バケットというかS3でStatic Website Hostingした際のURL。そしてOAIが設定されているのでCloudFront経由のリクエストしか届かないようにも設定されています。 特徴的なのがBehaviorの設定ですね。こんな感じになってます。

f:id:Keisuke69:20201127015136p:plain

これってつまりNext.jsをビルドしたときに生成されるディレクトリやそこへのパスを元にリクエストの振り分け設定がされています。具体的には静的なファイルなど基本的にすべてS3を使ったオリジンが指定されていますね。

Lambdaファンクション

Lambdaのほうはたった2つのファンクションがデプロイされているだけです。

defaultとapi用でどちらも512MBメモリです。

これらのファンクションがLambda@Edgeとして実行されるように設定されています。

S3バケット

S3はこんな感じで、静的Webサイトとして配信するための設定がされています。 f:id:Keisuke69:20201127020233p:plain

大まかな挙動

Serverless Next.js Componentを使ってデプロイした際の挙動について簡単に解説します。基本的にはビルド結果の生成物をS3に種別ごとにフォルダをわけて格納し、リクエストのパスを元に振り分けるという感じになります。その振り分けを行うのにCloudFront上でのBehaviorとLambda@Edgeが使われます。

まず、Behaviorについて見ていきます。作成されるのはDefalutとそれ以外の4種類で計5種類です。Behaviorというのは指定したリクエストパスのパターンでオリジンを変更したり異なる設定をしたりするもので、それが5パターンあると思っていただくといいです。それが以下の5種類です。

  • _next/static/*
  • static/*
  • api/*
  • _next/data/*
  • Default(*)

_next/static/*static/*は来たリクエストをそのままS3へと転送します。

api/*Origin Requestイベントに対してAPI用のLambda関数が設定されています。Origin RequestイベントってのはCloudFrontがリクエストをOriginに転送したときにのみ関数が実行され、CloudFrontのキャッシュから返される場合は実行されないというものです。ここでAPIへのリクエストをハンドリングします。ここでいうAPIってのはNext.jsで作成可能なAPIのことですね。

Next.jsではサーバーサイドで実行するAPIのエンドポイントも作成可能になっています。これはpages/api配下にファンクションを作ることで実現するのですが、これをいわゆるサーバーレス環境のファンクションとしてデプロイ可能となっています。ただし、あくまでも汎用的なファンクションシグネチャとなっていてLambdaそのもののフォーマットとは少し異なります。

こんな感じのものを用意します。

export default (req, res) => {
  // ...
}

これをyarn buildすると.next/serverless/pages/api/の下にビルドされたものができあがるのですが、Serverless Next.js ComponentはこれをLambdaファンクションのデプロイパッケージに含める形でデプロイされます。なお、LambdaファンクションとしてはServerless Next.js Componentが生成するindex.jsが登録されていて、APIへのリクエストに応じて呼び出す形になります。実際に登録されるindex.jsは御自身の開発環境のプロジェクトフォルダ内の.serverless_nextjs/api-lambda/index.jsです。

_next/data/*もLambda関数が紐付けられています。こちらはOrigin RequestOrigin Responseの両方でどちらも同じLambda関数で処理されています。Origin ResponseはOriginからのレスポンスを受け取ってキャッシュする前に実行されるというものです。Originからエラーが返ってきても実行されますが、Origin Requestで実行された関数からレスポンスが生成された場合は呼び出されません。

ここでは3種類のリクエストをハンドリングします。ここでいう3種類とは、

  • サーバーサイドレンダリング
    • getInitialPropsやgetServerSidePropsが使われているページはこの時点でレンダーされ、すぐにレスポンスされます
  • 最適化された静的ページ
    • Next.jsによってプリコンパイルされたHTMLページへのリクエストはS3に転送されます
  • パブリックリソース
    • いわゆるルートレベルの静的なアセットたちですね。faviconとかの。これらもS3へと転送されます。

静的ページとパブリックリソースもLambdaファンクション通るのはなんで?って思ったかもしれませんがこれはそのルートがパスのパターンマッチングで特定できないからだそうですがちょっと深堀りできていないです。

最後のDefaultも_next/data/*と同様のようです。同じ関数、同じイベントが設定されています。

つまり、上から順にリクエストされたURLのパスを評価していって、マッチしたパターンがあればオリジンにそのまま転送したりしていくのです。

なお、デプロイごとにCacheのInvalidateも行われます。これは/*を対象に行われます。

できないこと

さて、こんな感じで割と簡単に利用できるServerless Next.js Componentなんですが、実は最近のNext.jsにおける最注目機能といっても過言ではないIncremental Static Regeneration(ISR)には対応していません。ISRとはすごく雑に説明すると『基本的にはキャッシュから返しつつ、有効期限を過ぎたら非同期でキャッシュの更新をSSRで行う』っていうものです。Cache Controlにおけるstale-while-revalidateと同じような考え方が適用されたものと言ってもいいかもです。Next.js 9.4から追加された機能です。

これの嬉しさについては別のサイトに譲るとして、SSGとSSRそれぞれ辛みがあるわけですがその辛みの一旦を解消してくれそうな革命的な機能です。つまり、これまでパフォーマンス的に、スケーラビリティ的に、運用的にはSSGのほうが楽ではあるものの、SSRでないと動的な処理などは実現できないことがあったわけです。一方でSSGはその性質上ページの数やコンテンツの数が多くなるとビルドが思くなるという課題もありました。それをISRでは言葉どおり段階的にしつつ、CDNのキャッシュを有効活用しつつ、動的に近いこともできるようになった感じですね(実際には動的ではないですが)。

とういわけでこれに対応されるととてもいいのですが、残念ながら現状ではまだ対応されていません。一応、Issueは起こされているので近い将来対応することが期待されます。。。

まとめ

今回はNext.jsのアプリケーションをAWSのサーバーレス環境でServer Side Renderingしていく上で非常に簡単に使えるServerless Next.js Componentの紹介でした。とても使い勝手はいいのですが、破壊的なアップデートもガンガン入ってたりするのでそのあたり気をつけつつ使ってもらえるといいんじゃないでしょうか。

きっとNuxt.js向けの似たようなものもそのうち出てくると期待。

©Keisuke Nishitani, 2020   プライバシーポリシー