- 1 §1 なぜ DevOps Vol3 か — DevOps 三層構造 (基礎→応用→高度) + 三部作ナビ
- 2 §2 CodePipeline V2 本番運用 — V2アクションタイプ拡張 × 条件付き実行 × Variables × Triggers
- 3 §3 Pipeline as Code 本番運用 — CDK Pipelines × Wave × Stage × Step × Manual approval ★山場1
- 3.1 3.1 cdk-pipelines library の基本構造
- 3.2 3.2 Pipeline 定義の3要素 — ShellStep / CodeBuildStep / ManualApprovalStep
- 3.3 3.3 Wave / Stage / Step 階層モデル — 並列実行と依存関係
- 3.4 3.4 ApplicationStage 設計 — pre/post hooks と Stack output 連携
- 3.5 3.5 Self-mutating の仕組み — buildPipeline() と自動更新メカニズム
- 3.6 3.6 Cross-account deploy — CDK bootstrap × IAM role × KMS key policy
- 3.7 3.7 Manual approval ゲート — ManualApprovalStep × SNS 通知 × timeout
- 3.8 3.8 完全な Pipeline 定義例 — Dev → Stg → Prd 三環境昇格
- 4 §4 GitOps 連携本番運用 — CodeBuild × GitHub Actions hybrid × OIDC × Reusable workflow
- 5 §5 Self-mutating pipelines 本番運用 — CDK self-update × Pipeline drift × Cross-account deploy ★山場2
- 5.1 5-1 Self-mutating の仕組み — CDK Pipelines が自分自身を更新する
- 5.2 5-2 初回 cdk deploy — Bootstrap から Pipeline 作成まで
- 5.3 5-3 Self-mutating サイクル — コード変更から Pipeline 自動更新まで
- 5.4 5-4 Pipeline drift 検知 — 実環境と CDK 定義の乖離
- 5.5 5-5 Cross-account deploy — 環境ごとのアカウント分離
- 5.6 5-6 Rollback 戦略 — Stage / CloudFormation / 手動
- 5.7 5-7. Self-mutating 運用ベストプラクティス 5選
- 6 §6 詰まりポイント7選 図解
- 6.1 詰まり1: CodePipeline V2 Trigger 設定ミス — ブランチフィルタ未設定で全PR起動
- 6.2 詰まり2: CDK Pipelines Stack output cross-reference 失敗
- 6.3 詰まり3: GitHub Actions → AWS OIDC trust policy 設定ミス
- 6.4 詰まり4: Self-mutating cycle — CDK 自身更新でループ
- 6.5 詰まり5: Cross-account permission — KMS/S3 設定漏れ
- 6.6 詰まり6: Variables resolution タイミング — Runtime/Compile time 混在
- 6.7 詰まり7: Manual approval timeout — 7 日制限 + SNS 通知未設定
- 7 §7 アンチパターン → 正解パターン変換演習
- 8 §8 まとめ + DevOps 三部作完成 + 46 記事化告知 + 全軸クロスリンクナビ
§1 なぜ DevOps Vol3 か — DevOps 三層構造 (基礎→応用→高度) + 三部作ナビ
AWS DevOps / CI/CD 実践シリーズは「基礎 → 応用 → 高度」の三層構造で設計されている。Vol1 で CI/CD の土台を築き、Vol2 で多 workload への適用を広げた読者が、本 Vol3 で到達するのは「Pipeline 自体を Code で管理・自動更新する」という次のステージだ。
「CI/CD パイプラインを整備した。しかし今度はパイプライン自体のメンテナンスに手が回らなくなった」——この状況は、ある段階まで成長した開発チームが必ず直面する壁だ。Vol1/Vol2 で構築したパイプラインが 5 本・10 本と増えるにつれ、環境ごとの差分管理・Branch 制御の複雑化・Cross-account 権限の属人化という 3 つの問題が同時に顕在化してくる。本記事はその 3 問題を「Pipeline 自体を Code 化する」ことで根本解決する道筋を示す。
本記事では CodePipeline V2 の高度機能(V2 アクション拡張 / 条件付き実行 / Variables / Triggers)から始まり、CDK Pipelines による Pipeline as Code、GitHub Actions × CodeBuild の GitOps 連携、そして Self-mutating Pipeline と Cross-account デプロイまでを段階的に習得する。最終的に「git push だけで Pipeline 自体が自動更新される」状態の実現を目指す。
Vol1 から Vol3 へ — 三層の架橋
Vol1(基礎) では、CodePipeline × CodeBuild × CodeDeploy の 4 本柱と GitHub Actions OIDC 基礎を習得した。コンソールから Source → Build → Test → Deploy の一本道パイプラインを手動構築し、「コード Push から本番反映までが人手なしで完結する」体験を初めて得た段階だ。CI/CD の本質である「ヒューマンエラーの排除」と「デプロイ頻度の向上」を体感した起点でもある。
このとき構築したパイプラインには共通の制約がある。Pipeline 定義はコンソール上の設定であり、Git に記録されない という点だ。誰がいつ Stage を追加・変更したかが追跡不能なまま本番運用に入っているケースが多い。これは Vol1 段階ではほぼ問題にならないが、チーム規模と環境数が増えると深刻な課題になる。
Vol2(応用) では、Container CD(ECS Blue/Green デプロイ・EKS Rolling Update)、CodeArtifact(プライベート npm/Maven リポジトリ管理)、SAM Pipeline(Serverless CD)、Amplify Hosting(Static Site CD)と、多種多様な workload に CI/CD を広げた。「どのサービスにも CI/CD を適用できる」ことがゴールだった。
しかし Vol1 から引き継いだ「Pipeline 定義はコンソール上の設定」という制約はそのままで、むしろパイプラインの数が増えるほど管理コストが線形に増大した。新しいサービスにパイプラインを追加するたびに既存パイプラインとの整合性確認が必要になり、環境間の一貫性が失われていく。5 本のパイプラインが 10 本になり、環境が Dev/Stg/Prod の 3 つに増えると、管理すべきパイプライン定義は実質 30 本に膨れ上がる。
Vol3(高度) の本記事では、その根本課題を解決する。「Pipeline を人が Console で定義・管理する」から「Pipeline 自体を Code として Git 管理し、コードの変更によってパイプライン自身が自動更新される」へと移行する。この状態を Self-mutating Pipeline という。さらに Branch / Tag / Path フィルタによる精密な Trigger 制御(CodePipeline V2)と、GitHub Actions と CodeBuild の役割分担(GitOps)を組み合わせることで、大規模チームでも一貫したデプロイプロセスを維持できる。
Vol3 で習得する 4 軸とそれぞれの課題解決効果を整理する。
| 軸 | テーマ | 解決する課題 |
|---|---|---|
| ① | CodePipeline V2 高度機能 | Branch/Tag/Path 精密制御・Variables Stage 間引き継ぎ |
| ② | CDK Pipelines (Pipeline as Code) | Pipeline 定義の Git 管理・Wave-Stage 階層化 |
| ③ | GitOps — OIDC hybrid | GitHub Actions ↔ CodeBuild の役割分担標準化 |
| ④ | Self-mutating × Cross-account | Pipeline 自動更新・Multi-account 昇格の自動化 |
Vol3 が必要になる 3 つのシグナル
次のいずれかに当てはまるエンジニアが、本記事の主な読者だ。
シグナル1 — Pipeline ドリフトが発生し始めた: コンソールで直接 Stage を追加・変更しており、変更履歴が Git に残らない。Dev / Stg / Prod の 3 環境でパイプラインが微妙に異なり始め、「どの環境の定義が正しいのか」が不明な状態に陥っている。インシデント対応中に Pipeline を手動変更したが、その後元に戻したかどうか確認できない、という事態が起きている。
シグナル2 — Branch / Tag ベースのリリース制御が煩雑になった: feature branch の CI と main branch の CD を同一 Pipeline で制御しようとして条件分岐が複雑化している。または git tag v1.2.3 で本番デプロイを自動起動したいが、現行 Pipeline では Tag Trigger がなくスクリプトで代替している。docs/ 配下のみ変更されたコミットでも Pipeline が全 Stage を走り切る無駄が発生し、CI リソースとコストが浪費されている。
シグナル3 — Cross-account デプロイで IAM 設計が属人化した: Dev / Stg / Prod を分離した Multi-account 構成に移行したが、Pipeline からの Cross-account 権限設計が標準化されていない。デプロイ先アカウントの IAM Role ARN が tfvars に直書きされ、KMS Grant や S3 Bucket Policy の設定根拠が担当者の記憶に依存している。
DevOps 三層構造マップ
3 つの Vol が積み重なる構造を整理する。
層Vol主テーマ 到達状態
─────── ─── ────────────────────────────────────── ──────────────────────────────────────
基礎 1Pipeline/Build/Deploy 4本柱 + GHA OIDCConsole から CI/CD を構築できる
応用 2Container / Serverless / Static CD多 workload に CI/CD を適用できる
高度 3Pipeline as Code / GitOps / Self-mutating Pipeline 自体を Code で管理できる
Vol3 の高度層に到達すると、次のことが可能になる。
cdk synth→git pushだけで Pipeline 自体が自動更新される (Self-mutating)- Branch / Tag / Path フィルタで精密な Trigger 制御ができる (CodePipeline V2 Triggers)
- GitHub Actions と CodeBuild を役割分担した hybrid Pipeline を設計できる (GitOps)
- Dev → Stg → Prod への Multi-environment 昇格を Wave / Stage で自動化できる (CDK Pipelines)
到達後は、「パイプラインを管理する工数」がほぼゼロに近づく。新しい Stage を追加する際は TypeScript / Python で 10 行程度を追記して git push するだけで、Pipeline 自体が新 Stage を含む形に自己更新される。
Pipeline as Code が解決する根本問題
Pipeline as Code とは、パイプラインの構造・Stage 数・アクション設定・権限などを、コード(CDK TypeScript / Terraform HCL)として Git リポジトリにコミットする手法だ。Console 上の「設定」ではなく「コード」として管理することで、以下の根本問題が解決する。
問題1 — 変更履歴の不透明性: Console 変更は CloudTrail に記録されるが、「なぜ変更したか」という文脈は残らない。コードであれば git log と PR ディスクリプションで「何を・なぜ・いつ・誰が変えたか」が完全に追跡できる。レビューを経た変更だけが本番パイプラインに反映されることで、意図しない Stage 追加や削除が防げる。
問題2 — 環境間ドリフトの蓄積: Dev で試した変更を Stg/Prod に反映し忘れる事故がコード化によって防げる。Pipeline 定義が単一の Git ブランチとして管理されるため、cdk deploy または git push 一発で全環境が同一定義に揃う。CDK Pipelines では Wave/Stage の構造そのものがパラメータ化でき、環境ごとの差分は EnvironmentConfig クラスで明示的に管理する。
問題3 — オンボーディングコストの高さ: Console で構築されたパイプラインは「見ればわかる」構造だが、Stage の追加ルールや承認フロー設計の意図は記録されない。コードであれば新規メンバーが git clone してローカルで全体構造を把握でき、変更も PR ベースでレビューされる。CDK の型定義が設計意図をコードとして表現する補助になる。
CDK Pipelines はこれら 3 問題を TypeScript / Python の Pipeline / Stage / Wave / Step クラス定義で解決し、さらに Self-mutating 機能でパイプライン自身の定義変更をパイプライン自身が自動適用する。
CDK Pipelines Self-mutating の仕組み
CDK Pipelines の Self-mutating とは、「Pipeline 自身のコードが変更されたとき、Pipeline が自分を更新してから後続 Stage を実行する」仕組みだ。通常の手動管理 Pipeline との違いを整理する。
| 操作 | 手動管理 Pipeline | CDK Pipelines (Self-mutating) |
|---|---|---|
| Stage を追加したい | Console を開いて手動で Stage 追加 | TypeScript に addStage() を追記して git push |
| 本番環境に Stage を追加したい | Console で本番用 Pipeline に手動追加(差分リスク大) | 同一コードが全環境に自動適用 |
| Pipeline の変更履歴を確認したい | CloudTrail から手動追跡(文脈なし) | git log で変更内容と理由を確認 |
| Pipeline をロールバックしたい | Console で手動でステージを戻す | git revert してプッシュ |
Self-mutating の動作フローは次の通りだ。
git push→ Source Stage が起動- UpdatePipeline Step: CDK Synth の結果を使って Pipeline 定義を更新(ここが Self-mutating の核心)
- Pipeline が再起動し、更新後の定義で後続 Stage を実行
- Asset Stage → Deploy Staging → Deploy Production と Wave/Stage が順に実行される
Step 2 で Pipeline 自身が定義を更新するため、「新しい Stage をコードに追記した場合、その Push で初めてその Stage が Pipeline に追加され、かつ同じ Pipeline 実行内で新 Stage が実行される」という動作になる。これが通常の Console 管理では不可能な Self-mutating の本質だ。
Vol3 で実装する 4 軸の依存関係
4 軸は独立した機能ではなく、段階的に組み合わせる設計になっている。
| 軸 | 前提 | 習得後に可能になること |
|---|---|---|
| ① V2 高度機能 | Vol1 V1 Pipeline 経験 | Branch/Tag/Path/Variable による精密な Pipeline 制御 |
| ② CDK Pipelines | CDK 基礎 + ① の V2 概念 | Pipeline 定義を TypeScript/Python コードで Git 管理 |
| ③ GitOps OIDC hybrid | ② Wave/Stage + Vol1 OIDC | GitHub Actions と CodeBuild の役割分担を標準化 |
| ④ Self-mutating × Cross-account | ② CDK Pipelines 実装経験 | Pipeline の自律更新と Multi-account 昇格の完全自動化 |
① から ④ の順に学ぶことで、「V2 の個別機能 → Pipeline as Code → GitOps 連携 → 自律進化するパイプライン」の学習ラインを効率的に辿れる。
前提知識と事前準備
本記事を最大限活用するために、次の前提知識を確認してほしい。
| 前提知識 | 確認方法 | 不足している場合 |
|---|---|---|
| CodePipeline V1 の基本構造 | Vol1 §2 を読んだことがあるか | Vol1 §2 を先に読む |
| CodeBuild buildspec.yml の基本 | 実務またはハンズオン経験があるか | Vol1 §3 を参照 |
AWS CDK の基礎 (cdk init / cdk deploy) | CDK で Stack を 1 度でも作ったことがあるか | AWS CDK Workshop を先に実施 |
| GitHub Actions の YAML 基礎 | GitHub Actions の workflow ファイルを書いたことがあるか | Vol1 §5 GitHub Actions OIDC を参照 |
| IAM Role / Policy の設計基礎 | AssumeRole の仕組みを理解しているか | Vol1 §4 IAM 設計を参照 |
CDK の経験がない読者は、先に公式の CDK Workshop(無料・約 2 時間)を実施してから §3 CDK Pipelines セクションに進むことを推奨する。§2 CodePipeline V2 と §4 GitOps は CDK 未経験でも読み進められる。
本記事 §2 〜 §8 のロードマップ
本記事は §2 〜 §8 の 7 セクションで構成される。各セクションの役割と依存関係を示す。
| § | テーマ | 役割 |
|---|---|---|
| §2 | CodePipeline V2 高度機能 | V2 の新機能 5 軸を Terraform で習得 |
| §3 | CDK Pipelines — Pipeline as Code | §2 の V2 概念を CDK TypeScript で再実装 |
| §4 | GitOps — GitHub Actions × CodeBuild hybrid | §3 の Wave/Stage と OIDC を組み合わせる |
| §5 | Self-mutating Pipeline × Cross-account | §3 の CDK Pipeline を自己更新 + 多 account 展開 |
| §6 | 詰まりポイント7選 (Mermaid 判断ツリー) | §2-§5 の横断的な現場トラブルを体系化 |
| §7 | アンチパターン → 正解パターン演習 (5問) | §2-§5 の知識を自己確認する演習 |
| §8 | まとめ + 三部作完結 + 全軸クロスリンク | シリーズ接続点 + 後続記事へのナビ |
§2 → §3 → §4 → §5 の順に読み進めることで、「V2 の個別機能 → Pipeline as Code → GitOps 連携 → 自律進化するパイプライン」のスキルを体系的に身につけられる。§6・§7 は §2-§5 を先に読んでから挑むと、詰まりポイントとアンチパターンの背景が深く理解できる。
§2 と §3 は連続して読むことで相乗効果がある。§2 で Terraform を使って V2 Pipeline を定義した後、§3 で同等の構成を CDK TypeScript で書き直す。「同じ Pipeline を 2 つの言語で表現する」体験が、両者の設計思想の違いを際立たせる。§6 の詰まり7選は現場でのトラブルシュート時にそのまま参照できる設計になっており、§2-§5 の学習後に実務で直面した問題をここで素早く引けるよう構成されている。
Vol1(基礎): CodePipeline × CodeBuild × CodeDeploy × GitHub Actions OIDC — Console から CI/CD を構築する 4 本柱を習得。Source → Build → Test → Deploy の一本道を確立する起点。
Vol2(応用): Container CD × CodeArtifact × SAM Pipeline × Amplify Hosting — ECS Blue/Green・EKS Rolling・Serverless SAM・Static Site Amplify への多 workload CI/CD 展開。
Vol3(高度・本記事): CodePipeline V2 / CDK Pipelines / GitOps / Self-mutating — Pipeline 自体を Code で管理し、自動更新・Cross-account 昇格を実現。DevOps 三部作完結巻。
本記事の読者想定: Vol1/Vol2 読了済、または AWS CI/CD 実務経験 1 年以上。Console 構築の Pipeline がドリフトし始めた / Cross-account デプロイで詰まっている / CDK Pipelines に移行したいが設計方法がわからない、というエンジニアを主対象とする。
§2-§8 五大テーマ: ① CodePipeline V2 高度機能 → ② CDK Pipelines Wave/Stage → ③ GitOps OIDC hybrid → ④ Self-mutating × Cross-account → ⑤ 詰まり7選 × アンチパターン演習5問。
総行数目安: 本記事は §1-§8 合計で約 1900-2200 行の大型記事。各 § の学習時間目安は §2/§3/§4/§5 各 30-45 分・§6/§7 各 20-30 分・§8 15 分。
本記事のスタート地点は §2 CodePipeline V2 だ。V1 との差分を明確にした上で、新アクションタイプ / 条件付き実行 / Variables / Triggers / 実行モードの 5 機能を Terraform の完全例とともに解説する。まずここで「手動定義パイプラインの高度化」を完成させ、そこから §3 の CDK Pipelines へと移行する設計フローを体感してほしい。
§2 CodePipeline V2 本番運用 — V2アクションタイプ拡張 × 条件付き実行 × Variables × Triggers
CodePipeline V2 は 2023 年後半に GA した新世代パイプラインエンジンで、V1 にはなかった アクションタイプ拡張 / 条件付き実行 / Variables / Triggers / 実行モード選択 の 5 機能が核心だ。V1 と V2 は同じ CodePipeline コンソールで共存できるが、新機能はすべて V2 専用となっている。既存の V1 Pipeline を V2 に移行する際はコンソールの「Pipeline type」変更だけで済み、既存の Stage 構成はそのまま引き継がれる。
V1 vs V2 の主要差分
| 機能カテゴリ | V1 | V2 |
|---|---|---|
| Pipeline タイプ指定 | 指定不要 (V1 固定) | pipeline_type = "V2" が必須 |
| アクションタイプ | CodeBuild / Lambda / CloudFormation / S3 等 | V1 全種 + GitHub (V2) / Bitbucket / S3 (V2) |
| 条件付き実行 (Conditions) | 非対応 | Stage / Action 単位の Branch/Tag/Path/Variable 条件 |
| Variables | Stage 間の限定的な受け渡し | Pipeline / Stage / Action 3 レベル + namespace |
| Triggers | S3 変更 / CodeCommit EventBridge のみ | GitHub webhook / Bitbucket / Tag filter / Path filter |
| 実行モード | SUPERSEDED 固定 | QUEUED / SUPERSEDED / PARALLEL 選択可 |
| 課金モデル | Pipeline 数 × 月額 ($1/Pipeline/月) | アクション実行回数課金 ($0.002/アクション実行) |
料金の判断基準: 月間 Pipeline 実行回数が少ない(月 50 回未満)パイプラインは V2 が有利。高頻度(月 500 回超)の Pipeline は V1 の方がコスト面で有利になる場合がある。移行前に料金試算を必ず実施すること。
V2 アクションタイプの実態
V2 の新アクションタイプで最も重要なのは GitHub (V2) と Bitbucket だ。いずれも CodeStar Connection を経由して接続し、Branch / Tag / Path フィルタを Pipeline 定義内で直接指定できる。
GitHub (V2) アクション の特徴:
– GitHub App を使った OAuth 接続(V1 の CodeStar Connection ARN を流用可能)
– Branch フィルタ / Tag フィルタ / Pull Request フィルタを Pipeline 定義内で指定
– 特定ファイルパス変更時のみ Pipeline を起動する FilePathFilters に対応
– OutputArtifactFormat = "CODEBUILD_CLONE_REF" で CodeBuild に Git クローン参照を渡せる
Bitbucket アクション の特徴:
– CodeStar Connection 経由で Bitbucket Cloud に接続
– Branch / Tag フィルタは GitHub (V2) と同一構文
– Bitbucket Server(オンプレ)は対象外(CodeCommit または自己ホスト GitLab を使うこと)
S3 (V2) アクション の特徴:
– S3 バケットへのオブジェクト Put を Trigger として使用
– ObjectKeyFilter で対象オブジェクトのパターンマッチが可能(例: releases/*.zip)
– Lambda から S3 Put して Pipeline を起動するパターンに有用
Terraform による V2 Pipeline 定義(完全例)
V2 Pipeline を Terraform で定義する基本構造を示す。
resource "aws_codepipeline" "main" {
name = "my-pipeline-v2"
role_arn= aws_iam_role.pipeline.arn
pipeline_type = "V2"
execution_mode = "SUPERSEDED"
variable {
name = "Environment"
default_value = "staging"
description= "Deploy target environment"
}
artifact_store {
location = aws_s3_bucket.artifacts.bucket
type = "S3"
encryption_key {
id= aws_kms_key.pipeline.arn
type = "KMS"
}
}
stage {
name = "Source"
action {
name = "GitHub_Source"
category= "Source"
owner= "AWS"
provider= "CodeStarSourceConnection"
version = "1"
output_artifacts = ["source_output"]
configuration = {
ConnectionArn = aws_codestarconnections_connection.github.arn
FullRepositoryId = "myorg/myrepo"
BranchName = "main"
DetectChanges = "true"
OutputArtifactFormat = "CODEBUILD_CLONE_REF"
}
}
}
stage {
name = "Build"
action {
name = "Build"
category= "Build"
owner= "AWS"
provider= "CodeBuild"
version = "1"
input_artifacts = ["source_output"]
output_artifacts = ["build_output"]
namespace = "BuildVariables"
configuration = {
ProjectName = aws_codebuild_project.build.name
EnvironmentVariables = jsonencode([
{ name = "ENV", value = "#{variables.Environment}", type = "PLAINTEXT" }
])
}
}
}
stage {
name = "Deploy"
action {
name= "Deploy"
category = "Deploy"
owner = "AWS"
provider = "ECS"
version= "1"
input_artifacts = ["build_output"]
configuration = {
ClusterName = aws_ecs_cluster.main.name
ServiceName = aws_ecs_service.main.name
FileName = "imagedefinitions.json"
}
}
}
triggers {
provider_type = "CodeStarSourceConnection"
git_configuration {
source_action_name = "GitHub_Source"
push {
branches {
includes = ["main", "release/*"]
excludes = ["release/hotfix-*"]
}
file_paths {
includes = ["src/**", "infra/**"]
excludes = ["docs/**", "*.md"]
}
}
}
}
}
条件付き実行 (Conditions) の設計
V2 の重要な機能の一つが Stage / Action レベルの Conditions だ。これにより、同一 Pipeline で Branch / Tag / Path / 変数値によって異なる動作をさせられる。result = "SKIP" の場合、条件を満たさない Branch からの Push では Stage がスキップされる。result = "FAIL" に変えると条件不一致で Pipeline 全体が失敗扱いになる。
Stage Condition の構文
stage {
name = "Deploy_Production"
condition {
result = "SKIP"
rules {
name = "BranchCheck"
rule_type_id {
category = "Rule"
owner = "AWS"
provider = "BranchRefCondition"
version = "1"
}
configuration = {
BranchName = "main"
}
}
}
action {
name = "DeployProd"
category = "Deploy"
owner = "AWS"
provider = "ECS"
version = "1"
configuration = {
ClusterName = "production-cluster"
ServiceName = "my-service"
FileName = "imagedefinitions.json"
}
}
}
Tag フィルタを使った本番専用 Trigger
triggers {
provider_type = "CodeStarSourceConnection"
git_configuration {
source_action_name = "GitHub_Source"
push {
tags {
includes = ["v[0-9]+.[0-9]+.[0-9]+"]
excludes = ["v*-alpha", "v*-beta", "v*-rc*"]
}
}
}
}
git tag v1.2.3 && git push origin v1.2.3 のみで本番デプロイ Pipeline が起動し、feature branch へのコミットでは起動しない。セマンティックバージョンのみを対象にすることで、プレリリースタグによる誤起動を防ぐ。
Variables (変数) の設計
V2 の Variables は Pipeline / Stage / Action の 3 レベルで定義・参照できる。
| レベル | 定義場所 | スコープ | 主な用途 |
|---|---|---|---|
| Pipeline 変数 | Pipeline 定義の variable ブロック | 全 Stage から参照可 | 環境名 / デプロイ先 Region 等の固定値 |
| Action 変数 (namespace) | Action の namespace フィールド | 後続 Action が #{namespace.VAR} で参照 | ビルド成果物 URI / バージョン番号等 |
| 動的変数 | CodeBuild の exportedVariables | namespace 経由で後続 Stage に引き継ぎ | テスト結果 / デプロイ対象 Image tag 等 |
CodeBuild 出力変数の Stage 間引き継ぎ
Build Stage の CodeBuild が出力した変数を Deploy Stage で参照する完全な流れを示す。
stage {
name = "Build"
action {
name= "Build"
namespace = "BuildVars"
configuration = {
ProjectName = aws_codebuild_project.build.name
}
}
}
stage {
name = "Deploy"
action {
name = "Deploy"
configuration = {
ParameterOverrides = jsonencode({
ImageUri = "#{BuildVars.IMAGE_URI}"
BuildVersion = "#{BuildVars.BUILD_VERSION}"
})
}
}
}
CodeBuild 側の buildspec.yml で変数を公開する。
env:
exported-variables:
- IMAGE_URI
- BUILD_VERSION
phases:
build:
commands:
- IMAGE_URI="${ECR_URI}:${CODEBUILD_RESOLVED_SOURCE_VERSION}"
- BUILD_VERSION="${CODEBUILD_BUILD_NUMBER}"
- docker build -t "${IMAGE_URI}" .
- docker push "${IMAGE_URI}"
- printf '[{"name":"app","imageUri":"%s"}]' "${IMAGE_URI}" > imagedefinitions.json
#{BuildVars.IMAGE_URI} の参照が解決されるのは Build Stage の完了後だ。同一 Stage 内の別 Action から参照しようとすると null が展開される事故が多いため、変数の参照は必ず後続 Stage に限定すること。
Pipeline 実行モードの選択基準
V2 では Pipeline の同時実行をコントロールする 実行モード を 3 種から選択できる。
| モード | 動作 | 適合シナリオ | 注意点 |
|---|---|---|---|
| SUPERSEDED | 新実行が古い実行を中断 (V1 デフォルト) | 通常の CD Pipeline | テスト中の実行が新 Push で中断される |
| QUEUED | 実行を順番待ちキューに積む | 順序保証が必要なデプロイ | 長時間 Pipeline はキューが積み上がる |
| PARALLEL | 同時に複数実行を許可 | 独立した環境への並列デプロイ | 共有リソースへの並列更新でコンフリクト |
SUPERSEDED の注意点: 10 分かかるテストが走っている最中に新 Push が来ると、テスト実行が中断される。長時間テストを含む Pipeline では QUEUED を検討すること。
PARALLEL の注意点: 同一 ECS Service への Rolling Update を同時実行すると Deployment Controller のコンフリクトが発生する。リソース共有がない場合(例: 環境ごとに独立した ECS Cluster)に限定して PARALLEL を採用すること。

罠1 — ブランチフィルタ未設定で全 Push が起動:
triggers ブロックを省略すると V2 でも全ブランチへの Push で Pipeline が起動する。必ず branches.includes で対象ブランチを明示的に限定すること。罠2 — Tag Trigger と Branch Trigger の二重起動:
git push origin main --tags で main への Push と Tag 両方が起動条件を満たし、同一コミットで 2 回 Pipeline が走る。Branch Push と Tag Push を別 Pipeline に分離するか、branches.excludes と tags.includes を組み合わせて排他制御すること。罠3 — FilePathFilter は Pipeline 起動判定のみに作用:
file_paths.excludes = ["docs/**"] を設定しても、S3 Artifact にはフルソースが取得される。FilePathFilter は「起動するかどうか」の判定のみに作用し、CodeBuild への入力アーティファクトには影響しない。罠1 — Variables の resolution タイミング誤解: Pipeline 変数は Pipeline 起動時に評価される。Action の実行結果変数 (
#{namespace.VAR}) は当該 Action 完了後でないと後続 Stage から参照できない。同一 Stage 内の別 Action から参照すると null が展開されてデプロイが失敗する事故が頻発する。罠2 — 実行モード PARALLEL + 共有リソース:
execution_mode = "PARALLEL" にして同一 ECS Service への Rolling Update を同時実行すると Deployment Controller がコンフリクトし、サービスが不安定になる。共有リソースがある場合は必ず SUPERSEDED か QUEUED を選ぶこと。罠3 — namespace の大文字小文字区別:
namespace = "BuildVars" と定義した変数を #{buildvars.IMAGE_URI} と小文字で参照すると解決されず空文字になる。namespace は大文字小文字を区別するため、定義と参照を完全一致させること。□ 月間 Pipeline 実行回数を算出し、V1/V2 の料金差を試算したか
□ Branch / Tag / Path フィルタによる Trigger 制御の要件を整理したか
□ 既存の CodeStar Connection ARN を V2 で流用できることを確認したか
□ Variables で Stage 間に引き継ぐ値の一覧と namespace 名を設計したか
□ 実行モード (QUEUED/SUPERSEDED/PARALLEL) をリソース競合の観点で選択したか
□ Terraform に
pipeline_type = "V2" と triggers ブロックを追加したか§2 では CodePipeline V2 の V2 アクション拡張 / 条件付き実行 / Variables / Triggers / 実行モードを体系的に押さえた。続く §3 では、この V2 Pipeline を「Pipeline 定義ファイル自体を Git 管理する」Pipeline as Code (CDK Pipelines) へと進化させる。コンソールで手動構築してきたパイプラインを TypeScript コードで宣言し、git push 一発でパイプライン自体が自動更新される世界へ移行する。
§3 Pipeline as Code 本番運用 — CDK Pipelines × Wave × Stage × Step × Manual approval ★山場1
CDK Pipelines は aws-cdk-lib/pipelines モジュールが提供する高レベル抽象化 API で、CodePipeline を CDK コードで定義・管理する Pipeline as Code を実現する。Console や CloudFormation テンプレートを手動で管理する従来手法と違い、CDK Pipelines は「Pipeline の定義自体をコード化」し、コード変更時に Pipeline が自動更新 (Self-mutating) される仕組みを内蔵する。本セクションでは Pipeline の全構成要素を順番に組み立てていく。
3.1 cdk-pipelines library の基本構造
CDK Pipelines を使うには aws-cdk-lib の pipelines サブモジュールをインポートする。最小構成は CodePipeline インスタンスの生成と ShellStep によるビルドステップ定義から始まる。
import * as cdk from 'aws-cdk-lib';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import { Construct } from 'constructs';
export class MyPipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const pipeline = new CodePipeline(this, 'Pipeline', {
pipelineName: 'MyServicePipeline',
synth: new ShellStep('Synth', {
input: CodePipelineSource.gitHub('my-org/my-repo', 'main', {
authentication: cdk.SecretValue.secretsManager('github-token'),
}),
commands: [
'npm ci',
'npm run build',
'npx cdk synth',
],
}),
});
}
}
このコードが CodePipeline の Source ステージ + Synth ステージを自動生成する。CodePipelineSource.gitHub() は GitHub 連携、ShellStep は任意のシェルコマンドを実行するステップを表す。
3.2 Pipeline 定義の3要素 — ShellStep / CodeBuildStep / ManualApprovalStep
CDK Pipelines には用途に応じた3種類のステップクラスがある。
ShellStep — 軽量シェルコマンドを実行するデフォルトステップ。追加設定なしで CodeBuild が起動する。
new ShellStep('UnitTest', {
commands: [
'npm ci',
'npm test',
],
primaryOutputDirectory: 'coverage',
})
CodeBuildStep — 専用 CodeBuild プロジェクトでビルドを実行するステップ。カスタムビルド環境 (Docker イメージ / インスタンスサイズ / VPC 配置) が必要な場合に使う。
import { CodeBuildStep } from 'aws-cdk-lib/pipelines';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
const integTest = new CodeBuildStep('IntegTest', {
commands: ['npm run integ-test'],
buildEnvironment: {
buildImage: codebuild.LinuxBuildImage.STANDARD_7_0,
computeType: codebuild.ComputeType.LARGE,
},
vpc: myVpc,
subnetSelection: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
});
ManualApprovalStep — 人手承認ゲート。本番デプロイ前に承認者が CodePipeline コンソールで承認/却下するまで Pipeline を停止する。
import { ManualApprovalStep } from 'aws-cdk-lib/pipelines';
const prdApproval = new ManualApprovalStep('ApprovePrd', {
comment: '本番デプロイを承認してください。変更内容を確認後に承認してください。',
});
3.3 Wave / Stage / Step 階層モデル — 並列実行と依存関係
CDK Pipelines の実行モデルは Wave → Stage → Step の3階層で構成される。
Pipeline
└── Wave (並列実行グループ)
├── Stage (環境単位: Dev / Stg / Prd)
│├── Pre-step (デプロイ前の検証)
│├── Stack Deploy (CloudFormation デプロイ)
│└── Post-step (デプロイ後の検証)
└── Stage (同一 Wave 内は並列)
├── Pre-step
├── Stack Deploy
└── Post-step
Wave は複数の Stage を並列実行するグループ単位。同一 Wave に含まれる Stage は依存関係なく同時に進行する。
// Wave で東京・大阪リージョンに並列デプロイ
const devWave = pipeline.addWave('DevWave');
devWave.addStage(new MyAppStage(this, 'DevTokyo', {
env: { account: '111111111111', region: 'ap-northeast-1' },
}));
devWave.addStage(new MyAppStage(this, 'DevOsaka', {
env: { account: '111111111111', region: 'ap-northeast-3' },
}));
// Stg は Dev Wave 完了後に直列で実行
pipeline.addStage(new MyAppStage(this, 'Stg', {
env: { account: '222222222222', region: 'ap-northeast-1' },
}));
Step 間の依存関係 は addStepDependency() で明示する。依存するステップが完了するまで後続ステップは開始されない。
const unitTest = new ShellStep('UnitTest', { commands: ['npm test'] });
const integTest = new CodeBuildStep('IntegTest', { commands: ['npm run integ'] });
integTest.addStepDependency(unitTest);
3.4 ApplicationStage 設計 — pre/post hooks と Stack output 連携
cdk.Stage を継承したクラスで環境ごとのデプロイ単位を定義する。Stack 間の依存関係や出力値の公開もここで管理する。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class MyAppStage extends cdk.Stage {
readonly appUrl: cdk.CfnOutput;
constructor(scope: Construct, id: string, props?: cdk.StageProps) {
super(scope, id, props);
const dbStack = new DatabaseStack(this, 'DatabaseStack', props);
const apiStack = new ApiStack(this, 'ApiStack', props);
// Stack 間依存: dbStack が先にデプロイされる
apiStack.addDependency(dbStack);
// Stack output を Pipeline ステップに公開
this.appUrl = apiStack.appUrl;
}
}
addStage() の pre / post オプションでデプロイの前後にステップを挿入できる。Stack output を後続ステップで使うには envFromCfnOutputs を指定する。
const stgStage = new MyAppStage(this, 'Stg', {
env: { account: '222222222222', region: 'ap-northeast-1' },
});
pipeline.addStage(stgStage, {
pre: [
new ShellStep('Lint', { commands: ['npm run lint'] }),
],
post: [
new ShellStep('SmokeTest', {
commands: ['curl -f "${APP_URL}/health"'],
envFromCfnOutputs: {
APP_URL: stgStage.appUrl,
},
}),
],
});

鉄則1 — Wave/Stage で環境を階層化する: Wave は並列、addStage は直列。同一リージョン複数アカウントへの並列デプロイには Wave を使い、Dev → Stg → Prd の昇格には addStage を直列に並べる。Wave 内 Stage の失敗は同一 Wave の他 Stage に影響しないため、フェイルファスト設計になる。
鉄則2 — Self-mutating を前提に設計する: pipeline.buildPipeline() を呼び出す前にすべての Stage/Step を定義すること。buildPipeline() 以降に Stage を追加しても次の Self-mutating サイクルまで反映されない。初回デプロイ時は cdk deploy PipelineStack を手動で実行し、以降は push だけで自動更新される。
鉄則3 — Manual approval は pre フックに配置する: post フックに approval を置くとデプロイ後に待機が発生し、ロールバック判断が困難になる。承認は必ずデプロイ前 (pre) に配置し、承認後にデプロイが実行される流れを維持する。
3.5 Self-mutating の仕組み — buildPipeline() と自動更新メカニズム
CDK Pipelines の最大の特徴が Self-mutating だ。Pipeline 定義を変更してコードを push すると、Pipeline 自体が自動的に更新される。
Self-mutating サイクル:
1. 開発者が Pipeline 定義 (CDK コード) を変更して push
2. Source ステージが変更を検知して Pipeline が起動
3. Synth ステージが「cdk synth」を実行して CloudFormation テンプレートを生成
4. UpdatePipeline ステージが Pipeline スタックの diff を計算
5. 差分があれば Pipeline 自身を CloudFormation でアップデート (Self-mutate)
6. Pipeline が再起動し、更新後の定義で全 Stage を実行
selfMutation: true がデフォルト値。明示的に無効化する場合は selfMutation: false を指定する。
const pipeline = new CodePipeline(this, 'Pipeline', {
pipelineName: 'MyServicePipeline',
selfMutation: true, // デフォルト true
crossAccountKeys: true, // Cross-account KMS キーを自動生成
synth: new ShellStep('Synth', {
input: CodePipelineSource.gitHub('my-org/my-repo', 'main', {
authentication: cdk.SecretValue.secretsManager('github-oauth-token'),
}),
commands: [
'npm ci',
'npm run build',
'npx cdk synth',
],
primaryOutputDirectory: 'cdk.out',
}),
});
// すべての Stage を定義 (buildPipeline() 前に完了させる)
pipeline.addStage(new MyAppStage(this, 'Dev', {
env: { account: '222222222222', region: 'ap-northeast-1' },
}));
pipeline.addStage(new MyAppStage(this, 'Prd', {
env: { account: '333333333333', region: 'ap-northeast-1' },
}));
selfMutation: false を選ぶケース: Pipeline の安定性優先でコード変更が Stage 構成に影響しない場合、または Pipeline の変更を意図的に手動で管理したい場合に限定する。
3.6 Cross-account deploy — CDK bootstrap × IAM role × KMS key policy
CDK Pipelines で複数アカウントにデプロイするには、各アカウントで cdk bootstrap を実行し Pipeline アカウントを trust する必要がある。
ステップ1: Pipeline アカウント (CI/CD 専用アカウント) で bootstrap
cdk bootstrap aws://111111111111/ap-northeast-1 \
--profile pipeline-account-profile
ステップ2: デプロイ先アカウントで bootstrap –trust
# Dev アカウント: Pipeline アカウントを trust
cdk bootstrap aws://222222222222/ap-northeast-1 \
--trust 111111111111 \
--trust-for-lookup 111111111111 \
--cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \
--profile dev-account-profile
# Prd アカウント: 同様に trust
cdk bootstrap aws://333333333333/ap-northeast-1 \
--trust 111111111111 \
--trust-for-lookup 111111111111 \
--cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \
--profile prd-account-profile
CDK bootstrap が生成する IAM ロール構成:
Pipeline アカウント (111111111111)
└── CodePipeline 実行ロール
└── AssumeRole → デプロイ先アカウントの DeploymentRole
Dev/Prd アカウント (222222222222 / 333333333333)
├── cdk-hnb659fds-deploy-role (CloudFormation ChangeSet 作成・実行)
├── cdk-hnb659fds-cfn-exec-role(CloudFormation 実行時ロール)
├── cdk-hnb659fds-lookup-role (CDK synth 時の値参照)
└── cdk-hnb659fds-image-publishing-role (ECR イメージ publish)
KMS key policy は CDK bootstrap が --trust したアカウントに対して自動付与するため手動設定は不要だ。crossAccountKeys: true を Pipeline に指定することで Artifact バケットの暗号化キーがクロスアカウントアクセスに対応する。
// CDK コードで Cross-account Stage を追加
pipeline.addStage(new MyAppStage(this, 'Prd', {
env: {
account: '333333333333',
region: 'ap-northeast-1',
},
}), {
pre: [
new ManualApprovalStep('ApprovePrdDeploy', {
comment: '本番デプロイ承認: Stg での動作確認後に承認してください',
}),
],
});
3.7 Manual approval ゲート — ManualApprovalStep × SNS 通知 × timeout
SNS Topic と組み合わせることで承認依頼をメール通知できる。
import * as sns from 'aws-cdk-lib/aws-sns';
import * as subscriptions from 'aws-cdk-lib/aws-sns-subscriptions';
const approvalTopic = new sns.Topic(this, 'PrdApprovalTopic', {
displayName: 'Production Deployment Approval',
});
approvalTopic.addSubscription(
new subscriptions.EmailSubscription('ops-team@example.com')
);
// addStage の pre フックに配置
pipeline.addStage(new MyAppStage(this, 'Prd', {
env: { account: '333333333333', region: 'ap-northeast-1' },
}), {
pre: [
new ManualApprovalStep('ApprovePrd', {
comment: '本番デプロイを承認してください',
}),
],
});
timeout の注意点: CodePipeline の Manual approval アクションはデフォルトで7日間待機する。7日以内に承認/却下されない場合は自動的に失敗扱いとなり Pipeline が停止する。CDK Pipelines では approval の timeout を直接指定できないため、SNS 通知やアラームで期限前に承認者に再通知する運用フローを整備しておくこと。
3.8 完全な Pipeline 定義例 — Dev → Stg → Prd 三環境昇格
export class FullPipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const source = CodePipelineSource.gitHub('my-org/my-service', 'main', {
authentication: cdk.SecretValue.secretsManager('github-oauth-token'),
});
const pipeline = new CodePipeline(this, 'ServicePipeline', {
pipelineName: 'MyServiceDeliveryPipeline',
selfMutation: true,
crossAccountKeys: true,
synth: new ShellStep('Synth', {
input: source,
commands: [
'npm ci',
'npm run build',
'npm test',
'npx cdk synth',
],
primaryOutputDirectory: 'cdk.out',
}),
});
// Dev Wave: 東京・大阪 並列デプロイ
const devWave = pipeline.addWave('DevWave');
const devStage = new MyAppStage(this, 'Dev', {
env: { account: '222222222222', region: 'ap-northeast-1' },
});
devWave.addStage(devStage, {
post: [
new CodeBuildStep('DevIntegTest', {
commands: ['npm run integ -- --env dev'],
envFromCfnOutputs: { APP_URL: devStage.appUrl },
}),
],
});
// Stg: Dev 完了後に直列実行
const stgStage = new MyAppStage(this, 'Stg', {
env: { account: '222222222222', region: 'ap-northeast-1' },
});
pipeline.addStage(stgStage, {
post: [
new ShellStep('StgSmokeTest', {
commands: ['curl -f "${APP_URL}/health"'],
envFromCfnOutputs: { APP_URL: stgStage.appUrl },
}),
],
});
// Prd: Manual approval + Cross-account
const prdStage = new MyAppStage(this, 'Prd', {
env: { account: '333333333333', region: 'ap-northeast-1' },
});
pipeline.addStage(prdStage, {
pre: [
new ManualApprovalStep('ApprovePrdDeploy', {
comment: '本番デプロイ承認: Stg 動作確認後に承認してください',
}),
],
post: [
new ShellStep('PrdSmokeTest', {
commands: ['curl -f "${APP_URL}/health"'],
envFromCfnOutputs: { APP_URL: prdStage.appUrl },
}),
],
});
}
}
crossAccountKeys: true を指定すると CDK Pipelines が KMS カスタムキーを自動生成し、クロスアカウント Artifact 転送を暗号化する。初回は cdk deploy FullPipelineStack を手動実行し、以降は push だけで Self-mutating が自動的に Pipeline を更新する。
推奨する場面
- インフラとアプリケーションを同じ CDK コードベースで管理している
- 複数アカウント・複数リージョンへの一貫したデプロイが必要
- Pipeline 定義自体をバージョン管理・コードレビューしたい
- Dev → Stg → Prd の環境昇格ロジックを Wave/Stage で標準化したい
- Self-mutating により Pipeline 更新を自動化したい
推奨しない場面
- CDK を使用していない (Terraform / CloudFormation 手書き) プロジェクト
- Pipeline のカスタムアクションタイプが必要 (CDK Pipelines は CodePipeline 標準アクションに限定)
- 既存 Console 作成 Pipeline を段階移行中 (移行完了後に採用を推奨)
- CDK バージョンロック要件が厳しく cdk-pipelines ライブラリの更新追跡が困難
Phase 1 — 並行稼働: 既存の Console 作成 Pipeline を残したまま CDK Pipelines を別名で新規作成する。両 Pipeline が同じリポジトリを参照して問題ないことを確認する。
Phase 2 — CDK Pipelines での本番デプロイ確認: CDK Pipelines 経由で Dev/Stg にデプロイし動作を確認する。本番昇格は Manual approval で制御する。
Phase 3 — 旧 Pipeline の無効化: CDK Pipelines が安定稼働したことを確認後、旧 Pipeline のトリガーを Disabled 状態にする。削除はすぐ行わず1〜2週間様子を見る。
Phase 4 — 旧 Pipeline の削除: 旧 Pipeline が不要と確認できたら CloudFormation スタックを削除する。CDK Pipelines は独自スタックで管理されるため旧スタックと競合しない。
§4 では CDK Pipelines と連携する GitHub Actions / CodeBuild ハイブリッド構成と OIDC 連携による静的 IAM キーレス運用を解説する。
§4 GitOps 連携本番運用 — CodeBuild × GitHub Actions hybrid × OIDC × Reusable workflow
4-1 GitOps の本質 — Git を Single Source of Truth にする
GitOps は「インフラの宣言的定義を Git で管理し、Git への変更を唯一のデプロイトリガーにする」設計哲学だ。
従来の CLI 手動操作や Console クリックは GitOps の対極にある。GitOps が解決する問題は3つある。
| 課題 | 従来手法の問題 | GitOps の解 |
|---|---|---|
| ドリフト (実環境と定義の乖離) | 手動操作が追跡不能 | Git 差分が唯一の変更証跡 |
| 変更履歴の欠落 | 誰がいつ何を変えたか不明 | PR → review → merge → deploy で全追跡 |
| ロールバック困難 | 以前の状態への復元が手動 | git revert → 自動 pipeline で即回帰 |
Reconciliation loop とは、Git の desired state と実環境の actual state を常に突き合わせるループだ。
CodePipeline + CDK Pipelines の組み合わせでは、CDK Synth → cdk deploy が Reconciliation の役割を担う。
CDK Pipelines の Self-mutating 機能と組み合わせると、Git push だけで pipeline 定義から環境まで全て更新される。
宣言的インフラの3原則:
- バージョン管理 — Terraform / CDK コードは Git に集約。手動変更は即ドリフト扱い
- 自動適用 — merge イベントが deploy の唯一トリガー。人手の「デプロイ実行」は不要
- 監査可能性 — 全変更が PR コメント・commit log・pipeline 実行ログで追跡可能
4-2 CodeBuild × GitHub Actions hybrid 設計
AWS ネイティブ作業には CodeBuild、ユニットテストや汎用 CI には GitHub Actions — この分担が hybrid の核心だ。
分担の根拠
| 役割 | 推奨ツール | 理由 |
|---|---|---|
| AWS リソース deploy (CDK / Terraform) | CodeBuild | IAM Role / VPC 内アクセス / AWS CLI が自然 |
| ユニットテスト / リント / Docker build | GitHub Actions | マーケットプレイス Action / caching / matrix build |
| Pull Request チェック | GitHub Actions | PR status check に GitHub が直接統合 |
| 本番 deploy gate / Manual approval | CodePipeline | Stage 制御 / SNS 承認フロー |
| E2E テスト (AWS リソース参照) | CodeBuild | VPC 内 endpoint / IAM Role が必要な場合 |
Trigger 設計: PR → GitHub Actions (test/lint) → main merge → CodePipeline (deploy) の順序が基本だ。
CodePipeline の source trigger を GitHub Events に設定し、main branch への push のみ deploy を起動する。
テストと deploy の責務が分離するため、GitHub Actions 側は AWS 権限不要でシンプルに保てる。
# .github/workflows/ci.yml — GitHub Actions 担当 (test / lint)
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npm test
- run: npm run lint
main merge 後は CodePipeline が自動起動し、CDK Pipelines が deploy を担う。
4-3 OIDC連携 — GitHub Actions → AWS assume role
OIDC (OpenID Connect) 連携により、GitHub Actions は静的な IAM Access Key を持たずに AWS にアクセスできる。
IAM Identity Provider を AWS に登録し、GitHub の JWT トークンを AWS STS でアサンプションする仕組みだ。
OIDC の仕組み
GitHub Actions job 起動
↓
GitHub が OIDC JWT トークンを発行
(subject: repo:owner/repo:ref:refs/heads/main)
↓
aws-actions/configure-aws-credentials が
STS AssumeRoleWithWebIdentity を呼び出し
↓
IAM Identity Provider が JWT 署名を
token.actions.githubusercontent.com で検証
↓
trust policy の条件 (sub / aud) を評価
→ 一致すれば Temporary Credentials を発行
↓
GitHub Actions が AWS CLI / SDK を使用可能に
Terraform: IAM Identity Provider + Role 設定
# terraform/github_oidc.tf
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
resource "aws_iam_role" "github_actions" {
name = "github-actions-deploy-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.github.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
# repo + branch 両方を制限 — sub の厳格化が最重要
"token.actions.githubusercontent.com:sub" =
"repo:myorg/myrepo:ref:refs/heads/main"
}
}
}]
})
}
resource "aws_iam_role_policy" "github_actions_deploy" {
name = "github-actions-deploy-policy"
role = aws_iam_role.github_actions.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:GetObject",
"s3:PutObject",
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage"
]
Resource = "*"
}
]
})
}
trust policy の sub claim 厳格化 が最重要ポイントだ。StringLike で repo:myorg/myrepo:* と書いた場合、fork したリポジトリからもアクセス可能になる危険性がある。
本番では ref:refs/heads/main まで固定し、PR ブランチからの deploy 権限取得を防ぐ。
OIDC vs Access Key 比較
| 比較項目 | 静的 Access Key | OIDC |
|---|---|---|
| 認証情報の管理 | Secrets に保存・手動ローテーション | 不要 (一時 Token が自動発行) |
| 漏洩リスク | Secrets 漏洩で長期間悪用可能 | Token は 1 時間で失効 |
| 監査ログ | CloudTrail に AccessKeyId のみ | WorkflowRef / subject が残る |
| 設定コスト | 低 (即日設定可) | 中 (OIDC Provider 設定が必要) |
| 推奨 | 非推奨 (緊急時のみ) | 本番必須 |
4-4 Reusable workflow — .github/workflows/called.yml
Reusable workflow は GitHub Actions の「関数」にあたる機能で、複数リポジトリ・複数 job から同一の workflow を呼び出せる。
マイクロサービス構成では、各サービスリポジトリが中央の CI workflow を再利用する設計が一般的だ。
Reusable workflow の基本構造
# .github/workflows/called.yml — 呼び出される側 (中央リポジトリ)
name: Reusable Deploy Workflow
on:
workflow_call:
inputs:
environment:
description: "Deploy target (dev/stg/prd)"
required: true
type: string
image_tag:
required: true
type: string
secrets:
AWS_ROLE_ARN:
required: true
outputs:
deploy_url:
description: "Deployed endpoint URL"
value: ${{ jobs.deploy.outputs.url }}
jobs:
deploy:
runs-on: ubuntu-latest
outputs:
url: ${{ steps.deploy.outputs.endpoint }}
permissions:
id-token: write# OIDC トークン取得に必須
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- name: Deploy to ECS
id: deploy
run: |
aws ecs update-service \
--cluster my-cluster \
--service my-service-${{ inputs.environment }} \
--force-new-deployment
echo "endpoint=https://api-${{ inputs.environment }}.example.com" \
>> $GITHUB_OUTPUT
# .github/workflows/caller.yml — 呼び出す側 (各サービスリポジトリ)
name: Deploy
on:
push:
branches: [main]
jobs:
deploy-dev:
uses: myorg/central-workflows/.github/workflows/called.yml@main
with:
environment: dev
image_tag: ${{ github.sha }}
secrets:
AWS_ROLE_ARN: ${{ secrets.AWS_DEV_ROLE_ARN }}
deploy-stg:
needs: deploy-dev
uses: myorg/central-workflows/.github/workflows/called.yml@main
with:
environment: stg
image_tag: ${{ github.sha }}
secrets:
AWS_ROLE_ARN: ${{ secrets.AWS_STG_ROLE_ARN }}
permissions: id-token: write は OIDC トークン取得に必須だ。
Reusable workflow 側で明示的に付与しないと、呼び出し元が id-token: write を持っていても継承されない。workflow_call で呼び出された job は呼び出し元の permissions を自動継承しない点に注意する。
4-5 Pull Request フロー本番設計
PR trigger → Actions test → CodeBuild deploy の3段構成が GitOps の標準フローだ。
Developer: feature branch で開発
↓ git push → PR オープン
GitHub Actions: ci.yml が自動起動
- unit test / lint / type check
- PR status check に結果反映
↓ review + approve
Merge to main
↓ main push event
CodePipeline: source stage が起動
↓
CodeBuild: cdk synth (CDK Pipelines の Synth step)
↓
Self-mutating: pipeline 定義を更新
↓
Deploy stage: CDK deploy (dev → stg → prd)
Branch protection rules 設定 (GitHub リポジトリ設定):
Require status checks to pass before merging— CI job を必須化し、失敗時の merge をブロックRequire branches to be up to date— outdated branch からの merge を防止Require pull request reviews before merging— 最低1名レビュー必須Restrict who can push to matching branches— main への直 push を管理者のみに制限
これら4つのルールを全て有効化することで、「全変更がレビュー済み CI 通過コードのみが本番に届く」という GitOps の理想状態が実現する。
キャッシュ戦略: GitHub Actions は actions/cache で依存関係をキャッシュし、CodeBuild は S3 キャッシュを使う。
両者を混在させる hybrid 構成では、それぞれのキャッシュが独立しており共有されない点を理解しておく必要がある。

鉄則1 — sub claim は repo + branch まで厳格に絞るStringLike: "repo:myorg/myrepo:ref:refs/heads/main" — ワイルドカードで全ブランチを許可すると fork PR からの悪用が可能になる。PR ブランチからの assume role は許可しないのが原則だ。
鉄則2 — permissions: id-token: write を called.yml 側に明示する
workflow_call 経由でも id-token: write は自動継承されない。called.yml 側で明示的に宣言が必要だ。
鉄則3 — キャッシュに機密データを含めない
actions/cache はリポジトリ内の全 PR からアクセス可能。node_modules / pip packages のみキャッシュし、認証情報は除外する。
□ OIDC 必須 — 静的 Access Key は使用しない
□ IAM ポリシー最小権限 — deploy に必要な Action のみ許可 (S3/ECR/ECS 等を個別指定)
□ シークレット管理 — GitHub Secrets に認証情報を格納し、コードに直書きしない
□ Branch protection — main への直 push を禁止し PR 必須化
□ sub claim 厳格化 — fork PR からの権限取得を StringLike で防止
□ Reusable workflow 版管理 — @main でなく @v1.2.3 タグ参照を推奨
□ CloudTrail 確認 — GitHub Actions からの AssumeRole 履歴を定期的に監査
§5 では Self-mutating pipelines の仕組みを深掘りし、CDK が自身の pipeline 定義を自動更新するメカニズムと Cross-account deploy を解説する。
§5 Self-mutating pipelines 本番運用 — CDK self-update × Pipeline drift × Cross-account deploy ★山場2
5-1 Self-mutating の仕組み — CDK Pipelines が自分自身を更新する
Self-mutating とは「CDK Pipelines が Git push のたびに自身の pipeline 定義を CDK Synth し直し、変更があれば pipeline を更新してから実際の deploy を行う」仕組みだ。
これにより pipeline の定義変更も通常の Git push → merge で反映される。手動での pipeline 再作成は不要になる。
pipeline.buildPipeline() を呼ぶと CDK は CloudFormation テンプレートを生成し CodePipeline リソースを作成する。以降の定義変更は Git を通して自動反映される。
// lib/pipeline-stack.ts
import * as cdk from "aws-cdk-lib";
import { CodePipeline, CodePipelineSource, ShellStep } from "aws-cdk-lib/pipelines";
import { Construct } from "constructs";
export class PipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const pipeline = new CodePipeline(this, "Pipeline", {
selfMutation: true, // デフォルト true — 明示する
crossAccountKeys: true,// Cross-account deploy に必須
synth: new ShellStep("Synth", {
input: CodePipelineSource.gitHub("myorg/myrepo", "main", {
authentication: cdk.SecretValue.secretsManager("github-token"),
}),
commands: ["npm ci", "npm run build", "npx cdk synth"],
}),
});
// Stage を追加
pipeline.addStage(new AppStage(this, "Dev", {
env: { account: "222222222222", region: "ap-northeast-1" },
}));
}
}
5-2 初回 cdk deploy — Bootstrap から Pipeline 作成まで
Self-mutating pipeline は初回だけ手動で cdk deploy を実行し、以降は Git push で全て自動化される。
初回セットアップ手順:
# Step 1: CDK bootstrap (各アカウント × リージョンで一度だけ)
# Pipeline アカウント (ツールアカウント)
cdk bootstrap aws://111111111111/ap-northeast-1 \
--profile pipeline-account
# Dev アカウント (Cross-account deploy 先)
cdk bootstrap aws://222222222222/ap-northeast-1 \
--profile dev-account \
--trust 111111111111 \
--cloudformation-execution-policies \
arn:aws:iam::aws:policy/AdministratorAccess
# Prd アカウント
cdk bootstrap aws://333333333333/ap-northeast-1 \
--profile prd-account \
--trust 111111111111 \
--cloudformation-execution-policies \
arn:aws:iam::aws:policy/AdministratorAccess
# Step 2: 初回 deploy — Pipeline stack を作成
cdk deploy PipelineStack --profile pipeline-account
# Step 3: 以降は Git push だけで自動更新
git add . && git commit -m "feat: add new stage" && git push
--trust 111111111111 が Cross-account bootstrap の核心だ。
このオプションにより、Dev/Prd アカウントは Pipeline アカウントからの CloudFormation 実行を信頼する IAM Role を自動作成する。
5-3 Self-mutating サイクル — コード変更から Pipeline 自動更新まで
1. 開発者: CDK コードを変更 → main branch に push
↓
2. CodePipeline: Source stage が起動 (GitHub から取得)
↓
3. Synth step: CodeBuild で "npx cdk synth" を実行
↓
4. Self-Mutate step: 生成された CloudFormation テンプレートと
現在の Pipeline を比較 → 差分があれば CloudFormation で自動更新
↓
5. Pipeline 再起動: 更新された Pipeline が新しい定義で再実行
↓
6. Deploy step: 実際のアプリケーションを各環境にデプロイ
重要: Self-Mutate step は CDK Pipelines が自動で追加する特別なステップだ。cdk synth の出力 (CloudFormation テンプレート) を S3 に保存し、現在の Pipeline スタックと diff を取り、変更時のみ CloudFormation update を実行する。
5-4 Pipeline drift 検知 — 実環境と CDK 定義の乖離
drift とは、Console や CLI で手動変更した Pipeline 定義が CDK の定義と乖離した状態だ。
CDK Pipelines + Self-mutating の環境では、次の Git push 時に Self-Mutate step が drift を検知し自動修正する。
drift 修正フロー:
# drift の確認 (CloudFormation 機能)
aws cloudformation detect-stack-drift \
--stack-name PipelineStack
aws cloudformation describe-stack-drift-detection-status \
--stack-drift-detection-id <detection-id>
# drift の解消: CDK 再 deploy で CDK 定義を正とする
cdk deploy PipelineStack --profile pipeline-account
# または Git push で Self-mutating に任せる
git commit --allow-empty -m "chore: trigger pipeline refresh"
git push
Console 手動変更が危険な理由: Console で Stage を追加・削除した場合、次の CDK Synth で元の状態に戻される。
変更は必ず CDK コードで行い、Git push → Self-mutating で反映させる。これが GitOps の本質だ。
5-5 Cross-account deploy — 環境ごとのアカウント分離
本番運用では Dev / Stg / Prd を別々の AWS アカウントに分離する。
これにより Prd へのアクセス権限を絞り込め、誤操作の影響範囲を限定できる。
アカウント構成:
| アカウント | 役割 | 保有リソース |
|---|---|---|
| Pipeline アカウント (111) | ツール集中 | CodePipeline / CodeBuild / Artifact S3 |
| Dev アカウント (222) | 開発環境 | アプリ Dev 環境一式 |
| Stg アカウント (333) | ステージング | アプリ Stg 環境一式 |
| Prd アカウント (444) | 本番環境 | アプリ Prd 環境一式 + 厳格な IAM |
Cross-account deploy の TypeScript 設定:
// lib/pipeline-stack.ts — Cross-account Stage 設定
import { ManualApprovalStep, ShellStep } from "aws-cdk-lib/pipelines";
// Dev 環境 (自動デプロイ)
pipeline.addStage(new AppStage(this, "Dev", {
env: { account: "222222222222", region: "ap-northeast-1" },
}));
// Stg 環境 (自動デプロイ + smoke test)
const stgStage = new AppStage(this, "Stg", {
env: { account: "333333333333", region: "ap-northeast-1" },
});
pipeline.addStage(stgStage, {
post: [
new ShellStep("StgSmokeTest", {
commands: ["curl -f ${APP_URL}/health"],
envFromCfnOutputs: { APP_URL: stgStage.appUrl },
}),
],
});
// Prd 環境 (Manual approval + Cross-account)
pipeline.addStage(new AppStage(this, "Prd", {
env: { account: "444444444444", region: "ap-northeast-1" },
}), {
pre: [
new ManualApprovalStep("PromoteToPrd", {
comment: "Stg 動作確認後に承認してください",
}),
],
});
crossAccountKeys: true を設定すると CDK Pipelines は KMS CMK を自動作成する。
この KMS Key が Cross-account アカウントからの Artifact 復号を許可する Key Policy を持つ。
自動作成される IAM ロールの連鎖:
Pipeline アカウント (111) CodePipeline
↓ AssumeRole
Pipeline アカウント (111) CodeBuild Service Role
↓ AssumeRole (Cross-account)
Dev アカウント (222) cdk-hnb659fds-deploy-role-222-ap-northeast-1
↓ CloudFormation Execution Role
Dev アカウント (222) cdk-hnb659fds-cfn-exec-role-222-ap-northeast-1
↓ CloudFormation が実行
Dev アカウント (222) アプリリソース
5-6 Rollback 戦略 — Stage / CloudFormation / 手動
rollbackOnFailure 設定 (CDK Pipelines):
pipeline.addStage(new AppStage(this, "Prd", {
env: { account: "444444444444", region: "ap-northeast-1" },
}), {
rollbackOnFailure: true,
// deploy 失敗時に Stage 内全 Stack を rollback
});
CloudFormation 自動ロールバック: Stack 更新失敗時はデフォルトで前の状態に自動ロールバックする。
ただし DisableRollback: true が設定されている Stack や、ロールバック自体が失敗した場合は手動介入が必要だ。
手動ロールバック手順:
# Option 1: git revert → push (推奨 — GitOps に沿った方法)
git revert HEAD
git push
# Option 2: CloudFormation から手動 rollback
aws cloudformation rollback-stack --stack-name AppStack-Prd
# Option 3: 特定バージョンのテンプレートに戻す
aws cloudformation update-stack \
--stack-name AppStack-Prd \
--template-url s3://cdk-artifact-bucket/previous-template.json \
--capabilities CAPABILITY_IAM

□ cdk bootstrap –trust を全 target アカウントで実行済み
□ crossAccountKeys: true を PipelineStack で設定済み (KMS Key 自動生成)
□ target アカウントの cdk-hnb659fds-deploy-role が存在する (bootstrap 成功の証拠)
□ Prd Stage に ManualApprovalStep を追加済み
□ CloudFormation Execution Role が十分な権限を持つ
□ S3 Artifact Bucket の Bucket Policy が target アカウントの GetObject を許可済み
□ KMS Key Policy が target アカウントの Decrypt を許可済み
ミス1 — selfMutation: false のまま本番運用
CDK Pipeline の定義変更が Git push で自動反映されない。Pipeline を手動で再作成するたびにドリフトが発生する。対策: selfMutation: true (デフォルト) を明示確認し、意図せず false にしていないか確認する。
ミス2 — crossAccountKeys を false のまま Cross-account deploy
Artifact S3 バケットがデフォルトの AWS マネージドキーで暗号化され、Cross-account アカウントが Artifact を復号できない (AccessDenied エラー)。対策: crossAccountKeys: true を PipelineStack に必ず設定する。
ミス3 — Pipeline drift を放置
Console で Stage を追加・削除した場合、次の Git push の Self-Mutate step が元の CDK 定義に戻す。Console 変更が「なぜか戻る」と混乱する原因。対策: 全変更は CDK コードで行い、Console 手動変更は禁止ルールを徹底する。
5-7. Self-mutating 運用ベストプラクティス 5選
Self-mutating CDK Pipelines を本番で安定運用するための実践指針を5つにまとめる。これらは複数の本番運用事例を踏まえた経験則であり、Pipeline as Code の長期運用を成功させる勘所となる。
1. cdk diff を CI に必須化: Pipeline 定義を変更する PR では
cdk diff を必ず CI で実行し、レビュアーが Pipeline 構造の変更影響を視覚的に把握できるようにする。Self-mutating で Pipeline 自身が書き換わるため、merge 後の影響範囲を事前確認することが重要。2. Console 手動変更を完全禁止: Pipeline / Stage / Action を Console で変更すると、次の Self-Mutate サイクルで CDK 定義に上書きされる。チームルールとして「Pipeline 変更は CDK コードのみ」を徹底し、Console 操作権限から ReadOnly 以上を剥奪する。
3. Drift detection を Schedule で自動化: CloudFormation Drift Detection を週次でスケジュール実行し、想定外の変更を検知したら Slack/SNS で即時アラート。手動変更や API直接呼び出しによる drift を早期発見する。
4. Stack output cross-reference は最小化: Wave/Stage 間で Stack output を参照すると、変更時に依存 Stack も再デプロイが必要になる。Parameter Store / Secrets Manager 経由の遅延参照に切り替えることで、Stack 結合度を下げる。
5. 緊急時の break-glass 手順を整備: Self-mutating cycle が暴走した場合に備えて、(a) Source Stage を一時的に無効化、(b) Pipeline Stack を CDK destroy せず Console から手動停止、(c) S3 Artifact bucket への書き込みを deny する IAM ポリシーを事前準備しておく。
これら5つを徹底することで、Pipeline as Code の利便性を享受しつつ、運用上の予期せぬ事故を防止できる。特に「3. Drift detection」と「5. break-glass 手順」は本番投入前に必ず整備すること。
§6 では Self-mutating / Cross-account / OIDC 運用で頻発する詰まりポイント7選を体系化し、判断ツリーで即座に解決策を導けるようにする。
§6 詰まりポイント7選 図解
CodePipeline V2・CDK Pipelines・GitOps self-mutating を本番導入した際に高頻度で遭遇する障害を7パターンに分類する。各パターンは「症状→原因→解」の構造で解説し、末尾に Mermaid 判断ツリーを掲載する。
詰まり1: CodePipeline V2 Trigger 設定ミス — ブランチフィルタ未設定で全PR起動
症状: feature ブランチへの push で本番 Pipeline が起動する。開発中の不完全なコードが Staging/Production ステージまで流れ込む。
原因: V2 Trigger を追加したが branchesExcludes / filePathsIncludes を未設定。デフォルトではリポジトリ全イベントがトリガー対象になる。
解: Trigger に branches.includes: ["main"] を明示し、PR ブランチは除外する。CDK では以下のように設定する。
const pipeline = new CodePipeline(this, "Pipeline", {
pipelineName: "MyPipeline",
synth: new ShellStep("Synth", {
input: CodePipelineSource.gitHub("owner/repo", "main", {
trigger: GitHubTrigger.WEBHOOK,
}),
commands: ["npm ci", "npm run build", "npx cdk synth"],
}),
triggers: [
{
providerType: "CodeStarSourceConnection",
gitConfiguration: {
push: [
{
branches: { includes: ["main"] },
filePaths: { includes: ["src/**", "lib/**", "cdk.json"] },
},
],
},
},
],
});
branches.includes を明示。filePaths.includes でインフラ無関係ファイル(ドキュメント等)は除外し、不要起動を抑制する。詰まり2: CDK Pipelines Stack output cross-reference 失敗
症状: cdk synth は通るが、Pipeline 実行中に Stack X does not exist / Export Y cannot be deleted エラーが発生する。
原因: Stack 間で CfnOutput を参照する際、fromStackAttributes を使わず環境変数やハードコードで値を受け渡している。Stack 削除・再作成順序の不整合も発生する。
解: Stack 間依存は必ず CfnOutput + Fn.importValue で宣言的に管理する。
// NetworkStack — outputを定義
export class NetworkStack extends Stack {
public readonly vpcId: CfnOutput;
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
const vpc = new Vpc(this, "Vpc");
this.vpcId = new CfnOutput(this, "VpcId", {
value: vpc.vpcId,
exportName: `${this.stackName}-VpcId`,
});
}
}
// AppStack — importValueで参照
const vpcId = Fn.importValue(`${networkStack.stackName}-VpcId`);
CfnOutput.exportName + Fn.importValue を徹底。依存 Stack を先にデプロイする順序制御は CDK Stage で自動管理される。詰まり3: GitHub Actions → AWS OIDC trust policy 設定ミス
症状: GitHub Actions から aws sts assume-role-with-web-identity を実行すると AccessDenied が返る。ローカルでは IAM ユーザーキーで動作する。
原因: OIDC trust policy の StringEquals 条件が緩すぎる(repo 名のみ)か、StringLike を使い忘れ ref:refs/heads/main の形式が一致しない。
解: sub クレームの形式を CloudTrail で確認し、StringEquals + 完全一致で設定する。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:owner/repo:ref:refs/heads/main"
}
}
}
]
}
sub クレームは repo:owner/repo:ref:refs/heads/main の完全形式。PR トリガー時は pull_request イベントで sub が変わるため、環境別ロール + 条件分岐が必要。詰まり4: Self-mutating cycle — CDK 自身更新でループ
症状: CDK Pipelines を self-mutating 有効で初回 commit したところ、Pipeline が永続的に自己更新を繰り返し止まらない。
原因: selfMutation: true を設定したが、初回は cdk deploy を手動で実行していない。CDK Pipelines は初回手動デプロイで自身の CloudFormation Stack を作成する必要がある。また Pipeline 定義自体を頻繁に変更すると mutate → synth → mutate のサイクルに入る。
解: 初回は必ず cdk deploy PipelineStack を手動実行。その後は commit で self-mutating が機能する。
# 初回デプロイ (手動・一度だけ)
npx cdk bootstrap aws://123456789012/ap-northeast-1
npx cdk deploy PipelineStack
# 以降は git push main で self-mutating が自動実行
git add . && git commit -m "feat: update pipeline definition"
git push origin main
cdk deploy 手動実行。緊急ループ停止は AWS Console から Pipeline を選択し「Stop execution」→ 問題の commit を revert して再 push。詰まり5: Cross-account permission — KMS/S3 設定漏れ
症状: Cross-account Stage で CodeBuild が AccessDenied: KMS key または AccessDenied: s3:GetObject で失敗する。同一アカウントのステージは正常動作している。
原因: Pipeline Artifact Bucket の KMS キーポリシーに、デプロイ先アカウントの CodeBuild ロールが含まれていない。S3 バケットポリシーも同様。
解: KMS キーポリシーと S3 バケットポリシーにクロスアカウントの CodeBuild ロール ARN を明示的に追加する。
// Pipeline Stack — KMS key に cross-account grant を追加
const artifactKey = new Key(this, "ArtifactKey", {
enableKeyRotation: true,
});
// デプロイ先アカウントの CodeBuild ロールに grant
const crossAccountRole = Role.fromRoleArn(
this,
"CrossAccountRole",
`arn:aws:iam::${prodAccountId}:role/CodeBuildDeployRole`
);
artifactKey.grantDecrypt(crossAccountRole);
// S3 Bucket Policy に cross-account を許可
artifactBucket.addToResourcePolicy(
new PolicyStatement({
actions: ["s3:GetObject", "s3:PutObject"],
principals: [crossAccountRole],
resources: [artifactBucket.arnForObjects("*")],
})
);
cdk diff でポリシー差分を確認してからデプロイする。詰まり6: Variables resolution タイミング — Runtime/Compile time 混在
症状: CDK で定義した Pipeline Variables が CodeBuild 環境変数に渡らない。または ${variables.commitId} が文字列リテラルのまま実行される。
原因: CDK Pipelines の Variable は Pipeline 実行時(Runtime) に解決される。TypeScript の変数や cdk.Token は CDK synth 時(Compile time) に解決される。この二層を混同すると値が空になる。
解: Runtime 変数は pipeline.variable() で宣言し、参照時は variable.reference() を使う。
// Runtime Variable の宣言
const commitId = pipeline.addVariable(new Variable({
variableName: "COMMIT_ID",
description: "Git commit SHA from source stage",
}));
// CodeBuild ステップで Runtime Variable を参照
const deployStep = new CodeBuildStep("Deploy", {
commands: [
`echo "Deploying commit: $COMMIT_ID"`,
"npx cdk deploy AppStack",
],
env: {
// Runtime Variable は .reference() で渡す
COMMIT_ID: commitId.reference(),
},
});
VAR_ プレフィックスで統一し、CDK Token と視覚的に区別する。詰まり7: Manual approval timeout — 7 日制限 + SNS 通知未設定
症状: Manual Approval アクションを設定したが、承認者が気づかないまま 7 日経過し、Pipeline が自動的に失敗ステータスになる。再実行すると前のステージから再起動されコストが増大する。
原因: CodePipeline の Manual Approval はデフォルト 7 日でタイムアウトするが、SNS 通知を設定しないと誰にも通知が届かない。承認画面も直感的でなく見落とされやすい。
解: SNS Topic + Email/Slack 通知を必須化し、承認期限を externalEntityLink に明記する。
const approvalTopic = new Topic(this, "ApprovalTopic");
approvalTopic.addSubscription(new EmailSubscription("team@example.com"));
const approvalStage = pipeline.addStage(new ProdStage(this, "Prod"), {
pre: [
new ManualApprovalStep("ApproveProduction", {
comment: "本番デプロイを承認してください。期限: 5日以内",
externalEntityLink: "https://wiki.example.com/deploy-runbook",
}),
],
});
// Pipeline の SNS 通知を有効化
pipeline.pipeline.notifyOn("ApprovalNotification", approvalTopic, {
events: [PipelineNotificationEvents.MANUAL_APPROVAL_NEEDED],
});
externalEntityLink に設定することで承認者が即座に判断できる状態を作る。詰まりポイント7選 判断ツリー
flowchart TD
A[Pipeline問題発生] --> B{V2 Trigger誤動作?}
B -->|Yes| C[ブランチフィルタ設定確認]
B -->|No| D{CDK stack依存失敗?}
D -->|Yes| E[CfnOutput/cross-reference確認]
D -->|No| F{OIDC assume role失敗?}
F -->|Yes| G[trust policy条件キー確認]
F -->|No| H{Self-mutating cycle?}
H -->|Yes| I[初回cdk deploy手順確認]
H -->|No| J{Cross-account権限エラー?}
J -->|Yes| K[KMS/S3 cross-account policy確認]
J -->|No| L{Variables解決失敗?}
L -->|Yes| M[namespace/runtime変数分離]
L -->|No| N[Manual approval timeout確認]
① V2 Trigger: branches.includes 明示 / ② Stack output: CfnOutput + Fn.importValue / ③ OIDC: sub クレーム完全一致 / ④ Self-mutating: 初回は cdk deploy 手動 / ⑤ Cross-account: KMS + S3 + IAM 三点セット / ⑥ Variables: Runtime/Compile time 分離 / ⑦ Approval: SNS 通知 + 期限明記
§7 アンチパターン → 正解パターン変換演習
実際の現場で散見される誤った実装パターンを5問取り上げ、正解パターンとの差分を明示する。各問の構造は「状況説明 → アンチパターン → 正解パターン → 解説」で統一する。
Q1: Console 手動 Pipeline 構築 → CDK Pipelines Pipeline as Code
状況: チームが AWS Console で CodePipeline を手動設定し、スクリーンショットで構成を管理している。
アンチパターン: Console 操作で Pipeline を作成し、設定変更は毎回手動で実施。構成ドリフトが発生しても気づかない。
正解パターン: CDK Pipelines でコード化し、git push で Pipeline が自動更新される。
// CDK Pipelines で Pipeline as Code
import { CodePipeline, CodePipelineSource, ShellStep } from "aws-cdk-lib/pipelines";
const pipeline = new CodePipeline(this, "AppPipeline", {
pipelineName: "AppPipeline",
selfMutation: true,
synth: new ShellStep("Synth", {
input: CodePipelineSource.gitHub("owner/repo", "main"),
commands: [
"npm ci",
"npm run build",
"npx cdk synth",
],
}),
});
pipeline.addStage(new ApplicationStage(this, "Production"));
解説: Pipeline as Code により構成がバージョン管理される。selfMutation: true で Pipeline 定義の変更も自動反映される。Console での手動変更は次の git push 時に自動ロールバックされるため、ドリフトが発生しない。
Q2: 静的 IAM キー → GitHub Actions OIDC 連携
状況: GitHub Actions から AWS にアクセスするため、IAM ユーザーのアクセスキーを GitHub Secrets に保存している。
アンチパターン: 長期有効な IAM アクセスキーを Secrets に保存。キーローテーションが行われず、漏洩リスクが高い。
# アンチパターン: 静的キー
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
正解パターン: OIDC Provider を使用してキーレス認証を実現する。
# 正解: OIDC キーレス認証
permissions:
id-token: write
contents: read
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
role-session-name: GitHubActionsSession
aws-region: ap-northeast-1
解説: OIDC 連携により IAM アクセスキーが不要になる。一時クレデンシャルが自動発行され、有効期限(最大1時間)が切れると自動失効する。GitHub への認証情報漏洩リスクがゼロになる。
Q3: 手動 Pipeline 更新 → Self-mutating
状況: CDK でインフラ管理しているが、Pipeline 定義の変更は毎回 cdk deploy PipelineStack を手動実行している。
アンチパターン: Pipeline 定義変更のたびに手動デプロイが必要。CI/CD が半自動状態で属人化する。
// アンチパターン: selfMutation 無効
const pipeline = new CodePipeline(this, "Pipeline", {
selfMutation: false,
synth: new ShellStep("Synth", { /* ... */ }),
});
正解パターン: selfMutation: true で Pipeline 自身が自動更新される。
// 正解: self-mutating 有効
const pipeline = new CodePipeline(this, "Pipeline", {
selfMutation: true,
pipelineType: PipelineType.V2,
synth: new ShellStep("Synth", {
input: CodePipelineSource.gitHub("owner/repo", "main"),
commands: ["npm ci", "npm run build", "npx cdk synth"],
}),
});
解説: selfMutation: true により、CDK コードを変更して git push するだけで Pipeline 定義が自動更新される。SelfMutate ステージが CloudFormation を通じて Pipeline Stack を更新し、定義の乖離(ドリフト)が恒久的に解消される。
Q4: Single account deploy → Cross-account multi-environment
状況: 開発・ステージング・本番をすべて同一 AWS アカウントにデプロイしている。本番環境のリソースを誤って削除する事故が過去に発生した。
アンチパターン: 全環境を同一アカウントに集約。IAM 権限の境界が曖昧で誤操作リスクが高い。
// アンチパターン: 全環境を同一 account に
pipeline.addStage(new AppStage(this, "Dev", { env: { account: "111111111111", region: "ap-northeast-1" } }));
pipeline.addStage(new AppStage(this, "Stg", { env: { account: "111111111111", region: "ap-northeast-1" } }));
pipeline.addStage(new AppStage(this, "Prod", { env: { account: "111111111111", region: "ap-northeast-1" } }));
正解パターン: 環境ごとに別 AWS アカウントを割り当て、Pipeline から Cross-account でデプロイする。
// 正解: 環境ごとに別 account
pipeline.addStage(new AppStage(this, "Dev", { env: { account: "111111111111", region: "ap-northeast-1" } }));
pipeline.addStage(new AppStage(this, "Stg", { env: { account: "222222222222", region: "ap-northeast-1" } }));
pipeline.addStage(new AppStage(this, "Prod", { env: { account: "333333333333", region: "ap-northeast-1" } }), {
pre: [new ManualApprovalStep("ApproveProduction")],
});
解説: アカウント分離により本番環境への誤操作を IAM ポリシーレベルで防止できる。開発者は Dev アカウントのみ操作権限を持ち、Prod アカウントは Pipeline からのみデプロイ可能にする。アカウント境界はセキュリティの最強ガードレールである。
Q5: 環境差分手動管理 → Wave + Stage 構造で環境昇格自動化
状況: 開発・ステージング・本番それぞれで別の Pipeline を管理し、各環境へのデプロイは手動 trigger で実施している。環境間の設定差分が蓄積し、本番でのみ発生するバグが頻発している。
アンチパターン: 環境ごとに独立した Pipeline を手動管理。設定ドリフトが避けられない。
// アンチパターン: 環境別 Pipeline を個別に管理
new CodePipeline(this, "DevPipeline", { /* ... */ });
new CodePipeline(this, "StgPipeline", { /* ... */ });
new CodePipeline(this, "ProdPipeline", { /* ... */ });
正解パターン: 単一の Pipeline に Wave + Stage 構造を定義し、環境昇格を自動化する。
// 正解: Wave + Stage で環境昇格を自動化
const wave = pipeline.addWave("MultiRegionWave");
// Wave 内の Stage は並列実行
wave.addStage(new AppStage(this, "DevAP", { env: { account: devAccount, region: "ap-northeast-1" } }));
wave.addStage(new AppStage(this, "DevEU", { env: { account: devAccount, region: "eu-west-1" } }));
// Wave 通過後に Stg → Prod と順次昇格
pipeline.addStage(new AppStage(this, "Stg", { env: { account: stgAccount, region: "ap-northeast-1" } }), {
post: [new ShellStep("IntegrationTest", { commands: ["npm run test:integration"] })],
});
pipeline.addStage(new AppStage(this, "Prod", { env: { account: prodAccount, region: "ap-northeast-1" } }), {
pre: [new ManualApprovalStep("ApproveProd")],
post: [new ShellStep("SmokeTest", { commands: ["npm run test:smoke"] })],
});
解説: Wave 内のステージは並列実行されるため、マルチリージョンへの同時デプロイが可能。Stage 間は依存関係で直列化される。同じ CDK コードから全環境を生成するため、設定ドリフトが構造的に排除される。
アンチパターン変換演習 — 補足: Pipeline 設計の判断基準
上記5問をまとめて、アンチパターンから正解パターンへの変換で一貫して適用できる判断基準を示す。
判断基準1 — 「手動が介在するか」: デプロイフローに手動操作が含まれる場合、それは自動化の候補である。Console 操作・手動 trigger・手動キー管理はすべて「コードで置き換えられる手動作業」として扱う。
判断基準2 — 「ドリフトが発生するか」: 環境ごとに別の管理方法を採用すると、必ず設定差異が蓄積する。Wave + Stage 構造・CDK の同一コードベースでの全環境管理・self-mutating による Pipeline 定義の自動同期は、ドリフトを構造的に排除するアプローチである。
判断基準3 — 「認証情報がコードに触れるか」: 静的 IAM キー・パスワード・API トークンがコードや設定ファイルに存在する場合、OIDC・IAM ロール・Secrets Manager への置き換えが優先事項になる。
判断基準4 — 「アカウント境界を活用しているか」: 同一アカウントで本番・開発を同居させる設計は、IAM ポリシーだけでは誤操作を完全に防げない。アカウント分離はゼロコストのセキュリティガードレールであり、組織の成長に関係なく最初から採用することを推奨する。
これら4つの判断基準を持っておくと、新しいシステムの設計レビュー時に「このパターンはどのアンチパターンに当たるか」を素早く判断できる。
§8 まとめ + DevOps 三部作完成 + 46 記事化告知 + 全軸クロスリンクナビ
4 軸のまとめ
本記事では CodePipeline V2・CDK Pipelines・GitOps・Self-mutating の4技術軸を体系的に解説した。各軸の要点を以下に整理する。
CodePipeline V2: V1 との最大の差異は Trigger 設定の柔軟性とコスト構造の変化(実行分課金)にある。本番導入ではブランチフィルタと filePath フィルタを組み合わせ、不要な Pipeline 起動を防止することが品質維持の第一歩となる。
CDK Pipelines: CodePipeline コンストラクトにより Pipeline 定義をコードで管理できる。selfMutation: true により Pipeline 自身も git push で自動更新され、設定ドリフトを構造的に排除する。Stack 間依存は CfnOutput + Fn.importValue で宣言的に管理することが重要である。
GitOps: 「Git をシステムの真実の源泉(Single Source of Truth)とする」原則により、アプリケーション状態とインフラ状態の両方を git で管理する。ArgoCD と CDK Pipelines を組み合わせることで、Kubernetes ワークロードとクラウドインフラを統一的な GitOps フローで管理できる。
Self-mutating: Pipeline 自身が自分の定義を更新する仕組みにより、インフラチームの手動オペレーションを排除する。初回のみ cdk deploy 手動実行が必要な点を除き、以降はすべて git push で完結する完全自動化パイプラインを実現する。
DevOps Vol3 で習得した技術の実務活用シナリオ
シナリオ1 — スタートアップ段階 (5名チーム・単一リージョン)
CodePipeline V2 + self-mutating CDK Pipelines の最小構成から始める。Dev/Prod の 2 アカウント分離と OIDC 認証を最初から設定することで、チームが成長しても設計を壊さずにスケールできる基盤を作る。Manual Approval は Prod ステージのみに設定し、SNS でチーム全員に通知する。
シナリオ2 — 成長期 (20名チーム・マルチリージョン)
Wave + Stage 構造でマルチリージョン並列デプロイを追加する。アカウントを Dev/Stg/Prod に分離し、Integration Test ステージを Stg 後に配置して品質ゲートを強化する。GitOps 原則により、インフラ変更も git PR 経由でレビューを経てから本番に反映される。
シナリオ3 — エンタープライズ段階 (100名以上・マルチアカウント)
AWS Organizations + Control Tower でアカウント管理を統合する。CDK Pipelines を「プラットフォームチームの Pipeline」として運用し、各アプリケーションチームは自分のリポジトリに CDK コードを持ち、プラットフォームの Pipeline に接続する形で自律的にデプロイする。全 Pipeline の実行ログを AWS Security Lake に集約し、コンプライアンス監査に備える。
Vol1「CodePipeline × CodeBuild × CodeDeploy 基礎」→ Vol2「Container CD × CodeArtifact × SAM × Amplify 応用」→ Vol3「Pipeline V2 × CDK Pipelines × GitOps × Self-mutating 高度化」の三部作がついに完結。基礎から高度な自動化まで、AWS DevOps の全体像を体系的に習得できる構成になっています。
DevOps 三部作完成マップ — 全軸との接続
graph LR
DEV[DevOps Vol3 三部作完成] --> CONT[Container Vol1-3]
DEV --> SEC[Security Vol1-3]
DEV --> AI[AI/ML Vol1-3]
DEV --> IOT[IoT Vol1]
DEV --> OBS[Observability Vol1-2]
DEV --> SRV[Serverless Vol1-2]
DevOps/CI/CD Vol3 の公開により、AWS 本番運用シリーズは累計 46 記事に到達しました。全 19 軸・46 記事の体系的な学習コンテンツとして、AWS 実務者の技術キャリア形成を支援します。
全 19 軸の構成: DevOps Vol1-3 / AWS Code* Vol1-3 / Container Vol1-3 / Security Vol1-3 / AI/ML Vol1-3 / IoT Vol1 / Network Vol1-2+Hybrid / IAM Vol1 / Observability Vol1-2 / Serverless Vol1-2 / Storage Vol1-2 / Database Vol1-3 / Edge/CDN Vol1 / Analytics Vol1 / Migration Vol1
全軸クロスリンクナビ
本記事と連携する主要シリーズへのリンクを掲載する。Pipeline as Code・GitOps の実践には、インフラ管理・セキュリティ・可観測性の各軸との横断的な理解が不可欠である。
DevOps Vol1 — CodePipeline × CodeBuild × CodeDeploy 基礎
DevOps Vol2 — Container CD × CodeArtifact × SAM × Amplify
本番運用チェックリスト — DevOps 高度化の10項目
本記事で解説した技術を本番環境に適用する際の確認リストを示す。デプロイ前の最終確認として活用してほしい。
Pipeline 設計フェーズ
- [ ] CodePipeline V2 の Trigger 設定で
branches.includesとfilePaths.includesを明示した - [ ] CDK Pipelines に
selfMutation: true+pipelineType: PipelineType.V2を設定した - [ ] Stack 間の値受け渡しを
CfnOutput+Fn.importValueで宣言的に管理している - [ ] Cross-account デプロイ用の KMS キーポリシーと S3 バケットポリシーにデプロイ先ロールを追加した
認証・セキュリティフェーズ
- [ ] GitHub Actions の OIDC trust policy で
subクレームを完全一致で設定した - [ ] 静的 IAM アクセスキーを Secrets から削除し、OIDC 認証に完全移行した
- [ ] Manual Approval に SNS 通知を設定し、承認期限をコメントに明記した
GitOps 運用フェーズ
- [ ] git ブランチ戦略(trunk-based または GitFlow)を Pipeline Trigger と整合させた
- [ ] Wave + Stage 構造で Dev → Stg → Prod の昇格フローを定義した
- [ ] Pipeline 実行ログを CloudWatch Logs に送信し、失敗時の通知を設定した
トラブルシューティング早見表
現場でよく受ける質問と回答を簡潔にまとめる。
| 症状 | 原因 | 即時対処 |
|---|---|---|
| 全 PR で Pipeline が起動する | V2 Trigger に branches.includes 未設定 | triggers[].gitConfiguration.push[].branches.includes: ["main"] を追加 |
Export cannot be deleted エラー | Stack 間 CfnOutput の参照が残存 | 参照先 Stack を先に更新し、Export を削除してから再デプロイ |
OIDC AccessDenied | sub クレーム不一致 | CloudTrail で実際の sub 値を確認し trust policy を修正 |
| Self-mutating が止まらない | 初回手動デプロイ未実施 | npx cdk deploy PipelineStack を手動実行してから git push |
| Cross-account KMS エラー | キーポリシーにデプロイ先ロールが未追加 | key.grantDecrypt(crossAccountRole) を Pipeline Stack に追加 |
| Variables が空になる | Runtime Variable を Compile time 変数と混在 | variable.reference() を使い、VAR_ プレフィックスで区別 |
| Manual Approval が無通知で失効 | SNS 通知未設定 | pipeline.notifyOn() で MANUAL_APPROVAL_NEEDED イベントを SNS に接続 |
Pipeline as Code・GitOps・Self-mutating の三原則は、すべて「小さく・頻繁に・安全に変更を届ける」ためのものである。大きなバッチリリースより小さな継続的デリバリーのほうが、バグの影響範囲が小さく、原因特定も容易になる。本記事で解説した技術を「一度設定して終わり」ではなく、チームの継続的改善の基盤として育てていってほしい。
次のステップ — 推奨学習パス
本シリーズで習得した Pipeline as Code・GitOps・Self-mutating の技術は、以下の軸と組み合わせることでさらに強固な本番基盤を構築できる。
Container 軸との連携: EKS Pod Identity・Karpenter を組み合わせたコンテナ基盤の GitOps 管理。CDK Pipelines から EKS クラスターへのデプロイを自動化し、Helm Chart の管理を ArgoCD に委ねることで、Kubernetes ワークロードの完全 GitOps 運用を実現できる。
Observability 軸との連携: Pipeline 実行ログを CloudWatch Logs Insights で分析し、デプロイ頻度・リードタイム・変更障害率・復旧時間の DORA 4 メトリクスを可視化する。X-Ray を組み合わせることで、デプロイが本番パフォーマンスに与えた影響をトレースできる。
Security 軸との連携: Pipeline の各ステージに SAST(静的解析)・SCA(依存ライブラリ脆弱性スキャン)・コンテナイメージスキャンを組み込む。Amazon ECR の脆弱性スキャン結果を Pipeline の品質ゲートとして活用し、脆弱なイメージが本番に流れる前にブロックする。
AI/ML 軸との連携: SageMaker MLOps Pipelines と CDK Pipelines を統合し、モデルトレーニング → 評価 → 承認 → デプロイの一連のフローを Pipeline as Code で管理する。モデル品質の劣化をモニタリングし、再トレーニングを自動トリガーする GitOps フローを構築できる。
DevOps 三部作で培った「Infrastructure as Code + Pipeline as Code」の思想は、AWS 上のあらゆる本番運用の基盤となる。継続的改善のサイクルを回し、安全で高速なデプロイ文化をチームに根付かせてほしい。
学習深化のための公式リファレンス
本記事で解説した技術をさらに深掘りするための公式リソースを示す。AWS のドキュメントは頻繁に更新されるため、実装前に最新版を確認することを強く推奨する。
CodePipeline V2 関連
- AWS CodePipeline ユーザーガイド — V2 Pipeline タイプと Trigger 設定の詳細。Variables の namespace 設計と
${variables.xxx}の解決タイミングを理解する上で必読である。 - CodePipeline と GitHub の接続 —
CodeStarSourceConnectionのセットアップ手順と、Webhook vs ポーリングの選択基準を確認できる。
CDK Pipelines 関連
- AWS CDK Pipelines —
CodePipelineコンストラクトのリファレンス。Wave・Stage・ShellStep・CodeBuildStepの全パラメータと self-mutating の動作仕様が記載されている。 - CDK Workshop — Pipeline セクション。ハンズオン形式で CDK Pipelines の基本から Cross-account デプロイまで体験できる。
GitOps・OIDC 関連
- GitHub Actions と AWS の OIDC 統合 —
token.actions.githubusercontent.comの OIDC プロバイダー設定とsubクレームのフォーマット仕様の公式解説。 - ArgoCD ドキュメント — GitOps の実装リファレンス。
ApplicationSetを使った大規模マルチクラスター管理のベストプラクティスが参照できる。
8-7. DevOps 三層構造を貫く 5原則
Vol1 (基礎) / Vol2 (応用) / Vol3 (高度) を通読すると、AWS DevOps 本番運用には共通する5つの原則が浮かび上がる。これらは技術スタックを超えて適用できる普遍的な指針である。
原則1: すべてをコードに (Everything as Code): Infrastructure / Pipeline / Configuration / Policy / Test — すべての本番運用要素を Git 管理下のコードで表現する。Console 手動変更は原則禁止し、Drift Detection で逸脱を検知
原則2: キーレス認証を徹底 (Keyless Authentication): 静的IAMキーの保管・配布を撤廃し、OIDC / IAM Role / 短命クレデンシャルで認証統一。Vol3 §4 で示した GitHub Actions OIDC は最初の実装ターゲット
原則3: 段階的デプロイで安全担保 (Progressive Delivery): Wave + Stage 構造で Dev → Stg → Prd を昇格、Manual Approval で本番ゲート、Canary/Blue-Green でロールバック容易性を確保
原則4: 環境分離は Account単位で (Multi-Account by default): 本番/ステージング/開発を別 AWS Account で分離し、Cross-account deploy + IAM Trust で疎結合化。Blast radius を最小化
原則5: 可観測性とフィードバックループ (Observability + Feedback): Pipeline メトリクス (Lead time / Change failure rate / MTTR / Deployment frequency = DORA 4 指標) を CloudWatch で計測し、改善サイクルを回す
これら5原則は Vol1 の CodeBuild/CodePipeline 基礎から、Vol2 の Container/Serverless CD、Vol3 の CDK Pipelines/GitOps/Self-mutating まで一貫して通底する設計思想である。技術スタックが変わっても、この5原則が DevOps 本番運用の北極星となる。
8-8. 読者ペルソナ別 推奨実装順序
DevOps Vol3 を読み終えたあなたが、明日から組織で何を始めるべきかをペルソナ別に提示する。すべての項目を一度に着手するのではなく、自分の優先軸に応じて段階的に導入することを推奨する。
Velocity優先 (デプロイ頻度を上げたいチーム): Vol3 §4 GitOps OIDC → Vol2 §3 Container CD → Vol3 §2 V2 Variables → Vol3 §3 CDK Pipelines
Security優先 (監査対応を強化したいチーム): Vol3 §4 OIDC trust厳格化 → Vol3 §5 Cross-account 分離 → Vol1 IAM最小権限見直し → Vol3 §3 Manual approval ゲート
Cost優先 (運用コストを削減したいチーム): Vol2 §2 Container Spot活用 → Vol3 §3 CDK Pipelines (Console運用工数削減) → Vol3 §5 Self-mutating (Pipeline更新工数削減) → CodeBuild Linux ARM Graviton 切替
3つのペルソナのいずれにも共通するのは「すべてをコードに」の徹底だ。Console 操作を1つでも残すと、その箇所が将来の運用負債となる。
DevOps は「ツールを導入すること」ではなく「文化を醸成すること」である。CodePipeline V2・CDK Pipelines・GitOps・Self-mutating はその文化を支える技術的な基盤に過ぎない。本記事で紹介した技術を実際のチームに導入し、小さな成功を積み重ねながら、チーム全体が「変更を安全に・素早く・継続的に届けること」を当たり前とする文化を育ててほしい。DevOps 三部作がその第一歩になれば幸いである。