Serverless Nextjs Pluginを試してみた
こんにちは、岩城です。
Serverless Nextjs Pluginについて調べる機会がありました。
このプラグインを使うと以下のような環境を作ってくれます。
本エントリでは、Serverless Frameworkの導入方法をはじめ、実際にデプロイしてみてどんなリソースが作成されるかを紹介します。
なお、筆者はアプリケーション開発全般よく分かりません。
やってみた
Serveless Framework
セットアップ
まっさらな環境でセットアップしたかったので、新規で起動したEC2上で試しました。
$ cat /etc/system-release Amazon Linux release 2 (Karoo)
Amazon Linux 2はデフォルトでNode.jsがインストールされていません。 はじめにNode.jsをインストールします。
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash $ . ~/.nvm/nvm.sh $ nvm install node
Node.jsがインストールされたことを確認します。
$ node -e "console.log('Running Node.js ' + process.version)" Running Node.js v14.12.0
つぎにServerless Framworkをインストールします。
$ npm install -g serverless
Serverless Frameworkがインストールされたことを確認します。
$ serverless --version Framework Core: 2.2.0 Plugin: 4.0.4 SDK: 2.3.2 Components: 3.1.4
Serverless Nextjs Plugin
セットアップ
つぎにServerless Nextjs Pluginに必要なパッケージをインストールします。
npm init -y npm install -S react react-dom next
package.json
のdependencies
に追記されることを確認します。
{ "name": "ec2-user", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "next": "^9.5.3", "react": "^16.13.1", "react-dom": "^16.13.1" } }
デプロイ
デプロイの前にAWSのクレデンシャルを設定します。
$ aws configure AWS Access Key ID [None]:XXXXXXXXXXXXXXXXXXXX AWS Secret Access Key [None]:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Default region name [None]:ap-northeast-1 Default output format [None]: $ export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX $ export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Serverless Frameworkの設定ファイルを用意します。
$ vim serverless.yaml
# serverless.yml myApp: component: "@sls-next/[email protected]"
普段CloudFormationやTerraformを使っている身からすると、この内容だけで前述のAWS環境がデプロイできてしまうのはすごいです。
ただし、この内容だとバケット名やLambda関数がランダムな文字列で設定されてしまいます。このため本エントリではinputs
で必要な情報を設定しました。
# serverless.yml myApp: component: "@sls-next/[email protected]" inputs: bucketName: "serverless-next-<AWSアカウント番号>" name: "serverless-next-func"
これ以外にもCloudFrontで利用するドメインの指定やディストリビューションの設定を行ったり、Lambda関数のメモリサイズ設定など色々カスタマイズできます。 詳細は公式サイトを確認してみてください。
デプロイ
いよいよデプロイです。
serverless
デプロイすると以下のようなエラーが出力されました。
$ serverless error: Error: Command failed with exit code 1: node_modules/.bin/next build > Build error occurred Error: > Couldn't find a `pages` directory. Please create one under the project root at findPagesDir (/home/ec2-user/node_modules/next/dist/lib/find-pages-dir.js:3:170) at build (/home/ec2-user/node_modules/next/dist/build/index.js:4:416)
pages
ディレクトリがなくエラーになるので作業ディレクトリに作成してください。
$ mkdir pages
あらためてデプロイすると今度は成功するはずです。
$ serverless myApp: appUrl: https://XXXXXXXXXXXX.cloudfront.net bucketName: serverless-next-XXXXXXXXXXXX 37s › myApp › done
コマンド自体はすぐに返ってきますが、CloudFrontのデプロイに時間が掛かります。
しばらく経った後appUrl
にアクセスすると以下のような404のページが表示されるようになります。
作成されたリソース
以前Serverless Frameworkを使ったことがあったので、当然CloudFormationが裏で動くものと想定していましたが違いました。 CloudFormationを使わずに作成されていました。
Cloud Front
Distributionの設定は以下のような感じ。
Originの設定は以下のような感じ。
Behaviorsの設定は以下のような感じ。
_next/data/*
とDefault
については、以下のようにLambda関数が設定されていたのでLambda@Edgeへのデプロイもされていました。
Lambda
Lambda関数は以下のようなコードがデプロイされていました。コード見ても私にはさっぱりなのでキャプチャにとどめておきます。
基本設定は以下のような感じ。
ロールはAWSLambdaBasicExecutionRole
ポリシーがアタッチされているだけなのでCloudWatch Logsへの権限だけ許可されていました。
IAMロール
ubj22yt-4hhif8y
という名前でIAMロールが作成されていました。
ランダムな文字列と思いつつも何度作成し直しても同じ名前になったので理由はありそうです。(調べてません)
なお、IAMロールの名前を指定する術はありませんでした。
デフォルトではAWSLambdaBasicExecutionRole
がアタッチされていましたが、DynamoDBや他のAWSリソースにアクセスする場合は事前にカスタムしたIAMポリシーを用意しておいてinputs
でpolicy
を指定します。
# serverless.yml myApp: component: "@sls-next/[email protected]" inputs: bucketName: "serverless-next-<AWSアカウント番号>" name: "serverless-next-func" policy: "arn:aws:iam::XXXXXXXXXXXX:policy/MyCustomPolicy"
S3
作成されたS3バケットは以下のような構成になっていました。
$ s3-tree serverless-next-XXXXXXXXXXXX serverless-next-XXXXXXXXXXXX ├── _next │ └── static │ ├── chunks │ │ ├── commons.cb82874e43d6dd0d0fae.js │ │ ├── framework.9ec1f7868b3e9d138cdd.js │ │ ├── main-e3b219ceef4bb4fe6eb4.js │ │ ├── pages │ │ │ ├── _app-24382224f10887fed77f.js │ │ │ └── _error-3203e7e37e39af6cd7ee.js │ │ ├── polyfills-fd3597f65753721f35bc.js │ │ └── webpack-e067438c4cf4ef2ef178.js │ └── Y49oVB2sQWN_vB8RPC8B3 │ ├── _buildManifest.js │ └── _ssgManifest.js └── static-pages └── 404.html
削除
削除コマンドが用意されており、実行すると4秒とかで返ってきますが、実際はCloudFrontのディストリビューションがDisabledされるだけで削除されていません。 リソースを完全に削除したい場合は、マネジメントコンソールなどを使って個別に削除する必要があるので注意してください。
$ serverless remove 4s › myApp › done
おわりに
簡単にLambda@Edgeな環境を構築できるのは魅力的ですが、何が設定されているか把握しないまま利用するのは危険です。まずは検証環境でどのような設定がされているかを確認しましょう。
本エントリがどなたかのお役に立てれば幸いです。
リファレンス
試す中で色々と躓い際、以下の記事に助けられました。ありがとうございます。