節約のために CodePipeline をやめて CodeBuild に全部任せてみた
2019-08-02CodePipeline を使うとビルド、デプロイ、結果の通知までを簡単に構築できますが、作成後 30 日以降は料金が発生してしまいます。なので、節約のために CodeBuild で全部やってしまおうという話です。
目次
前提
- Vue.js で書かれた静的 Web サイトの CI/CD を CodePipeline を使って実現している
- ソースの変更は頻繁には行われないが、最低でも月に 1 回はある
- GitHub への Push をトリガーにビルド・デプロイ、 Slack への通知ができれば OK
あくまでも個人で運用している AWS アカウントの料金節約を目的としています。また、今回やってみる内容では、 CodePipeline で実現できていることを全て再現することはできません。諦めなければいけない挙動もあるので、その点はご理解ください。
CodePipeline と CodeBuild の料金
タイトルで 節約のために と書いている通り、今回の内容で毎月の料金を節約することができるので、 CodePipeline と CodeBuild についてあらためて確認してみます。
CodePipeline
CodePipeline は、利用するパイプラインの数に対して料金が発生します。
- アクティブなパイプライン 1 つにつき、 1 USD (アクティブとは、30 日以上存在している 且つ その月に少なくとも 1 つのコード変更が発生)
- 作成後 30 日間は無料
- 無料利用枠として、アクティブなパイプラインを 1 つ利用可能
CodeBuild
CodeBuild は、ビルドにかかった時間 (分) に対して料金が発生します。(1 分未満は切り上げ)
またその単価は、利用するコンピューティングタイプによって変わります。
タイプ | メモリ (GB) | vCPU | Linux (USD/分) | Windows (USD/分) |
---|---|---|---|---|
build.general1.small | 3 | 2 | 0.005 | 該当なし |
build.general1.medium | 7 | 4 | 0.010 | 0.018 |
build.general1.large | 15 | 8 | 0.020 | 0.036 |
無料利用枠として、 1 ヶ月あたりビルドを 100 分使用できます。
CodeBuild を使って該当の Vue.js アプリケーションのビルド・デプロイするのにかかる時間は 1 - 2 分程度なので、 build.general1.small
を使用する場合は 1 回につき 0.02 USD 程度ということになります。
CodePipeline を使っている場合だと、プラス 1 USD (1 回きりですが) が発生します。
やっていたこと/やること
まずは CodePipeline を使っていたときの構成についてです。
イメージとしてはこんな感じです。
- GitHub の master ブランチへの Push をトリガーにパイプラインが開始
- CodeBuild でビルド、生成されたソースを S3 へ配置
- パイプラインの実行結果を Slack へ通知するための Lambda を実行
これを、次のような構成にします。
シンプルになりました。
構成はこれでいいとして、 CodeBuild の設定、 buildspec.yml
も変更する必要があります。具体的には下記のポイントです。
- 送信元を GitHub に変更
- プライマリソースのウェブフックイベントを設定
master ブランチへの Push でビルドが開始されるようにします buildspec.yml
内で Slack への通知を追加
では、設定の変更方法についてみていきます。
CodeBuild の設定変更
送信元を GitHub に変更
まずは送信元を GitHub に変更します。が、既に CodePipeline に紐づいているビルドプロジェクトを変更する場合、送信元はマネジメントコンソールで変更することができません。なので CLI で変更します。
一旦、既存の設定を JSON 形式で取得します。
$ aws codebuild batch-get-projects --names "BuildProjectName" > ./current.json
{
"projects": [
{
"name": "BuildProjectName",
"arn": "arn:aws:codebuild:ap-northeast-1:123456789012:project/BuildProjectName",
"source": {
"type": "CODEPIPELINE",
},
"artifacts": {
"type": "CODEPIPELINE",
"name": "BuildProjectName",
"packaging": "NONE"
},
"cache": {
"type": "NO_CACHE"
},
"environment": {
"type": "LINUX_CONTAINER",
"image": "aws/codebuild/nodejs:10.14.1",
"computeType": "BUILD_GENERAL1_SMALL",
"environmentVariables": [],
"privilegedMode": false
},
"serviceRole": "arn:aws:iam::123456789012:role/service-role/codebuild-BuildProjectName-service-role",
"timeoutInMinutes": 60,
"encryptionKey": "arn:aws:kms:ap-northeast-1:123456789012:alias/aws/s3",
"tags": [],
"created": 1557990804.228,
"lastModified": 1562114621.841,
"badge": {
"badgeEnabled": false
}
}
],
"projectsNotFound": []
}
こんな感じの JSON が取得できるので、これを元にして次のような JSON ファイルを新たに作成します。(仮に update.json
とします)
変更点としては、 source
と artifacts
です。
environment.environmentVariables
については、後の Slack 通知で使用する環境変数になります。多分 Slack の Webhook URL は Systems Manager のパラメータストアから、 KMS で暗号化した上で取得したほうがよさそうです。このへんはまだちょっとわかってないので、一旦プレーンテキストで入れてます。
{
"name": "BuildProjectName",
"source": {
"type": "GITHUB",
"location": "https://github.com/michimani/repo.git"
},
"artifacts": {
"type": "NO_ARTIFACTS"
},
"environment": {
"type": "LINUX_CONTAINER",
"image": "aws/codebuild/standard:2.0",
"computeType": "BUILD_GENERAL1_SMALL",
"environmentVariables": [
{
"name": "notifyTitle",
"value": "BuildProjectName build",
"type": "PLAINTEXT"
},
{
"name": "slackHookUrl",
"value": "https://hooks.slack.com/services/123456789/ABCDEFGHI/abcdefghij1234567890abcd",
"type": "PLAINTEXT"
}
],
"privilegedMode": false
}
}
この JSON ファイルを使って CodeBuild の設定を変更します。
$ aws codebuild update-project --cli-input-json file://update.json
正しく変更できれば、変更後の設定が出力されます。
プライマリソースのウェブフックイベントを設定
続いてはビルド開始の設定です。これについてはマネジメントコンソールで操作しました。
CodeBuild のビルドプロジェクトから対象のプロジェクトを選択して、送信元の編集画面を開きます。
ちなみに、この時点でソースプロバイダが GitHub になっていることを確認できます。
画面の下の方にある プライマリソースのウェブフックイベント で、ビルド開始条件を設定します。
イベントタイプ で プッシュ を選択し、 これらの条件でビルドを開始する の HEAD_REF に ^refs/heads/master$
と入力して更新します。
この master
部分を変更することで、特定のブランチへのイベントを検知することができます。
buildspec.yml 内で Slack への通知を追加
最後に、 Slack への通知処理を buildspec.yml
内に追加します。処理といっても、下記の curl コマンドを post_build
フェーズの commands
に追加するだけです。
curl -H 'Content-Type:application/json' -d "{'channel':'dev','icon_emoji':':codebuild:','attachments':[{'author_name':'CodeBuild','title':'$notifyTitle','color':'#00FF00','fields':[{'value':'Build and deploy were successed.'}]}]}" $slackHookUrl
POST している JSON は次のような構造になっています。
{
"channel": "dev",
"icon_emoji": ":codebuild:",
"attachments": [
{
"author_name": "CodeBuild",
"title": "$notifyTitle",
"color": "#00FF00",
"fields": [
{
"value": "Build and deploy were successed."
}
]
}
]
}
実際に通知されるとこんな感じになります。
以上で、 CodeBuild のみでビルド・デプロイ・通知までできるようになりました。
失ったもの ※追記あり (2019/11/12)
CodePipeline を使用しなくなったことで料金の節約には成功しましたが、 CI/CD のクオリティとしては下がっています。
特に問題なのが、 ビルドに失敗したことがわからない という点です。
CodePipeline を使っていた時は、仮に CodeBuild の処理中にエラーが発生した場合はあパイプラインの失敗となります。失敗したというステータスは Slack 通知用の Lambda 内で取得できるので、成功しても失敗しても、どちらの場合も通知で確認することができます。
一方、今回のように CodeBuild だけでやろうとすると、 CodeBuild 内でのエラー・失敗をキャッチして通知する術がありません。
本当に無理やりやろうとするなら、 buildspec.yml
内の各フェーズの最初に通知コマンドを実行して、最後のフェーズの通知が来なかったらその前段階で失敗したということはわかるかもしれません。
※追記 2019/11/12
AWS の Code シリーズ向けに新たな通知サービスがリリースされ、各 Code シリーズから個別に SNS および AWS Chatbot (beta) にイベント通知を送信できるようになりました。
その結果、失ったと思われたものはクオリティが上がって戻ってきました!詳細は下記のブログで書いてます。
まとめ
節約のために CodePipeline をやめて CodeBuild に全部任せてみたという内容でした。
失ったもの で書いたように、 CI/CD のクオリティとしてはだいぶ低くなります。GitHub への Push でビルド・デプロイしたい!通知はとりあえず何かくれば OK! くらいのゆるーい感じであれば、 CodeBuild だけでもなんとかなりそうです。
そもそも他の CI/CD サービス使えばいいのかもしれませんが…。
comments powered by Disqus