こんにちは、屋根裏エンジニアの折戸です。
今回はNext.jsアプリケーションをCI/CDするための設定手順についてのご紹介です。
- 構成
- 前提
- 事前準備
- ローカル環境へNext.jsアプリケーションを作成
- Git 作業
- EC2 アタッチ用ロール 作成
- CodeDeploy用ロール 作成
- CodeDeploy 作成
- CodePipeline 作成
- デプロイ先インスタンスにデプロイ先ディレクトリ 作成
- CodeBuild サービスロールへ接続使用権限 付与
- リポジトリへ設定ファイルなどをPush
- CI/CD確認
- 【参考】デプロイ時のログ
- 【参考】CodeBuild アーティファクト確認
- 【参考】ハマリポイント
- 最後に
構成
- AWS CodePipeline(以下、CodePipeline)のソースステージでGitHubのリポジトリのPushを検知
- ソースコードをS3のSourceArtiへ保存
- AWS CodeBuild(以下、CodeBuild)でbuildspec.ymlを元にソースコードをビルド
- ビルドファイルをS3のBuildArtifへ保存
- AWS CodeDeploy(以下、CodeDeploy)でappspec.ymlを元に任意のEC2へデプロイ
これらの一連の処理をCodePipelineでまとめて自動化する様な構成です。
前提
- CodePipeline作成の流れで同時にGitHubリポジトリとCodeBuildを設定できますが、 CodeDeployは事前に作成しておいた方がスムーズに設定できるため、CodeDeploy関連のリソースを先に作成する手順としています。
- ローカル環境とデプロイ先のEC2共に、インターネットから接続可能な環境に構築されているものとします。
事前準備
ミドルウェア
npm
- Next.jsアプリケーションを作成するため、npmコマンドとnpxコマンドを使用します
- インストールされていない場合は、適宜以下のページより環境に応じたnpmをご準備してください nodejs.org
- 今回は以下のnpmバージョンを利用
ローカルMac端末
% npm --version 8.3.0
デプロイ先EC2インスタンス
$ npm --version 6.14.16
pm2
- デプロイ先のNext.jsアプリケーションの起動に使用します。
- 今回は以下のpm2バージョンを利用
デプロイ先EC2インスタンス
$ pm2 --version … [PM2] PM2 Successfully daemonized 5.2.0
リポジトリ
ソースリポジトリはGitHubのリポジトリとします
- アカウントをお持ちでない場合は、適宜準備してください github.com
GitHubリポジトリの認証方法はSSHとします
- 設定されてない場合は、適宜設定してください docs.github.com
ローカル環境へNext.jsアプリケーションを作成
npxコマンドでNext.jsアプリケーションを作成
アプリケーションを作成したい任意のディレクトリで以下コマンドを実行します
% npx create-next-app@latest … Ok to proceed? (y). → y をEnter … ✔ What is your project named? → 【アプリケーション名】Enter …
アプリケーション名:任意(今回はnext-cicdとしました)
完了すると、 next-cicd
の名前のディレクトリが作成されます
npm build & start
作成されたディレクトリへ移動し、ビルドします
その後、ローカル環境で起動させます
% cd next-cicd/ % npm run build % npm run start
起動したアプリケーションへアクセス
任意のブラウザより
http://localhost:3000
へアクセスします
上記のページが表示されれば成功です
これでローカル環境へアプリケーションを作成できました🎉
アプリケーションを停止
起動確認は完了したので、ローカル環境のアプリケーションは停止させておきます
Ctrl+c
Git 作業
GitHubにリポジトリを作成
GitHubアカウントへログインし、リポジトリを作成します
右上ペイン +
-> New repository
クリック
Repository name :任意(今回は next-cicd
としました)
Private
選択
Create repository クリック
ローカル環境のアプリケーションをGitHubリポジトリへ push
npxコマンドでNode.jsアプリケーションを作成すると初回のgit commitまで実行されている状態です
% git log commit b423d743bf148697a260db67fa7a93406de40de3 (HEAD -> main) Author: Ryota Orito <…@…> Date: Fri Jan 14 22:44:28 2022 +0900 Initial commit from Create Next App
よって、git remote add コマンドから順に実行します
% git remote add origin git@github.com:【GitHubユーザー名】/【Repository name】.git % git branch -M main % git push -u origin main Enter passphrase for key '/Users/user/.ssh/git': → GitHubのSSHキーパスワードを入力
【GitHubユーザー名】
【Repository name】
は適宜変更してください
EC2 アタッチ用ロール 作成
各ポリシー 概要
AmazonSSMManagedInstanceCore
CodeDeployエージェントインストール用ポリシー
デプロイ処理はEC2へインストールされたCodeDeployエージェントを通して実行されます。
当手順ではEC2へCodeDeployエージェントをインストールするために、AWS Systems ManagerからCodeDeployエージェントをインストールしています。
このインストール処理に必要なポリシーがAmazonSSMManagedInstanceCoreです。
※この方法はAWS公式ドキュメントでお勧めの方法ですが、AWS CLI でS3バケットから CodeDeploy エージェントをインストールすることもできます。 docs.aws.amazon.comUsing AWS Systems Manager is the recommended method for installing and updating the CodeDeploy agent. You can also install the CodeDeploy agent from an Amazon S3 bucket.
AmazonEC2RoleforAWSCodeDeploy
CodeDeployがEC2へデプロイするためのポリシー
ロール 作成
IAM > ロール > ロールを作成
信頼されたエンティティタイプ:AWSのサービス
ユースケース:EC2
次へ
AmazonSSMManagedInstanceCore チェック
AmazonEC2RoleforAWSCodeDeploy チェック
次へ
ロール名:任意(今回はAmazonSSMManagedInstanceCoreAndAmazonEC2RoleforAWSCodeDeployRoleとしました) ロールを作成
EC2へアタッチ
デプロイしたいインスタンスへロールをアタッチ
EC2 > インスタンス > インスタンス選択 > アクション > セキュリティ > IAMロールを変更
作成したロールを選択
保存
CodeDeploy用ロール 作成
CodeDeploy自体のロールを作成
IAM > ロール > ロールを作成
信頼されたエンティティタイプ:AWSのサービス
ユースケース:他のサービスのユースケース > CodeDeploy
次へ
AWSCodeDeployRole 選択
次へ
ロール名:任意(今回はAWSCodeDeployRoleとしました)
ロールを作成
CodeDeploy 作成
アプリケーション 作成
CodeDeploy > アプリケーション > アプリケーションの作成
アプリケーション名:任意(今回はnext-cicdとしました)
コンピューティングプラットフォーム:EC2/オンプレミス
アプリケーションの作成
デプロイグループ 作成
アプリケーション選択 > デプロイグループ > デプロイグループの作成
デプロイグループ名の入力:任意(今回はnext-cicd-deploy-groupとしました)
サービスロール:作成したCodeDeploy用ロールのArnを選択
デプロイタイプ:インプレース
環境設定:Amazon EC2 インスタンス チェック
キー/値:デプロイしたいEC2のタグを入力
Load balancer:チェックを外す
デプロイグループの作成
CodeDeploy エージェント インストール 確認
AWS Systems Manager を使用したエージェント設定によってEC2へCodeDeployエージェントがインストールされていることを確認
AWS Systems Manager > ステートマネージャー > 関連付けの名前:CodeDeployDG-【CodeDeployデプロイグループ名】 ステータス:成功 確認
ちなみに関連 IDを確認すると、、 スケジュール式が rate(14 days) となっており、14日間隔で自動的にCodeDeployエージェントが更新される設定となっています。
EC2インスタンス
$ systemctl status codedeploy-agent status ● codedeploy-agent.service - AWS CodeDeploy Host Agent Loaded: loaded (/usr/lib/systemd/system/codedeploy-agent.service; enabled; vendor preset: disabled) Active: active (running) since 木 2022-04-07 16:49:08 UTC; 4min 39s ago Process: 12990 ExecStart=/bin/bash -a -c [ -f /etc/profile ] && source /etc/profile; /opt/codedeploy-agent/bin/codedeploy-agent start (code=exited, status=0/SUCCESS) Main PID: 13000 (ruby) CGroup: /system.slice/codedeploy-agent.service ├─13000 codedeploy-agent: master 13000 └─13004 codedeploy-agent: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller of master 13000 4月 07 16:49:08 ip-10-0-0-5.ap-northeast-1.compute.internal systemd[1]: Starting AWS CodeDeploy Host Agent... 4月 07 16:49:08 ip-10-0-0-5.ap-northeast-1.compute.internal systemd[1]: Started AWS CodeDeploy Host Agent. Unit status.service could not be found.
CodePipeline 作成
CodePipeline > パイプラインの作成
パイプライン名:任意(今回はnext-cicdとしました)
サービスロール:新しいサービスロール
ロール名:新しいサービスロールを選択すると、自動で入力されます
次に
ソースプロバイダ:GitHub(バージョン2)
GitHub に接続する
接続名:任意(今回はnext-cicdとしてますが、他にCodeDeployなどで連携したいリポジトリが存在する場合は、より汎用的な名称が良いです。)
GitHub に接続する
GitHub認証画面で認証情報を入力し、Sign in
2段階認証設定している場合は、適宜認証完了させます。
GitHub アプリ:選択項目のアプリケーションを選択
接続
AWS Connector for GitHub 設定
GitHubの設定で、AWSからリポジトリへのアクセス権限を設定します。
右上アイコンペイン > Settings > Applications > AWS Connector for GitHub Configure
Only select repositories
Select repositories:リポジトリを選択
Save
CodePipelineの設定画面へ戻ります。
リポジトリ名:AWS Connector for GitHub で追加したリポジトリを選択
ブランチ名:main
出力アーティファクト形式:完全クローン
次に
ビルドステージを追加する
プロバイダーを構築する:AWS CodeBuild リージョン:アジア・パシフィック(東京) プロジェクト名:プロジェクトを作成する
プロジェクト名:任意(今回はnext-cicdとしました)
環境イメージ:マネージド型イメージ
オペレーティングシステム:Amazon Linux 2
ランタイム:Standard
イメージ:aws/codebuild/amazonlinux2-x86_64-standard:3.0
イメージのバージョン:このランライムバージョンには常に最新のイメージを使用してください
環境タイプ:Linux
サービスロール:新しいサービスロール
ロール名:自動入力
Buildspec:buildspec ファイルを使用する
CodePipeline に進む
CodeBuild で next-cicd が正常に作成されました。 を確認
次に
デプロイステージを追加する
デプロイプロバイダー:AWS CodeDeploy
リージョン:アジアパシフィック(東京)
アプリケーション名:CodeDeployアプリケーションを選択(今回はnext-cicd)
デプロイグループ:CodeDeployデプロイグループを選択(今回はnext-cicd-deploy-group)
次に
設定内容を確認し、パイプラインを作成する
Build が失敗していることを確認
CodePipelineは一通り設定できましたが、まだ完全ではないので追加で設定していきます。
デプロイ先インスタンスにデプロイ先ディレクトリ 作成
$ mkdir 【デプロイ先ファイルパス】
今回は/home/orito/next-cicd/としました。
もしデプロイ先で既にアプリケーションを手動で作成していた場合は、デプロイ先のソースコードを削除しておきましょう。
CodeBuild サービスロールへ接続使用権限 付与
Gitクローン:ソースコードをビルド環境に直接ダウンロードできます。 Gitクローンモードでは、動作するGitリポジトリとしてソースコードを操作できます。このモードを使用するには、接続を使用するためのCodeBuild環境権限を付与する必要があります。
パイプラインのSource Arn確認
ConnectionArn を控えておきます。
ビルドプロジェクトサービスロール 遷移
ビルドプロジェクト > ビルドの詳細 > サービスロール
アクセス許可を追加
ポリシーをアタッチ
ポリシー 作成
ポリシーの作成
JSON タブ
以下を入力
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "codestar-connections:UseConnection", "Resource": "【控えておいたConnectionArn】" } ] }
次のステップ:タグ
次のステップ:確認
名前:任意(今回はcodebuild-next-cicd-service-role-codestar-policyとしました)
ポリシーの作成
作成したポリシーをアタッチ
作成したポリシーを検索し、チェック
ポリシーをアタッチ
リポジトリへ設定ファイルなどをPush
buildspec.yml 作成
リポジトリへbuildspec.ymlを作成します。
- buildspec.yml
- source: / version: 0.2 env: variables: NODE_ENV: "production" phases: install: commands: - echo Installing dependency... - npm install build: commands: - echo Build started on `date` - echo Compiling the Next.js code - npm run build artifacts: files: - .next/**/* - next.config.js - node_modules/**/* - package.json - appspec.yml - restart.sh enable-symlinks: yes
appspec.yml 作成
リポジトリへappspec.ymlを作成します。
- appspec.yml
version: 0.0 os: linux files: - source: / destination: 【デプロイ先ファイルパス】 hooks: ApplicationStart: - location: restart.sh timeout: 180
デプロイ先:デプロイしたいファイルパスを指定(今回は/home/orito/next-cicd/としました)
再起動用スクリプト 作成
リポジトリへrestart.shを作成します。 - restart.sh
#!/bin/bash cd /home/orito/next-cicd/ pm2 list pm2 stop next-cicd pm2 start npm --name next-cicd -- start
作成したファイルをGit push
$ git add appspec.yml buildspec.yml restart.sh $ git commit -m "Add Setting files" $ git push origin main
CI/CD確認
index.js を編集
変更されたことを確認するために、トップページの表示文言を変更します
$ vim pages/index.js
本稿では以下の Welcome to
の部分を Hello
へ変更しました
% git diff pages/index.js <main className={styles.main}> <h1 className={styles.title}> - Welcome to <a href="https://nextjs.org">Next.js!</a> + Hello <a href="https://nextjs.org">Next.js!</a> </h1>
Git push
$ git add pages/index.js $ git commit -m "Edit text" $ git push origin main
CodePipeline 確認
コミットメッセージが反映され、 Source->Build->Deployと、 順次進行されていく様子が確認できます。
Deploy が成功となったら、
EC2のアプリケーションURLへアクセスします
Welcome to
の部分が Hello
に変わっていることが確認できれば、成功です🎉🎉
【参考】デプロイ時のログ
デプロイ処理がうまく設定できない場合等に確認するログです。
$ tail -f /opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log
【参考】CodeBuild アーティファクト確認
buildspec.yml の artifacts のファイルがS3のcodepipeline-ap-northeast-1-********** バケット内の BuildArtif 配下へzip化されて保存されていることが確認できます。 このビルドファイルを元にCodeDeployの処理が進行します。
- ダウンロード 確認
【参考】ハマリポイント
enable-symlink: yes がないと、npm run start コケる
- エラー
Error: Cannot find module '../build/output/log' Require stack: - /home/orito/next-cicd/node_modules/.bin/next
node_modules内でシンボリックリンクが定義されているようで、ビルドソースがS3バケットへ保存されるときに内部シンボリックリンクを保持するように設定しておく必要がありました。
restart.sh で アプリケーションディレクトリへ cd しないと、npm run start コケる
pm2 で起動するためにはアプリケーションのルートディレクトリへ移動させる必要がありました。
最後に
開発サイクルの早いアプリケーション開発にとって、CI/CD環境はかかせません。
かなり手順は多いですが、一度設定してしまえば運用コストが削減できるので、どなたかのお役に立てれば幸いです。
では。