GitHub で管理している Serverless Framework プロジェクトのリポジトリに Pull Request がマージされたら CodePipeline を動かして自動デプロイする方法
いわゆる 継続的デプロイ(Continuous deployment)を実現します。
デプロイだから CodeDeploy を使うんだろ? なんて思ってしまいがちですが、CodeBuild を用いたデプロイとなります。
確かこの辺りは AWS 認定デベロッパーアソシエイト試験範囲で、「S3 へのデプロイは何使う?」みたいなやつが模擬問題だったか何かで見た気がします(うろ覚え感)。Serverless Framework も同じ理屈で CodeBuild です。
Serverless Framework プロジェクトのリポジトリを GitHub に用意する
今回も Serverless Framework + TypeScript で行います。ただしコードの変更は今回はありませんので aws-nodejs-typescript 以外のテンプレートでも応用が利くでしょう。
先に GitHub 上でリポジトリを作ってから git clone してそのディレクトリ内で、serverless create が手っ取り早いと思います。
そんなわけでリポジトリを作りました
直接的な影響はありませんが serverless.yml を以下のように変更しています。東京リージョンにデプロイ予定です。バケット名も固定してしまっていますので、下記を流用する際は適宜変更してください。バケットも先に作っておいてください。
buildspec ファイルを用意する
Serverless Framework は dev と prod のステージを持っているのでそれぞれにデプロイするには buildspec もそれぞれに用意してあげます。今回は prod のみのデプロイを行いますので dev の方は不要ですが一応用意しておきます。これをリポジトリ直下に置いておきます。
buildspec-dev.yml
version: 0.2
phases:
install:
runtime-versions:
nodejs: latest
commands:
- npm install -g serverless
pre_build:
commands:
- npm install
post_build:
commands:
- serverless deploy
buildspec-prod.yml
version: 0.2
phases:
install:
runtime-versions:
nodejs: latest
commands:
- npm install -g serverless
pre_build:
commands:
- npm install
post_build:
commands:
- serverless deploy --stage prod
CodePipelineを作成する
AWS コンソールにログインして、CodePipeline の画面を開きます。そしてオレンジ色の「パイプラインを作成する」ボタンを押します。
パイプライン名にこのプロジェクトのパイプラインと分かるような名前を入力し、それ以外はデフォルトのまま「次に」ボタンを押します。
ソースステージの追加で、ソースプロバイダーに GitHub を選択します。
「GitHub に接続する」ボタンが表示されますので、それをクリックしGitHubと連携させます。下記の文言が出れば正常に連携できています。
✔ プロバイダに正常にアクションを設定しました。
※ GitHub Organization のリポジトリを使用する場合は、GitHub の Organization settings の Third-party access で 「Grand access」ボタンを押して許可する必要があります。
そして対象のリポジトリとブランチを選択し、「次に」ボタンを押します。ブランチ名はテキスト入力可能ですので現時点で存在しないものも設定可能です。
ビルドステージの追加にてAWS CodeBuild を選択します。そして中段の「プロジェクトを作成する」ボタンを押します。
CodeBuild プロジェクトを作成する
プロジェクト設定
プロジェクト名に分かりやすい名前を入力します。この名前は後から変更できません。説明やタグも必要に応じて入れましょう。
環境
それっぽく Amazon Linux 2 で Standard で最新イメージを使います。
Buildspec
Serverless Framework に則って CodePipeline 側のステージを dev と prod に分けようと思っていたのですが面倒になったので、master マージで prod にデプロイしようと思います。なので buildspec-prod.yml を設定します。
ログはお好みで。一通り CodeBuild の設定が完了しましたら「CodePipeline に進む」ボタンを押して戻ります。
CodePipeline で残りの設定を行う
成功メッセージが表示されていることを確認し、「次に」ボタンを押します。
✔ CodeBuild で sample-serverless-codepipeline が正常に作成されました。
デプロイステージはスキップします。
最後にレビュー画面が出てきますので「パイプラインを作成する」ボタンを押し、作成を完了させます。
作成完了させるとパイプラインが動き出します。そして失敗します。😇
IAMロールを変更する
なぜ失敗したかって? IAM 権限です。
Serverless Error ---------------------------------------
Could not locate deployment bucket. Error: Access Denied
Get Support --------------------------------------------
Docs: docs.serverless.com
Bugs: github.com/serverless/serverless/issues
Issues: forum.serverless.com
Your Environment Information ---------------------------
Operating System: linux
Node Version: 12.16.1
Framework Version: 1.69.0
Plugin Version: 3.6.9
SDK Version: 2.3.0
Components Version: 2.30.6
[Container] 2020/05/05 12:46:11 Command did not exit successfully serverless deploy --stage prod exit status 1
[Container] 2020/05/05 12:46:11 Phase complete: POST_BUILD State: FAILED
[Container] 2020/05/05 12:46:11 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: serverless deploy --stage prod. Reason: exit status 1
Serverless Framework は AdministratorAccess が必要とドキュメントに書かれていますからね。
必要なものだけ設定してやる方法も上記に書かれていますが、今回はAdministratorAccess を用意してやります。
コンソールで IAM を開き、ロールから CodeBuild プロジェクト作成時に自動生成されたIAM ロールを開き、「ポリシーをアタッチします」ボタンを押します。
そして AdministratorAccess を選択し「ポリシーのアタッチ」を行います。
アタッチが成功したら下記メッセージが表示されます。
codebuild-sample-serverless-codepipeline-service-role にポリシー AdministratorAccess がアタッチされました。
試しに CodePipeline を手動実行してみましょう。CodePipeline の画面から「変更をリリースする」ボタンを押すことで手動実行ができます。
IAM ポリシーをアタッチしたらデプロイも成功しました。
Build の詳細からログを追っていけば prod/hello の URL があると思いますのでアクセスするとレスポンスが返ってくるのが確認できます。
GitHub 上で Pull Request をマージしてみる
ローカルで適当にブランチを作り、適当にコードを編集し、適当にコミットしプッシュをします。そして適当に Pull Request を作成します。
作成したらマージします。
Webhook での連携なのですぐに CodePipeline が動き始めます。最新の master を取得できていることが確認できますね。
少し待てば Build も成功しました。
同じく /prod/hello にアクセスしてみると変更されていることが確認できました。
おまけ:GitHub で master への直 push を禁止する
master への直 push を禁止し、変更は全部 Pull Request 経由にすることで、コードレビューされていない変更のデプロイを防ぐことができます。
GitHub 側で以下のように設定が可能です。マージで他者のレビューを必須にする場合は1個目のチェックを付けましょう。
まとめ
CodePipeline と CodeBuild を構築し GitHub を設定することで、Pull Request を受け入れたら即座に変更を反映させることができました。
これはデプロイまでを自動化しているので継続的デプロイと呼びます。
実際の現場では develop ブランチへのPull Request マージ時には検証環境に継続的デプロイ、master ブランチへの Pull Request マージ時には上長の承認後に本番環境に継続的デリバリーを行いたいかと思います。試していませんがその辺りも CodePipeline 上で実現できると思います。
ローカル環境で serverless deploy --stage prod されたら本番環境にデプロイできてしまいますが、この辺りを防ぐ手立てが私も知りたいです🤔
😉