この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、岩城です。
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/serverless-component@1.15.1"
普段CloudFormationやTerraformを使っている身からすると、この内容だけで前述のAWS環境がデプロイできてしまうのはすごいです。
ただし、この内容だとバケット名やLambda関数がランダムな文字列で設定されてしまいます。このため本エントリではinputs
で必要な情報を設定しました。
# serverless.yml
myApp:
component: "@sls-next/serverless-component@1.15.1"
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/serverless-component@1.15.1"
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な環境を構築できるのは魅力的ですが、何が設定されているか把握しないまま利用するのは危険です。まずは検証環境でどのような設定がされているかを確認しましょう。
本エントリがどなたかのお役に立てれば幸いです。
リファレンス
試す中で色々と躓い際、以下の記事に助けられました。ありがとうございます。