こんにちは~ 浮田です。
■ TL;DR
- CodeCommit に push するだけで「テスト → 承認 → cdk deploy」が走るパイプラインを、コンソールだけで作りました
- 構成は CodePipeline(V2)+ CodeBuild 2 つ(CI 用 / デプロイ用)+ 手動承認。CI は約 4 分、デプロイは約 8 分半でした
- 一番の罠は「ステージを後から足しても、パイプラインのロールの権限は増えない」こと。codebuild:StartBuild と iam:PassRole で、Deploy が起動から 1 秒で立て続けに落ちました
- ほかにも「buildspec の上書きで保存できない」「保存に失敗したのに CodeBuild プロジェクトだけ作られている」など、コンソールならではの罠がありました
- 結論: CI/CD は「デプロイのボタンを押す人」を、仕組みと承認に置き換えることだと腑に落ちました
■ 目次
- はじめに
- そもそも CI/CD とは
- 今回作るもの
- 構築手順(コンソール)
- 動作確認
- 詰まったところ(ここが本番)
- 感想・次にやりたいこと
■ はじめに
自分で作っている AWS アプリ、デプロイはずっと手元のターミナルから npx cdk deploy を叩いていました。
動くには動くんです。ただ、MFA のセッションが切れてやり直したり、フォーマットをかけ忘れてやり直したり、「あれ、これ最新のコードでデプロイしたっけ?」と不安になったり……地味にストレスが溜まっていました。
「これ、push したら勝手にテストしてデプロイしてくれないかな~」 そう思って調べ始めたのが CI/CD です。……と言いつつ、正直なところ CI/CD が何の略かも説明できないくらいの状態からのスタートでした。
AWS CDK(Cloud Development Kit。AWS の構成を TypeScript などのコードで書けるツール。以下、CDK)で一気に書いてしまう手もあったのですが、まずは仕組みを目で見て理解したかったので、今回は あえてコンソールでポチポチ作ってみることにしました。
対象読者は「CI/CD ってよく聞くけど、自分で作ったことはない」くらいの人です。これから同じことをやる人(=1 週間前の自分)の助けになれば。
■ そもそも CI/CD とは
CI/CD は 2 つの言葉の組み合わせです。
- CI = Continuous Integration(継続的インテグレーション): push するたびに、ビルドとテストを自動で回すこと
- CD = Continuous Delivery / Continuous Deployment: テストに通ったものを、本番に出せる状態まで(あるいは本番まで)自動で運ぶこと
CD には 2 種類あって、違いは「最後に人が OK を出すかどうか」です。
|
用語 |
意味 |
今回のどこ? |
|
CI |
push ごとにビルド・テストを自動実行 |
CodeBuild(CI 用) |
|
Continuous Delivery |
いつでも出せる状態まで自動。本番投入は人が承認 |
手動承認ステージ |
|
Continuous Deployment |
テストが通れば本番まで全自動 |
(今回は採用しない) |
ここを工場の検品ラインでたとえると分かりやすいです。 部品(コード)が届くたびに自動で検品(テスト)して、合格品だけを出荷場に並べるのが Delivery。出荷トラックに積むところまで自動でやるのが Deployment です。
AWS のサービスに当てはめると、こんな役割分担になります。
|
AWS サービス |
役割 |
たとえ |
|
CodeCommit |
ソースコードの置き場所 |
部品倉庫 |
|
CodePipeline |
各工程を順番につなぐ指揮役 |
ベルトコンベア |
|
CodeBuild |
実際にコマンドを実行する作業場 |
検品・組み立て担当 |
|
CloudFormation(CDK) |
AWS にリソースを作る |
出荷先 |
■ 今回作るもの
題材は、社内の技術コミュニティ”GAWS”のテックブログのレビューアプリです。 backend・frontend・cdk の 3 パッケージ構成で、Lambda の一部は Docker イメージで arm64(Graviton) で動いています。

|
ステージ |
中身 |
使うもの |
|
Source |
main ブランチへの push を検知 |
CodeCommit + EventBridge |
|
Build(CI) |
format チェック / build / test / cdk synth |
CodeBuild(buildspec/ci.yml) |
|
Approval |
本番に出してよいか人が確認 |
手動承認 |
|
Deploy |
cdk deploy --all |
CodeBuild(buildspec/deploy.yml) |
環境はこちらです。
- リージョン: 東京(ap-northeast-1)
- ソース: CodeCommit(main ブランチ)
- CDK ブートストラップ: 東京で実施済み
- Node.js 22 / CodeBuild のイメージは arm64
■ 構築手順(コンソール)
❶ buildspec をリポジトリに置く
buildspec は、ひとことで言うと CodeBuild への作業指示書 です。 「どのランタイムを使って、どのコマンドをどの順に叩くか」を YAML で書きます。
リポジトリのルートに buildspec/ フォルダを作って、2 つ置きました。

▲ CI 用。backend → frontend → cdk の順にチェックして、最後に cdk synth まで通るかを見ます

▲ デプロイ用。やっていることは、手元で叩いていた cdk deploy そのものです
❷ パイプラインを作る(ウィザード)
CodePipeline のコンソールから「パイプラインを作成する」→「カスタムパイプラインを構築する」で進めます。
|
項目 |
値 |
|
パイプライン名 |
gaws-blogreview-cicd-pipeline |
|
実行モード |
キュー(デプロイの途中で次の実行が割り込まないように) |
|
ソース |
CodeCommit / main / Amazon EventBridge で変更を検知 |
.png?width=1024&height=482&name=%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%92%E4%BD%9C%E3%82%8B(%E3%82%A6%E3%82%A3%E3%82%B6%E3%83%BC%E3%83%89).png)
2.png?width=1024&height=803&name=%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%92%E4%BD%9C%E3%82%8B(%E3%82%A6%E3%82%A3%E3%82%B6%E3%83%BC%E3%83%89)2.png)
|
項目 |
値 |
理由 |
|
イメージ |
aws/codebuild/amazonlinux-aarch64-standard:3.0 |
Lambda が arm64 なので揃える |
|
特権付与 |
ON |
Docker イメージをビルドするのに必須 |
|
タイムアウト |
60 分(デプロイ用は 120 分) |
余裕を持たせた(実測は CI 約 4 分、デプロイ約 8 分半) |
|
Buildspec |
buildspec/ci.yml |
①で置いたファイル |
なお、特権付与はビルド用のコンテナの中で Docker を動かすための設定で、コンテナに強い権限を渡します。自分のリポジトリのコードだけをビルドするなら問題ありませんが、外部からの持ち込みコード(フォークからのプルリクエストなど)をビルドする用途では使わないようにしましょう。
ここで一度手が止まりました。 「イメージ」の欄、初期値は amazonlinux-x86_64-standard:6.0 です。 そもそも「イメージって何?」というところから確認したのですが、これは CodeBuild がビルドのたびに立ち上げる使い捨てコンテナのテンプレート です。
OS と Node.js や Docker などのツールが入っていて、x86 版と arm64 版で違うのは基本的に CPU の種類だけでした(6.0 と 3.0 は CPU ごとの別の番号で、新旧の差ではありません)。
このアプリは Lambda の Docker イメージを arm64 でビルドしています。x86 のビルド環境だとエミュレーションが必要になって、遅いうえに失敗しやすくなります。 「本番の Lambda と CPU を揃える」 のがポイントでした。デフォルトのまま進めていたら、たぶんここで 1 つ罠を踏んでいたと思います。
デプロイステージは、ウィザードでは「スキップ」して後から足します(これが後で効いてきます……)。

作成すると、すぐに 1 回目の実行が始まりました。push した buildspec を取り込んで、CI が約 4 分で緑になりました。

❸ 承認ステージとデプロイステージを足す
パイプラインの「編集」から、Build の下の「+ ステージを追加する」で 2 つ足します。

|
ステージ |
アクション |
設定 |
|
Approval |
ManualApproval(手動承認) |
コメント: 本番へデプロイしてよいか確認してください(任意) |
|
Deploy |
CdkDeploy(AWS CodeBuild) |
入力アーティファクト: SourceArtifact / プロジェクト: gaws-blogreview-cicd-deploy |
Deploy の入力は、ビルドの出力ではなくソースにしています。デプロイ用の CodeBuild の中で npm ci からやり直すので、CI の成果物は使いません。

❹ デプロイ用ロールに権限を足す
最後に、デプロイ用 CodeBuild のサービスロールにインラインポリシーを 1 つ足します。
ここが個人的に一番「へぇ~」と思ったところです。 CDK v2 の cdk deploy は、実行している人(今回は CodeBuild)の権限で直接リソースを作るわけではありません。ブートストラップのときに作られたロールを引き受けて作業します。
|
ブートストラップのロール |
使いどころ |
|
cdk-hnb659fds-deploy-role-… |
CloudFormation の操作 |
|
cdk-hnb659fds-file-publishing-role-… |
S3 へのアセットのアップロード |
|
cdk-hnb659fds-image-publishing-role-… |
Amazon ECR(コンテナイメージの置き場所)への Docker イメージの push |
|
cdk-hnb659fds-lookup-role-… |
既存リソースの参照 |
なので CodeBuild に渡す権限は「このロールを借りに行っていい」の 1 つだけで済みます。AdministratorAccess のような強い権限は要りません。
合鍵を CodeBuild に直接渡すのではなく、「鍵を借りに行っていい」という許可証だけを渡すイメージです。
なお、CodeBuild が自動で作る CodeBuildBasePolicy-... に書き足すのではなく、別のインラインポリシーにしました。自動生成のポリシーは CodeBuild 側で作り直されることがあるのと、「標準の権限」と「CDK 用に足した権限」を分けておいたほうが、あとで見返したときに分かりやすいと思ったからです。
■ 動作確認
push すると、EventBridge 経由でパイプラインが自動で動き出します。 実行履歴を見ると、トリガーが CloudWatchEvent になっています(ちなみにコンソールの「変更をリリースする」ボタンで手動実行したときは StartPipelineExecution です)。CI が緑になったところで止まり、Approval で承認待ちになります。

「確認」→「承認」を押すと Deploy が動いて、CloudFormation のスタックが UPDATE_COMPLETE に。ログにもデプロイ先がちゃんと東京になっていることが出ていました。

▲ Deploy のログ抜粋。Docker イメージを ECR に push してから、スタックを更新しています
実測はこんな感じです。
|
ステージ |
所要時間 |
内訳 |
|
Source |
数秒 |
|
|
Build(CI) |
約 4 分 |
ほぼ build フェーズ(210 秒)。ソースのダウンロードに 26 秒 |
|
Approval |
― |
人待ち |
|
Deploy |
約 8 分半 |
npm ci 66 秒 + cdk deploy 424 秒(うちスタック更新 278 秒) |
CI の 210 秒のログを追ってみると、約 7 割は npm ci でした(backend 約 1 分、frontend 約 1 分 20 秒)。テストそのものは backend・cdk 合わせて 30 秒もかかっていません。Deploy のほうは、Docker イメージ 3 つのビルドと ECR への push がスタック更新の前にかかっています。
手元から叩いていたときとやっていることは同じなので、時間が劇的に縮んだわけではありません。変わったのは、その間ターミナルを握っていなくていいことと、テストを通ったものしか承認に並ばないことです。
■ わざと失敗させてみる
成功するところだけ見ても、CI がちゃんと「止めてくれる」かは分かりません。そこで、backend のファイルのインデントをわざと 1 行だけ崩して push してみました。プログラムの動きは変わらず、Prettier のフォーマットチェックにだけ引っかかる崩し方です。


▲ 崩したファイルが名指しで出て、そこでビルドが止まります

backend の最初のチェックで落ちたので、その後ろの build・test や frontend・cdk のチェックは実行されません。もちろん Approval にも並ばないので、崩れたコードが承認者の目の前に来ることはありません。
1 つ意外だったのは、CodeBuild のビルド履歴が 2 件増えていたことです。ビルドは 1 回あたり約 1 分 15 秒で落ちたのですが、パイプラインの定義を見ると、ウィザードで作った Source と Build のステージには「失敗したら自動で 1 回再試行する」設定が入っていました。

▲ aws codepipeline get-pipeline で見た Build ステージの設定
ネットワークの一時的なエラーなら再試行で助かりますが、フォーマット違反は何回やっても落ちます。そのぶんビルド時間(=料金)も 2 回分かかるので、CI のように「落ちたら直すしかない」ステージでは外してもよさそうです。
ここで 1 つ注意点があります。パイプラインのトップ画面はステージごとに最後に動いた実行を表示するので、Build は赤なのに、Approval と Deploy には前回成功したときの緑が残って見えます。ステージごとの実行 ID を見るか、「実行履歴」から今回の実行を開いて確認するのが確実です。
■ 承認で却下してみる
崩したコミットを git revert で戻して push すると、CI は緑に戻って Approval で止まりました。今度はここで「却下」を選んでみます。

送信すると、画面の上に「アクション ManualApproval が却下されました」と出て、Approval は失敗扱いになりました。
Deploy はこの実行では動いていません。実行履歴には、却下した人(IAM ユーザー)と入れたコメント(「却下してみる」)が残ります。
なお、承認も却下もされないまま 7 日たつと、却下と同じく失敗扱いになります。

テストに通っていても、人が「まだ出さない」と決めれば本番には出ない。ここが Continuous Delivery と Continuous Deployment の違いそのものです。
|
試したこと |
結果 |
|
正常に push |
CI → 承認 → Deploy まで緑 |
|
フォーマットを崩して push |
Build で停止。Approval に並ばない |
|
承認で却下 |
Approval が失敗。Deploy は動かない |
■ 詰まったところ
すべてウィザードのあとに「編集」で足した Deploy ステージまわりでした。
❶ 親切心で埋めた「buildspec の上書き」で保存できない
InvalidActionDeclarationException
Action configuration for action 'CdkDeploy' contains unknown configuration 'BuildspecOverride'
CdkDeploy アクションの上書き欄に buildspec/deploy.yml を入れたら、保存で弾かれました。リファレンスでは正式な設定項目なので、なぜ弾かれたのかは分かりません(2026 年 10 月時点・東京)。ただ、プロジェクト側で同じ buildspec を指定済みで、そもそも上書きする意味がなかったので、欄を空にして回避しました。
❷ 保存は失敗したのに、CodeBuild プロジェクトだけできている
①を直して作り直そうとしたら Project already exists。「プロジェクトを作成する」は別ウィンドウで、パイプラインの保存とは関係なく先に作成が終わっていました。プルダウンから既存のプロジェクトを選べば OK です。
❸ 承認した 1 秒後に Deploy が落ちる(StartBuild)
Error calling startBuild: User: arn:aws:sts::<アカウントID>:assumed-role/AWSCodePipelineServiceRole-ap-northeast-1-gaws-blogreview-cicd-/...
is not authorized to perform: codebuild:StartBuild
on resource: arn:aws:codebuild:ap-northeast-1:<アカウントID>:project/gaws-blogreview-cicd-deploy
アプリの画面がいつも通り開けたので、最初はデプロイも成功したと思い込んでいました。前回手元からデプロイしたものが動いていただけです。「アプリが動いている」と「パイプラインでデプロイできた」は別物でした。
止められていたのは CodeBuild ではなくパイプラインのロールです(デプロイ用 CodeBuild のビルド履歴は 0 件)。ウィザードが作ったポリシーは、ウィザードで指定した ci プロジェクトの分しか StartBuild を許可していません。「編集」でステージを足しても、自動では増えないんです。Resource に deploy プロジェクトを 1 行足して解決しました。
"Resource": [
"arn:aws:codebuild:*:<アカウントID>:project/gaws-blogreview-cicd-ci",
"arn:aws:codebuild:*:<アカウントID>:project/gaws-blogreview-cicd-deploy"
]
❹ 直したら、今度は PassRole で落ちる
is not authorized to perform: iam:PassRole
on resource: arn:aws:iam::<アカウントID>:role/service-role/codebuild-gaws-blogreview-cicd-deploy-service-role
アクションに**サービスロールの上書き(ServiceRoleArnOverride)**が入っていました。中身はプロジェクトと同じロールでも、上書きを指定するとパイプラインのロールに iam:PassRole が必要になります。PassRole を足すより、上書きを外すほうが権限を増やさずに済むので、そちらにしました。
❺ 保存したら、承認待ちの実行がキャンセルされた
④を直してパイプラインを保存した直後、承認待ちだった別の実行が The approval action has been canceled. で打ち切られました。構成を変えると、古い構成の実行は先に進めないようです。「変更をリリースする」で実行し直して、ようやく全ステージ緑になりました。
■ まとめ
|
|
症状 |
原因 |
対処 |
|
① |
BuildspecOverride で保存できない |
上書き欄にプロジェクトと同じ値を入れた |
欄を空にする |
|
② |
Project already exists |
プロジェクトだけ先に作成済み |
既存のプロジェクトを選ぶ |
|
③ |
codebuild:StartBuild で失敗 |
ウィザードのポリシーが ci プロジェクトだけ対象 |
Resource に deploy を追加 |
|
④ |
iam:PassRole で失敗 |
ServiceRoleArnOverride が入っている |
上書きを外す |
|
⑤ |
承認待ちがキャンセル |
パイプラインの構成を変えた |
実行し直す |
①④は、上書き欄にプロジェクトと同じ値を入れていたのが原因で、半分は自分のせいです。上書きは「プロジェクトと違うことをしたいとき」のものなので、同じなら空のままでいい。
もう 1 つのコツは、エラーの User: に出ているロールを最初に見ることです。AWSCodePipelineServiceRole-... ならパイプラインのロール、codebuild-... なら CodeBuild のロールが止められています。
■ 感想・次にやりたいこと
コンソールでポチポチ作ってみて、「CI/CD を作るだけなら簡単。でも後から手を入れた途端に難しくなる」と体感できたのがいい経験になりました。
ウィザードに沿ってパイプラインを作るところまでは、本当にすぐです。CI は 1 回目からいきなり緑でした。ただ、ステージを後から足した途端に IAM の面倒を自分で見る必要があります。
StartBuild と PassRole は、どちらもエラーメッセージを読めば原因はすぐ分かるのですが、「パイプラインのロール」「CodeBuild のロール」「CDK のブートストラップロール」と登場人物が 3 人いるので、今どのロールが止められているのか を見極めるのが一番の勘所でした。
手元で cdk deploy を叩いていたときは、テストをしたか、どのコードを出したかを全部自分の記憶に頼っていました。今は push すれば検品ラインが勝手に動き、合格したものだけが承認待ちで並んでくれます。 そして、その置き換えた「仕組み」に何の権限を渡すのかを、ロールごとに決めていく作業こそが CI/CD 構築の中身なんだな、と。
一方で、コンソールで作ってみて弱点も見えました。
- なぜその設定にしたのかが、コードとしてレビューや差分管理できない(今回のタグも付け忘れていました……)
- ウィザードが自動で作った IAM ポリシーの中身が見えにくい(③はまさにこれ)
- 作り直すのがつらい
振り返ると、今回の詰まりは 5 つ全部が「手で後から足した部分」でした。CDK ならアクションを足すだけで、パイプラインのロールに StartBuild の権限も一緒に付きますし、ロールや buildspec を上書きする欄もありません。少なくとも③④は、書き方を覚えるまでもなく起きないはずです。次は、このパイプラインを CDK で書き直してみます。
■ 料金
|
サービス |
使った量 |
単価(東京) |
金額 |
|
CodeBuild(arm / MEDIUM) |
ビルド 9 回、計 約 39 分(1 分単位で切り上げ) |
$0.009 / 分 |
約 $0.35 |
|
CodePipeline(V2) |
アクションの実行時間 計 約 50 分(手動承認は対象外) |
$0.002 / 分 |
約 $0.10(無料枠の月 100 分に収まれば $0) |
|
合計 |
|
|
約 $0.45(100 円しない) |
失敗も含めて 7 回パイプラインを動かして、この金額です。S3 のアーティファクトや CloudWatch Logs、ECR も少し使っていますが、ほぼ誤差です。
※この記事は 2026 年 10 月時点のコンソール画面と挙動に基づきます。
