【GitHub Actions】Next.jsのPreview Mode + microCMS(EC2・S3への自動デプロイ設定)
現在、とあるサイトを Next.js + microCMS で運用している。そして、インフラ環境は、CloudFront + Amazon S3 構成としている。今回、エンジニア以外の人がmicroCMSで記事を執筆して、プレビュー画面で見栄えも確認したいのに、気軽に確認できない。という問題にぶつかった。今回は、突貫作業で EC2 にローカル環境と同一のサイトを構築し、プレビューできる環境を用意してみた。誰かの参考になればと思い、備忘録として残しておく。
- Next.js の Preview Mode
- システム構成概要
- EC2 環境構築
- IAMユーザー作成
- GitHub Actions作成(Previewページ用)
- microCMS用に、GitHubでトークンを発行する
- microCMSにGitHub ActionsのWebhookを追加する
- GitHub Actions作成(本番へのデプロイ用)
- まとめ
Next.js の Preview Mode
Next.js 9.3から、ヘッドレスCMS向けに作られた機能として、Preview Modeが追加された。静的サイト生成(SSG)による Jamstack 構成は高パフォーマンス、高セキュリティを実現できるが、プレビューの実現には毎回ビルドする必要があり、少し手間がかかってしまう部分があった。Preview Modeでは、サーバーレス関数を起動できるAPI Routes機能を利用して、サーバーサイドレンダリング(SSR)を行い、簡単にプレビューを実現することができる。
詳細の設定方法などは、公式ページを参照して欲しい。
そして、Next.js アプリで SSR(Server-side Rendering)や API ルートなどの機能を使用している場合、Next.js サーバー上で Web サイトをホスティングする必要がある。そして、現状そのような環境をサーバーレスなサービスとして提供しているのは、Vercel のみである。
ただ、現状 Vercel は使っておらず、AWS 環境しか使っていなかったので、今回は、AWS の EC2 でプレビュー用のページを作ることにした。
システム構成概要
EC2には、Node.jsをインストールして、Next.jsを動かせるようにする。そして、開発サーバーを起動しておく。microCMSのAPI設定の画面プレビュー設定のURLを以下のようにしておくことで、プレビュー画面を表示することができる。
http://<-EC2のPublic IP address->/api/preview?slug={CONTENT_ID}&draftKey={DRAFT_KEY}
セキュリティの問題もあるため、プレビュー画面が閲覧できるのは、社内からのみなど、EC2のセキュリティのインバウンドルールを適切に設定しておく。
また、デザイン変更などをした場合に、自動的にプレビュー画面と本番環境に反映させられるように、Github Actionsを設定した。
EC2 環境構築
少人数で利用するNext.jsのプレビュー画面用なので、「t2.micro」で構築した。(Node.jsの環境構築に関しては、今回説明を割愛する。)
今回、next dev
で開発サーバーを起動しておけばいいのだが、プロセス管理にSupervisorを導入した。導入した理由は、プロセスの管理がしやすいことと、開発サーバーをデーモン化させて、autorestartなどをさせたかったことが挙げられる。Supervisorのインストールなどは、以前の記事を参考にして欲しい。今回のSupervisorの設定ファイルを参考として紹介する。
[program:preview] directory=/var/www/html/sample-website command=/bin/bash -c "/opt/nvm/versions/node/v14.17.0/bin/node /var/www/html/sample-website/node_modules/.bin/next dev" autostart=true autorestart=true startsecs=3 user=ec2-user redirect_stderr=false stderr_logfile=/var/www/html/log/preview.stderr.log stdout_logfile=/var/www/html/log/preview.stdout.log
上記の設定をしておくことで、プロセス管理が簡単にできる。
# 起動 $ supervisorctl start preview # ステータス確認 $ supervisorctl status preview # 停止 $ supervisorctl stop preview # 再起動 $ supervisorctl restart preview
開発サーバーが起動している状態で、microCMSの「画面プレビュー」ボタンを押すと、プレビュー画面を閲覧する環境を構築することができた。
IAMユーザー作成
Github Actionsで、AWSにデプロイするために、IAMユーザーを新規に作成しておく。割り当てておくべきアクセス権限のポリシーは、以下の通りである。
- EC2デプロイ用
- AmazonVPCFullAccess
- AmazonEC2ContainerServiceRole
- S3 + CloudFront用
- AmazonS3FullAccess
- CloudFrontFullAccess
アクセスキーを作成して、AWS_ACCESS_KEY_ID
とAWS_SECRET_ACCESS_KEY
を取得しておく。
GitHub Actions作成(Previewページ用)
GitHubから、EC2へのデプロイに関しては、以下の方法で行うことにした。
- Github Actions の Public IP address を確認する
- AWS の Credential を設定する
- EC2 の Security Group に Github Actions の Public IP address を追加する
- EC2 に Github Actions から SSH アクセスして、デプロイ作業をする
- 先ほど追加した、Github Actions の Public IP address を削除する
IPの追加に関しては、AWS CLI の athorize-security-group-ingress を用いた。詳細は、以下の公式ドキュメントを参考にして欲しい。
GitHubのSettings > Security > Secrets から、以下のSecretsを事前に設定しておく必要がある。
- AWS_ACCESS_KEY_ID:IAMユーザーから取得
- AWS_SECRET_ACCESS_KEY:IAMユーザーから取得
- SECURITY_GROUP:EC2(セキュリティグループID)から取得
- SECRET_KEY:EC2(キーペア)から取得
- EC2_HOST:EC2(パブリックIPv4)から取得
- EC2_USER:EC2から取得
name: deploy-to-ec2 # Controls when the workflow will run on: pull_request: branches: [ main ] types: [closed] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: build: runs-on: ubuntu-latest - name: Checkout uses: actions/checkout@v2 - name: Public IP id: ip uses: haythem/public-ip@v1.2 - name: Print Public IP run: | echo ${{ steps.ip.outputs.ipv4 }} - name: Configure AWS credentials from account uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-1 - name: Open a specific port of the security group run: | IP_ADDRESS=`echo ${{ steps.ip.outputs.ipv4 }}` aws ec2 authorize-security-group-ingress --group-id ${SECURITY_GROUP} --protocol tcp --port 22 --cidr "$IP_ADDRESS"/32 env: SECURITY_GROUP: ${{ secrets.SECURITY_GROUP }} - name: Deploy run: | echo "$SECRET_KEY" > secret_key chmod 600 secret_key ssh -oStrictHostKeyChecking=no -i secret_key ${EC2_USER}@${EC2_HOST} "cd /var/www/html/sample-website && git pull origin main && supervisorctl restart preview" env: SECRET_KEY: ${{ secrets.SECRET_KEY }} EC2_USER: ${{ secrets.EC2_USER }} EC2_HOST: ${{ secrets.EC2_HOST }} - name: Close a specific port in a security group run: | IP_ADDRESS=`echo ${{ steps.ip.outputs.ipv4 }}` aws ec2 revoke-security-group-ingress --group-id ${SECURITY_GROUP} --protocol tcp --port 22 --cidr "$IP_ADDRESS"/32 env: SECURITY_GROUP: ${{ secrets.SECURITY_GROUP }}
この設定をしておくことで、プルリクがマージされた際に、このワークフローが実行される。
microCMS用に、GitHubでトークンを発行する
microCMS の Webhook で使用するトークンを発行する。
GitHubの「Settings > Developer settings > Personal access tokens」で、「Generate new token」を選択する。
- Note:何目的で発行したトークンか区別できるようにメモを残しておく
- Expiration:期限を自由に設定する(No expiration:無期限にもできる)
- Select scopes:「repo」にチェックを入れる
最後に、「Generate token」を押すと、トークンが発行されるので、コピーして保存しておく。
microCMSにGitHub ActionsのWebhookを追加する
設定方法に関しては、公式ドキュメントを参照ください。
「トリガーイベント名」は自由に設定できるが、GitHub Actionsのワークフローの設定と一致させておく必要がある、今回は、「dispatch_cms」とした。
GitHub Actions作成(本番へのデプロイ用)
S3 + CloudFrontの環境構築に関しては、今回割愛して、GitHub Actions を用いた自動デプロイの設定だけを紹介する。
上記の設定に追加して、GitHubのSettings > Security > Secrets から、以下のSecretsを事前に設定しておく必要がある。
- AWS_PROD_DISTRIBUTION_ID:CloudFrontのディストリビューションIDから取得
name: deploy-to-s3-cloudfront-for-prod # Controls when the workflow will run on: pull_request: branches: [ main ] types: [closed] repository_dispatch: types: [dispatch_cms] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: deploy: name: build and deploy to S3 runs-on: ubuntu-latest strategy: matrix: node-version: [14.x] steps: - name: Checkout uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - name: Get yarn cache directory path id: yarn-cache run: echo "::set-output name=dir::$(yarn cache dir)" - uses: actions/cache@v2 with: path: ${{ steps.yarn-cache.outputs.dir }} key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- - name: yarn install if: steps.yarn-cache.outputs.cache-hit != 'true' run: yarn install --frozen-lockfile - name: yarn build:static run: yarn build:static - name: Configure AWS credentials from account uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-1 - name: Copy Files to S3 run: | aws s3 sync ./out s3://<-BUCKET NAME-> - name: invalidate cloudfront uses: chetan/invalidate-cloudfront-action@master env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} DISTRIBUTION: ${{ secrets.AWS_PROD_DISTRIBUTION_ID }} PATHS: '/*'
この設定をしておくことで、以下の条件下でこのワークフローが実行される。
- プルリクがマージされた場合
- microCMS からのWebhook通知があった場合
まとめ
突貫作業で作成したが、エンジニア以外の人が簡単にプレビューできる環境を作ることで、お互いに作業効率を向上させることができた。Vercelでは、今回実行したことをボタンひとつで簡単に実行できてしまうので、最高だなーっと改めて思えた。
是非とも、もっといい方法などがあれば、教えてください。よろしくお願いします。