Table of Contents
Next.jsをデプロイするぞ!
いま、Next.jsを使って開発を行なっています。 Next.jsのデプロイ先としては、開発元のVercelが提供するプラットフォームVercel Platformがあります。
公式が言うにはVercel Platformが推奨ということにはなっていますが、今回はバックエンド側もAWS上にあるので、フロントエンドもAWSにあったほうが何かと便利!ということでAWS上にデプロイすることにしました。
Serverless Next.js Componentを使うぞ!
デプロイにはServerless Next.js Componentを使います。
Serverless Componentsは、Serverless Frameworkを介してサーバーレスなアプリケーションのよくある構成を設定ファイルだけでいい感じにデプロイしてくれる便利なヤツです。
Serverless Next.js ComponentはそのNext.jsデプロイ用コンポーネントです。CloudFrontとAWS Lambda@Edgeにデプロイしてくれます。
シンプルにデプロイするぞ!
デプロイするだけなら超簡単です。
Next.jsのプロジェクトルートで、serverless.yml
という名前のファイルを作ります。
{version_here}
にはバージョンを入れます。2020/12/19時点で最新版は1.18.0
です。
myNextApplication: # 名前はなんでもいい
component: "@sls-next/serverless-component@{version_here}"
そして、おもむろに以下のコマンドを叩きます。
AWS_PROFILE
に与えるのはAWS CLIのプロファイル名です。
必要なパーミッションは公式のREADMEを参照してください。
$ AWS_PROFILE={profile_name_here} npx serverless
なんとこれだけでデプロイできてしまいます!
設定がなさ過ぎて不安になりますが、本当にこれだけです。 すごいぞ!Serverless Components!
デプロイ先をstaging / productionで切り替えるぞ!
ここから実運用ができるよう頑張っていくわけですが、 まずしないといけないのが、デプロイ先をstaging / productionで切り替えることです。
問題は2つ。
- 設定ファイルの名前は
serverless.yml
のみで、オプションで指定することができない。 - デプロイ時にできる
.serverless
ディレクトリにCloudFrontの設定等が保存されているが、こちらも名前が固定なのでデプロイ先を切り替えると上書きされてなくなってしまう。
これらを解決するために、ちょっと泥臭いですがデプロイ用のスクリプトを書きました。 書いてあるとおりですが、以下のことをしています。
- staging/production用の設定ファイルを都度プロジェクトルートにコピー
.serverless
ディレクトリの中身をS3に退避、復元
#!/bin/bash
set -e
export APP_NAME=sample-app
export AWS_PROFILE=$APP_NAME-$STAGE
export BUCKET_NAME=$APP_NAME-config-$STAGE
# 念のためクリーンアップ
if [ -e ./serverless.yml ]; then
rm ./serverless.yml
fi
if [ -d ./.serverless ]; then
rm -rf ./.serverless
fi
if [ -d ./.serverless_nextjs ]; then
rm -rf ./.serverless_nextjs
fi
# serverlessの設定ファイルをコピー
cp ./bin/serverless/serverless.$STAGE.yml ./serverless.yml
# S3からデプロイ設定ファイルを復元
aws s3 cp s3://$BUCKET_NAME/.serverless ./.serverless --recursive
# デプロイ
npx serverless
# S3にデプロイ設定ファイルを退避
aws s3 cp ./.serverless s3://$BUCKET_NAME/.serverless --recursive
# 後片付け
rm ./serverless.yml
rm -rf ./.serverless
rm -rf ./.serverless_nextjs
ディレクトリ構造は以下です。
APP_ROOT
├── ...(その他いろいろ)
└── bin
├── serverless
| ├── serverless.stg.yml # staging用
| └── serverless.prd.yml # production用
└── deploy.sh # ↑のスクリプト
AWS CLIのプロファイル名は$APP_NAME-$STAGE
と合うように設定しておいてください。
また、事前に$APP_NAME-config-$STAGE
の名前でS3バケットを用意してください。
こうしておけば、例えばstaging環境にデプロイするときは以下のコマンドを叩けばOKです。
package.json
に設定しておけば便利です。
$ STAGE=stg ./bin/deploy.sh
設定をカスタマイズするぞ!
リソース名を固定する
なにも設定しなければ、S3のバケット名やLambda@Edgeの関数名がランダムになってしまいます。
何のリソースなのか分かるよう、名前を指定しておきましょう。{app_name_here}
にはアプリ名を入れます。
IAMロールも作られますが、なぜかこれは名前を固定する設定がありませんでした。。
myNextApplication: # 名前はなんでもいい
component: "@sls-next/serverless-component@{version_here}"
inputs:
bucketName: "{app_name_here}-stg"
name:
apiLambda: "{app_name_here}-api-func-stg"
defaultLambda: "{app_name_here}-default-func-stg"
Lambda@Edgeのスペックを指定する
SSRをする場合、ある程度の規模のアプリケーションになるとLambdaの初回起動時の処理が重くなり、デフォルトだとタイムアウトして503が返ってくることがありました。 アプリケーションの内容に合わせて適切にスペックを指定しましょう。
myNextApplication: # 名前はなんでもいい
component: "@sls-next/serverless-component@{version_here}"
inputs:
memory:
defaultLambda: 2048
apiLambda: 1024
timeout:
defaultLambda: 10
apiLambda: 10
stagingにBasic認証やIP制限をかける
staging環境のアクセスは制限したいですよね。 アクセスの前にアクセス制限の処理をするLambda@Edgeを実行するようにしましょう。 Serverless ComponentsにはLambdaを作る機能はないので、別途作ってLambda@Edge関数のARNを指定します。
Lambda@Edgeを作る際には以下の点に注意しましょう。
- リージョンは
us-east-1
(バージニア北部) - 指定するARNには
$LATEST
やエイリアスが使えないので、バージョンを発行する必要がある
myNextApplication: # 名前はなんでもいい
component: "@sls-next/serverless-component@{version_here}"
inputs:
cloudfront:
defaults:
lambda@edge:
viewer-request: arn:aws:lambda:us-east-1:xxxxxxxxxx:function:BasicAuthentication:1
たとえばBasic認証をかける場合は次の記事が参考になると思います。 CloudfrontとS3でBasic認証をかける - Qiita
ただ、Basic認証に関してはServerless Next.js Componentの1.19.0-alpha.3からserverless.yml
の設定で実現できるようになっているようです。
コードサイズを削減する(experimental)
デフォルト設定では、node_modulesの内容がSSRを行う画面ごとにまるっと入ってしまうため、SSRの画面が増えるとわりと簡単にLambdaのコードサイズ制限50MBをおびやかします。 SSRの画面はなるべく減らしましょうという話ではあるのですが、減らすのもなかなか大変です。特に認証が絡んでくると。
useServerlessTraceTarget
を使うとnode_modulesの中で実際に使われているものだけが入るようで、大幅にサイズが減ります。が、まだ "experimental" なのでご注意ください。
myNextApplication: # 名前はなんでもいい
component: "@sls-next/serverless-component@{version_here}"
inputs:
useServerlessTraceTarget: true
また、これを使う際には環境変数NODE_ENV
にproduction
を入れておく必要があります。
プロジェクトルートに.env.production
ファイルを作り、以下のように書きましょう(next.jsの機能です)。
NODE_ENV=production
まとめ
お試しでやってみるだけであればほぼ設定なしでいけますが、本番利用にはちょっとコツがいりました。 みなさまのNext.jsの本番利用が捗れば幸いです。
kta-m
先進技術部門 IoTチーム チームリーダー