CodePipeline×CodeBuildにClaude Codeで自動テストを組むAWSネイティブCI/CD
buildspec.ymlの実例、CodeBuildの環境変数とIAM最小権限、デプロイ失敗の切り分けを実体験で解説。Claude CodeでAWSネイティブなCI/CDを安全に組む手順。
金曜の夕方、ECSへのデプロイが赤くなった。ログを開くと Cannot connect to the Docker daemon。CodeBuildでDockerイメージをビルドしている行で止まっていました。
原因は拍子抜けするほど単純で、CodeBuildプロジェクトに privileged: true を付け忘れていただけ。でも、その1行に気づくまで僕は40分、buildspec.ymlとIAMポリシーとネットワーク設定を行ったり来たりしていました。CodePipelineの失敗は、画面の赤い印を見ても「どのstageのどのactionで、何が足りなかったか」がすぐ分からない。そこがいちばんしんどいところです。
この記事は、そのしんどさを減らすための実装メモです。GitHub Actionsの話ではありません。ECRへのプッシュ、ECSへのデプロイ、Parameter Storeからのシークレット注入——AWSの中だけで完結させるCI/CDを、Claude Codeを使って組む手順に絞ります。GitHub Actionsで同じことをやりたい人はClaude CodeでGitHub Actionsを高度化する実践ガイドのほうが近いので、先にそちらを見てください。
この記事の要点
- CodePipelineは「Source→Build→Deploy」を流すベルトコンベア。実際の作業(テスト・ビルド・Dockerイメージ化)はCodeBuildのbuildspec.ymlに書く。ここが本体です。
- buildspec.ymlはコピペで動くものを1つ用意しました。Node.js 20、
npm test、Dockerビルド、ECRプッシュまで通ります。 - CodeBuildの環境変数は平文で書かない。トークン類はParameter Store / Secrets Managerから注入する。IAMはaction単位で最小権限に絞る。
- デプロイが落ちたら、pipeline全体ではなくstageとactionを見る。Sourceなら接続、Buildならログ、Deployならartifact名とリージョンを疑う。確認コマンドを後半に置きました。
- Claude Codeには「実装して」だけでなく、禁止事項(広いIAMを付けない・承認を抜かない)と確認コマンドまで渡すと、レビューが一気に楽になります。
なぜGitHub ActionsではなくCodePipelineなのか
正直に言うと、GitHubでコードを管理しているなら、たいていの場合GitHub Actionsのほうがラクです。YAMLを1枚置けば動くし、AWSの権限まわりで悩むことも少ない。
それでもCodePipeline + CodeBuildを選ぶ理由は、ひとつだけ。AWSリソースとの距離が近いことです。ECRにイメージを積む、ECSのサービスを差し替える、CloudFormationスタックを更新する、Parameter Storeから設定を読む——こういう操作を、外部サービスにAWSの鍵を渡さずにAWSの中で完結させたいとき、この組み合わせがいちばん素直に書けます。IAMロールでCodeBuildに権限を渡せるので、長期のアクセスキーをどこかに置く必要もありません。
逆に言うと、デプロイ先がVercelやNetlifyだったり、AWSをほとんど使っていないなら、わざわざCodePipelineを選ぶ理由は薄いです。「AWSの中で動くものを、AWSの仕組みでデプロイする」——その一点に価値があると思ってください。
用語を4つだけ揃える(ここを曖昧にすると事故る)
CodePipelineの設計は、最初に4つの言葉をはっきりさせるだけで見通しが段違いになります。
- pipeline: リリース全体の流れ。ベルトコンベアそのもの。
- stage: SourceやBuildのような大きな区切り。
- action: stageの中で実行する1つの作業。CodeBuildを動かす、承認を待つ、など。
- artifact: actionから次のactionへ渡す成果物。Sourceで取ったコードが
SourceOutput、Buildで作ったdistやimageがBuildOutput。
AWS公式のCodePipeline conceptsでも、pipelineは複数のstageでできていて、stageの中にactionがあり、artifactをaction間で受け渡す、と説明されています。
なぜこの4語にこだわるかというと、Claude Codeへの依頼でもエラーの切り分けでも、全部この単位で考えるからです。「Buildで落ちた」のか「Deployで落ちた」のかで見る場所がまるで違う。最初に作るなら、Source → Build → Test → Approve → Deploy の5ステージで十分です。本番デプロイの前にManual approval(人間の承認)を1枚挟んでおくと、寝ぼけた金曜の夜でも事故を止められます。
| stage | action | artifact | 何をするか |
|---|---|---|---|
| Source | CodeStar connection(GitHub) | SourceOutput | mainブランチの変更を取る |
| Build | CodeBuild | BuildOutput | npm ci、テスト、ビルド、イメージ作成 |
| Test | CodeBuild | TestOutput | smoke testやlintを分けて見る |
| Approve | Manual approval | なし | 本番反映の前に人間が確認する |
| Deploy | ECS / S3 / CloudFormation | BuildOutput | 実環境へ反映する |
まずbuildspec.ymlをClaude Codeに書かせる
CI/CDの本体は、見た目が地味な buildspec.yml です。CodeBuildはこのファイルに書いたコマンドを上から実行するだけ。GitHub Actionsの steps: に当たるものだと思ってください。
僕はいつもこんな粒度でClaude Codeに頼みます。条件を箇条書きで渡すのがコツで、ふわっと「CI/CD作って」と言うと、IAMが広すぎたりテストを飛ばしたりします。
claude -p "
CodeBuild の buildspec.yml を生成して。条件は以下。
ビルド内容:
- Node.js 20、npm ci でインストール
- npm test でユニットテスト(落ちたらビルド失敗)
- npm run build で TypeScript ビルド
- Docker イメージをビルドして ECR にプッシュ
- イメージタグは CODEBUILD_RESOLVED_SOURCE_VERSION(Git SHA)と latest
セキュリティ:
- ECR レジストリの URL は Parameter Store から取る(平文で書かない)
- ECR プッシュ後に Trivy で HIGH/CRITICAL をスキャンし、あればビルド失敗
成果物:
- ECS デプロイ用に imagedefinitions.json を出力
"
返ってくる buildspec.yml がこれです。コメントは日本語に直してあります。これはそのまま動く形にしてあるので、リポジトリ直下に置けます。
version: 0.2
env:
variables:
AWS_DEFAULT_REGION: ap-northeast-1
ECR_REPO_NAME: myapp
parameter-store:
# トークンやレジストリURLは平文で書かず Parameter Store から注入する
ECR_REGISTRY: /myapp/ecr-registry
phases:
install:
runtime-versions:
nodejs: 20
commands:
- echo "依存をインストール中..."
- npm ci
pre_build:
commands:
- echo "テスト実行(落ちたらここで止まる)..."
- npm test
- echo "ECR にログイン..."
- aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REGISTRY
- IMAGE_TAG=$CODEBUILD_RESOLVED_SOURCE_VERSION
- IMAGE_URI=$ECR_REGISTRY/$ECR_REPO_NAME:$IMAGE_TAG
build:
commands:
- echo "TypeScript ビルド..."
- npm run build
- echo "Docker イメージをビルド..."
- docker build -t $IMAGE_URI -t $ECR_REGISTRY/$ECR_REPO_NAME:latest .
post_build:
commands:
- echo "イメージを ECR にプッシュ..."
- docker push $IMAGE_URI
- docker push $ECR_REGISTRY/$ECR_REPO_NAME:latest
- echo "Trivy で脆弱性スキャン(HIGH/CRITICAL があれば失敗)..."
- |
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image \
--exit-code 1 \
--severity HIGH,CRITICAL \
$IMAGE_URI
- echo "ECS デプロイ用の imagedefinitions.json を作成..."
- printf '[{"name":"app","imageUri":"%s"}]' $IMAGE_URI > imagedefinitions.json
artifacts:
files:
- imagedefinitions.json
reports:
UnitTestResults:
files:
- "coverage/junit.xml"
file-format: JUNITXML
ここで覚えてほしいのは3点だけです。ひとつ、テストは pre_build に置くと、ビルドやプッシュより先に落ちてくれて無駄がない。ふたつ、env.parameter-store を使うと、ECRのURLやトークンを平文でymlに書かずに済む。みっつ、reports セクションに junit.xml を渡すと、CodeBuildの画面でテスト結果が表で見られます。buildspec の書式で迷ったらAWS公式のbuildspecリファレンスが確実です。
CodeBuildの環境変数とIAMを最小権限にする
ここが事故の温床です。順番に潰します。
環境変数は3層で考える。 CodeBuildの環境変数には種類があります。variables はただの平文(リージョンやリポジトリ名など、見られても困らないもの)。parameter-store はSystems Manager Parameter Storeから取る値。secrets-manager はSecrets Managerから取る値。トークン・パスワード・APIキーの類は絶対に variables に書かない。これだけで「GitHubにbuildspec.ymlごとトークンを公開してしまった」という典型的な事故が消えます。
IAMはaction単位で絞る。 やってしまいがちなのが、CodeBuildのサービスロールに AdministratorAccess を付けて「とりあえず動かす」こと。動きますが、後で誰も権限を削れなくなります。Dockerイメージをビルドして1つのECRリポジトリにプッシュするだけなら、必要なのはECR系の操作だけです。CDKで書くとこうなります。
// CodeBuild に渡す権限は「ECR にこのリポジトリだけ」に絞る
const region = cdk.Stack.of(this).region;
const account = cdk.Stack.of(this).account;
buildProject.addToRolePolicy(new iam.PolicyStatement({
// ログイン用トークンの取得だけは resource を絞れないので別文に分ける
actions: ["ecr:GetAuthorizationToken"],
resources: ["*"],
}));
buildProject.addToRolePolicy(new iam.PolicyStatement({
actions: [
"ecr:BatchCheckLayerAvailability",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage",
],
// 全 ECR ではなく、対象リポジトリの ARN だけに限定する
resources: [`arn:aws:ecr:${region}:${account}:repository/myapp`],
}));
ecr:GetAuthorizationToken だけはリソース指定ができない仕様なので別の文に分けます。それ以外のプッシュ系は、対象リポジトリのARNに絞る。「全部 *」と「actionごとに絞る」の差は、最初に書くときの数分だけです。権限設計をもう少しちゃんとやりたくなったらClaude Code × AWS IAM 完全ガイドに最小権限の考え方をまとめてあります。
Dockerを使うなら privileged: true。 冒頭で40分溶かしたやつです。CodeBuildでdocker buildを動かすには、プロジェクト側で privileged: true を立てる必要があります。これがないと Cannot connect to the Docker daemon でビルドが赤くなります。CDKなら codebuild.PipelineProject の environment に privileged: true を入れるだけ。Trivyのようにdocker.sockをマウントするツールを使うときも同じです。
パイプライン全体をCLIの骨格で先に見る
CDKでいきなり全部抽象化すると、初心者はAWSコンソールのパイプライン画面とコードの対応が見えなくなります。僕は最初の1本だけは、構造が目で追えるJSONで作るのをおすすめします。次の pipeline.json がたたき台です。ARN・bucket・repo・project名は自分の環境に置き換えてください。
{
"pipeline": {
"name": "webapp-main",
"roleArn": "arn:aws:iam::123456789012:role/service-role/AWSCodePipelineServiceRole-ap-northeast-1-webapp-main",
"artifactStore": { "type": "S3", "location": "my-codepipeline-artifacts-apne1" },
"stages": [
{
"name": "Source",
"actions": [{
"name": "Source",
"actionTypeId": { "category": "Source", "owner": "AWS", "provider": "CodeStarSourceConnection", "version": "1" },
"configuration": {
"ConnectionArn": "arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"FullRepositoryId": "your-org/your-repo",
"BranchName": "main",
"OutputArtifactFormat": "CODE_ZIP"
},
"outputArtifacts": [{ "name": "SourceOutput" }],
"runOrder": 1
}]
},
{
"name": "Build",
"actions": [{
"name": "BuildAndUnitTest",
"actionTypeId": { "category": "Build", "owner": "AWS", "provider": "CodeBuild", "version": "1" },
"configuration": { "ProjectName": "webapp-build" },
"inputArtifacts": [{ "name": "SourceOutput" }],
"outputArtifacts": [{ "name": "BuildOutput" }],
"runOrder": 1
}]
},
{
"name": "ApproveProd",
"actions": [{
"name": "ApproveProduction",
"actionTypeId": { "category": "Approval", "owner": "AWS", "provider": "Manual", "version": "1" },
"configuration": { "CustomData": "smoke test と CloudWatch アラームを確認してから承認" },
"runOrder": 1
}]
},
{
"name": "Deploy",
"actions": [{
"name": "DeployStaticSite",
"actionTypeId": { "category": "Deploy", "owner": "AWS", "provider": "S3", "version": "1" },
"configuration": { "BucketName": "my-webapp-prod", "Extract": "true" },
"inputArtifacts": [{ "name": "BuildOutput" }],
"runOrder": 1
}]
}
]
}
}
作成と確認はこの3コマンドです。
aws codepipeline create-pipeline --cli-input-json file://pipeline.json
aws codepipeline get-pipeline --name webapp-main
aws codepipeline start-pipeline-execution --name webapp-main
公式のCreate a pipeline, stages, and actionsにもある通り、パイプラインは最低でもSourceと、もうひとつ(BuildまたはDeploy)のstageが必要です。構造が頭に入ったら、同じものをCDKに移すと管理がラクになります。ECSへ寄せるならClaude Code × AWS ECS/Fargate 完全ガイド、静的サイトをS3/CloudFrontに出すならClaude Code × AWS S3入門が地続きです。
デプロイが落ちたときの切り分け順
ここがこの記事でいちばん書きたかったところです。CodePipelineが赤くなったとき、僕はpipeline全体を眺めるのをやめました。落ちたstageと、そのactionだけを見る。 場所によって疑うものが決まっているからです。
- Sourceで落ちた: 接続ARN、ブランチ名、
OutputArtifactFormat。CodeStar connectionが「保留中」のまま承認されていないこともよくあります。 - Buildで落ちた: CodeBuildのログ、buildspec.ymlの該当phase、環境変数、IAM。だいたいここです。
- Deployで落ちた: 入力artifactの名前、S3バケット、リージョン、ECSならタスク定義のコンテナ名。
確認はこのコマンドで上から流します。get-pipeline-state で落ちたactionを特定し、そのBUILD_IDをCodeBuildのログに突っ込む、という順番です。
# どの stage/action で落ちたかを一覧で見る
aws codepipeline get-pipeline-state --name webapp-main
# 直近のアクション実行の詳細(失敗理由が入っている)
aws codepipeline list-action-executions --pipeline-name webapp-main --max-results 5
# 該当 BUILD_ID のビルド詳細
aws codebuild batch-get-builds --ids webapp-build:BUILD_ID_FROM_ACTION_EXECUTION
# CodeBuild のログを追う(ここに本当の原因が出る)
aws logs tail /aws/codebuild/webapp-build --since 30m --follow
僕が実際にハマった失敗を、多い順に3つ書きます。1つ目は artifact名の取り違え。Buildで BuildOutput という名前で出したのに、Deploy側で SourceOutput を読んでいて「artifactが見つからない」で落ちる。2つ目は IAMの権限不足。CodeBuildのサービスロールにECRやS3、CloudFormationの権限が足りず、ビルドは通るのにプッシュやデプロイで落ちる。3つ目は 平文トークン。Parameter StoreやSecrets Managerを使わず環境変数にトークンを直書きして、レビューで指摘される。
AWS公式のactions guideにある通り、actionにはSource・Build・Test・Deploy・Approval・Invokeの種類があります。権限もこのaction単位で分けて考えると、どこに何を足すべきかが迷いません。
Claude Codeに丸投げしないための依頼文
Claude Codeにそのまま「CI/CD作って」と言うと、よかれと思ってIAMを広くしたり、承認stageを抜いたり、CloudFrontのキャッシュ削除を忘れたりします。だから僕は、作ってほしいものと一緒に禁止事項と確認コマンドを必ず渡します。
このリポジトリに AWS CodePipeline + CodeBuild の CI/CD を追加して。
目的:
- Source: GitHub main(CodeStar connection 経由)
- Build: CodeBuild で npm ci、npm test、npm run build、ECR へイメージプッシュ
- Test: smoke test を別の CodeBuild action で実行
- Approve: 本番の前に Manual approval を置く
- Deploy: ECS サービスへデプロイ
制約:
- IAM に AdministratorAccess やワイルドカード権限を付けない
- 本番 deploy を承認 stage なしで自動化しない
- secret は平文の環境変数に置かず Parameter Store か Secrets Manager を使う
- 既存の pipeline や bucket を削除しない
成果物:
- buildspec.yml
- pipeline.json または CDK stack
- 失敗時の確認コマンド
- README の運用手順(get-pipeline-state と CodeBuild ログの見方)
進め方:
- 変更前に現在の構成を説明してから diff を見せて
この依頼文はAWSのDefine CI/CD pipelinesの考え方に寄せてあります。「実装して」だけでなく「どの公式概念に合わせたか説明して」と添えると、出てきたコードのレビューがかなり速くなります。CloudFormation/CDKで全体を組むときの注意点はClaude Code × AWS CloudFormation/CDK 完全ガイドにまとめてあります。
よくある質問
Q. CodeBuildでテストだけ動かしたい。最小のbuildspec.ymlは?
A. install で npm ci、build で npm test を書くだけで動きます。タグやDockerが要らないなら、上の例から pre_build 以降のECR部分を消せばOKです。
Q. Cannot connect to the Docker daemon が出る。
A. CodeBuildプロジェクトの environment.privileged が true になっているか確認してください。Dockerを使うビルドではこれが必須です。
Q. テスト結果をPRごとに見たい。
A. buildspec.ymlの reports セクションに junit.xml などを渡すと、CodeBuildの画面でテストのレポートが表示されます。カバレッジは lcov.info を CLOVERXML 形式で渡せます。
Q. シークレットはどう渡すのが安全?
A. env.parameter-store(Parameter Store)か env.secrets-manager(Secrets Manager)から注入します。env.variables に直書きするとログやリポジトリに残るので避けてください。
Q. 本番デプロイをいきなり自動化していい? A. 最初はやめたほうがいいです。Deployの前にManual approval stageを1枚置いて、smoke testとCloudWatchを見てから人間が承認する形にすると、事故ったときに止められます。
実際に試した結果
いくつかパイプラインを組んでみて、いちばん効いたのは承認stageでも凝ったCDKでもなく、artifact名を最初に固定したことでした。SourceOutput・BuildOutput・TestOutput と決め打ちしておくだけで、落ちたときに「どこで壊れたか」が一目で追えるようになります。
逆に遠回りだったのは、1本目からCDKで全部を抽象化しようとしたこと。コンソールの画面とコードの対応が見えなくなって、デバッグのたびに迷子になりました。最初の1本はJSONかコンソールで構造を目に焼き付けて、2本目からCDK化する。この順番にしてから、新規パイプラインの構築時間が体感で1/4になりました。
そしてもうひとつ。CodePipelineの設計は、結局IAM・S3・ECS・CloudFrontの理解と必ずつながります。Lambdaを絡めるならClaude Code × AWS Lambda 完全ガイドも一緒に読むと、点ではなく流れで掴めます。CI/CDをチームに本格導入するなら、buildspec・IAM・承認・切り戻しまでセットで設計が要るので、そこまで詰めたい人は研修・相談で実際のAWS構成に合わせて一緒に組めます。まずはbuildspec.ymlを1枚、npm test から動かしてみてください。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
制作会社がClaude Codeに触らせる前に決める権限チェックリスト
クライアントサイトを壊さずにAI編集を使うための、制作会社向け権限と確認の型です。
SaaSサポートのバグ報告をClaude Codeで再現手順に変える実務フロー
問い合わせ文をそのまま開発へ投げず、再現手順、証拠、次の一手に整えるサポート向け手順です。
Obsidianの古いメモをClaude Codeの指示書に変える10分ルーチン
Obsidianに溜めたメモが毎回ゴミになる人へ。事実・決定・未確認に仕分けして、Claude Codeがそのまま動ける指示書に変える朝の10分の型を紹介します。