AWS CDK PipelinesによるCI/CD
AWS CDK Pipelinesの役割、パイプラインStackとアプリケーションStackの関係、Bootstrapから初回デプロイまでの流れ、GitHubの変更を起点にした継続的なデプロイ、Self-mutationによるパイプライン自身の更新を解説します。
CDK Pipelinesとは
AWS CDK Pipelinesは、AWS CDKアプリケーションのビルド、テスト、デプロイを継続的デリバリーとして定義するConstruct Libraryです。開発者はインフラをCDKコードで記述するだけでなく、そのCDKコードを取得して合成し、環境へ展開するCodePipelineベースの仕組みもCDKのConstructとして組み立てられます。
通常のCDK利用では、開発者が端末からcdk deployを実行してCloudFormation Stackを作成・更新します。CDK Pipelinesを導入すると、日常の変更はGitへのPushを起点にパイプラインが実行し、Synthで作成したCloud Assemblyを用いてCloudFormation経由でアプリケーションStackを更新します。つまり、CDKコードを使った通常のデプロイを自動化されたリリース手順に移すものであり、CloudFormationを置き換えるものではありません。
ここで扱うのはAWS CDKアプリケーション自体をCloudFormationでデプロイするパイプラインです。EC2上のアプリケーションをCodeDeployで更新するなど、任意のデプロイ方式をすべて代替する汎用パイプライン製品という意味ではありません。別のデプロイ工程や細かな制御が必要なら、CodePipelineのConstruct Libraryなどで個別に構成する選択肢があります。
Stackが二層になる理由
CDK Pipelinesでは、少なくとも二つの種類のStackを区別します。
| Stack | 何を定義するか | いつ作成・更新されるか |
|---|---|---|
| パイプラインStack | ソース連携、ビルド・Synth、Self-mutation、アセット公開、アプリケーション環境へのデプロイを行うパイプライン | 最初は開発者がcdk deployなどで作成する。パイプラインコードが変われば、パイプラインのSelf-mutationが更新する |
| アプリケーションStack | Lambda、API、データベースなど、実際に稼働するアプリケーションのAWSリソース | パイプライン実行のDeploy段階でCloudFormationが作成または更新する |
パイプラインStackはアプリケーションを配置するための自動化基盤であり、アプリケーションStackそのものではありません。CDKアプリケーションのコードには両方を定義しますが、CloudFormation上では別個のStackとして管理します。パイプラインがアプリケーションStackをデプロイする関係は「デプロイを行う側」と「デプロイされる側」の関係です。
初回セットアップとパイプラインの作成
CDK Pipelinesを使う前に、パイプラインを置く環境とアプリケーションをデプロイする環境を準備します。アカウントとリージョンの組み合わせが異なる場合、それぞれが独立したCDK環境です。パイプライン用環境とアプリケーション用環境は同一にもできますが、テスト用と本番用を分離すれば、権限や変更の影響範囲を切り分けやすくなります。
1. 対象環境をBootstrapする
cdk bootstrapは、指定したAWSアカウント・リージョンにCDKのデプロイ基盤を用意します。CDK Pipelinesでは、アセットの保管に使うS3バケット、コンテナイメージ向けのECRリポジトリ、パイプラインとCloudFormationの各処理に必要なIAMロールなどが重要です。Bootstrap Stackは一般にCDKToolkitという名前ですが、名前や構成は変更できます。
最低限、パイプライン自身をプロビジョニングする環境と、アプリケーションのStackをデプロイする各ターゲット環境をBootstrapします。複数アカウントや複数リージョンにデプロイする場合は、対象となるそれぞれの環境のBootstrapと信頼関係、ロール権限を整えます。パイプラインを置く場所だけBootstrapしても、別のデプロイ先に必要なロールやアセット格納先がなければ、ターゲットStackを展開できません。
Bootstrapは単に空のS3バケットを作る作業ではありません。どのロールがアセットを公開するか、どのロールがCloudFormationの実行権限を持つかというデプロイの信頼境界に関係します。特にCloudFormation実行ロールへ強い権限を与える場合、パイプラインが実行するソースコードや依存パッケージを信頼できる状態に保つことが重要です。
2. CDKコードでパイプラインStackを定義する
パイプラインを定義するCDKコードでは、ソースリポジトリ、Synth時のコマンド、デプロイするアプリケーションStageなどをConstructで表します。次は、TypeScriptでGitHub接続とSynthコマンドを定義する例です。接続ARNやリポジトリ名は自分の環境に合わせて設定します。
import * as cdk from 'aws-cdk-lib';
import * as pipelines from 'aws-cdk-lib/pipelines';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
class InventoryApplicationStage extends cdk.Stage {
constructor(scope: Construct, id: string, props?: cdk.StageProps) {
super(scope, id, props);
const applicationStack = new cdk.Stack(this, 'InventoryApplication');
new s3.Bucket(applicationStack, 'InventoryUploads', {
enforceSSL: true,
versioned: true,
});
}
}
class ReleasePipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const pipeline = new pipelines.CodePipeline(this, 'ReleasePipeline', {
pipelineName: 'InventoryRelease',
synth: new pipelines.ShellStep('Synth', {
input: pipelines.CodePipelineSource.connection(
'example-org/inventory-service',
'main',
{ connectionArn: 'arn:aws:codestar-connections:us-east-1:111122223333:connection/example-id' },
),
commands: [
'npm ci',
'npm run build',
'npx cdk synth',
],
}),
});
pipeline.addStage(new InventoryApplicationStage(this, 'test', {
env: { account: '111122223333', region: 'us-east-1' },
}));
}
}
CodePipelineSource.connectionはGitHubなどのプロバイダーとのCodeConnections接続を参照します。接続はAWS側で作成・認可し、CodePipelineがアクセスできる状態にしておきます。リポジトリとブランチの指定だけで権限設定まで完了するわけではありません。接続の承認状態、リポジトリへのアクセス範囲、パイプライン実行ロールの権限を確認します。
ShellStepのcommandsは、Sourceから取得したコードに対してSynth前に順番に実行するコマンド列です。ここではnpm依存関係のクリーンインストール、プロジェクトのビルド、cdk synthによる合成を行っています。プロジェクトや利用言語に応じて、コンパイル、単体テスト、静的解析などを加えられます。コマンドが失敗すれば後続のSynthやデプロイには進まないため、必要なビルドツールやロックファイルをリポジトリに含めて再現可能な環境にします。
3. パイプラインStackを初回デプロイする
パイプラインを作る最初のデプロイでは、開発者が認証済みの端末からcdk deployなどを使ってパイプラインStackをCloudFormationに作成させます。これによりCodePipelineやCodeBuildなど、後続の自動実行に必要なリソースが作られます。パイプラインStackがまだ存在しない段階では、当然ながらそのパイプライン自身を使って初回のパイプラインStackを作ることはできません。
その後、ソース連携が有効になったパイプラインがソースリポジトリからSynthを実行し、アプリケーションStackをデプロイします。初回のパイプラインStack作成と、パイプラインによるアプリケーション初回デプロイは別の作業段階です。cdk deployを一度も使わずにパイプラインを立ち上げるということではありません。
ソース更新時のパイプライン実行
パイプライン作成後は、設定されたソース変更が実行の起点になります。GitHubの接続とブランチをSourceとして構成している場合、対象ブランチへのPushを検知してPipelineが実行されます。概念上の流れは次のとおりです。
- Source:CodeConnectionsを通じて対象リポジトリのソースとリビジョンを取得する。
- Synth:
ShellStepで依存関係の導入、コンパイルやテスト、cdk synthなどを実行する。 - Cloud Assemblyの生成:Synthの結果としてCloudFormationテンプレート、アセット情報、Stack間の関係などをまとめたCloud Assemblyを作成する。
- Self-mutation:パイプライン定義に変更があれば、パイプラインStackを更新する。
- アセット公開:Synthで必要になったファイルアセットやコンテナイメージを、Bootstrap環境に用意されたS3やECRへ公開する。
- Deploy:対象のアプリケーションStackをCloudFormationで作成または更新する。
パイプラインはSynth結果をアセットとともにターゲット環境へ渡すので、アプリケーションコードのLambda関数やコンテナイメージに変更があれば、必要なアセットを公開したうえでStackを更新できます。処理の細部やステージの構成は設定により異なりますが、SynthだけでAWSリソースが更新されるわけではありません。実際のStack変更はDeploy段階のCloudFormationが担います。
通常のコード修正のたびに、開発者がローカルからアプリケーションStackへcdk deployを実行する必要はありません。Git Pushを起点とするパイプラインがSynthからDeployまでを行うためです。ただし、初回BootstrapやパイプラインStackの作成、障害復旧・運用上の特別な変更まで一切の手動操作がなくなるという意味ではありません。
パイプライン定義の変更とSelf-mutation
アプリケーションのStack定義を変更する場合と、パイプラインの構造を変更する場合では、更新される対象が異なります。たとえば、アプリケーションStackへ新しいLambdaを加える変更はアプリケーションStackの更新です。一方、デプロイ先のStage追加、Synthコマンドの変更、テスト工程の挿入などはパイプライン自体の定義変更です。
パイプライン定義を変更してGitへPushすると、既存パイプラインがそのコミットを取り込み、Synthで新しいパイプライン構成を含むCloud Assemblyを作ります。**Self-mutation(自己更新)**の工程はその結果を使ってパイプラインStackを更新します。以後のパイプライン実行では新しいステージや設定が利用されます。この仕組みにより、パイプラインの変更も通常はGit Pushを起点に自動適用でき、パイプラインStackを毎回端末からcdk deployする必要はありません。
ただし、Self-mutationはパイプラインStackの更新を指すものであり、任意のコード変更がその時点ですべて即座に適用されたことを意味しません。たとえば、新しく追加した承認工程やデプロイStageなど、更新後のパイプライン構造を使って実行する処理は、構成変更を取り込んだ次回以降の実行で有効になる場合があります。変更の反映状態と現在の実行履歴を確認し、必要なら新しい実行を開始します。
Self-mutationを無効にする構成では、パイプラインコードを変更しても自動で自身を更新しません。その場合はパイプラインStackを別の方法で更新する運用が必要です。自動化の利便性だけでなく、誰がどの変更を承認できるか、Pipeline定義の変更をどこでレビューするかも合わせて設計します。
GitHub連携とソース管理の注意
GitHubをCodePipelineのソースにする場合、現在の一般的な連携方法はAWS CodeConnectionsの接続を使うGitHub App連携です。パイプラインのSource指定にはリポジトリ、ブランチ、接続ARNが関係し、接続の所有者認可やリポジトリへのアクセス許可は別途必要です。Pushを常に起動条件とするか、ブランチ・タグなどで対象を絞るかもパイプライン設定で決めます。
CodeCommitは既存利用者と新規利用者で提供状況が異なるサービスです。新規顧客向けの利用可否にはAWSの最新案内を確認し、GitリポジトリとしてGitHubなどを使う構成も選択肢にします。試験や設問では、特定のリポジトリ製品に依存せず、Source工程が変更を検知し、後続のビルド・デプロイを開始する役割を理解することが重要です。
権限・変更管理・失敗時の確認
CDK Pipelinesの実行には、ソース取得、ビルド、アセット公開、CloudFormationによるリソース変更を行う権限が必要です。自動化だからといって無制限の管理者権限を安易に与えるべきではありません。少なくとも、次の観点を確認します。
- Bootstrapで作成または更新されるロールと、パイプラインの実行ロール・CloudFormation実行ロールの信頼関係と権限範囲。
- 本番アカウントへ変更できるコードのレビュープロセス、承認ゲート、ブランチ保護、実行対象となるタグやブランチ。
- npmなど外部依存パッケージの信頼性、バージョン固定、ロックファイルの管理。依存関係の変更も最終的に配備内容へ影響し得る。
- ソース接続が有効で対象リポジトリを参照できること、Synth用環境で必要なランタイムやコマンドが使えること。
- デプロイ先環境でBootstrapが適切に完了し、アセット公開先と必要なIAMロールが存在すること。
- CloudFormation Stackの失敗状態、変更セット、イベントログを調べ、再実行前に失敗原因を解消すること。
CDK Pipelinesはソースからデプロイまでを自動化しますが、悪意ある変更を自動的に検出して止める万能の仕組みではありません。パイプラインに強いデプロイ権限を与えるほど、ソースコードや依存関係へのアクセス制御とレビューが重要になります。本番用認証情報を開発者の端末に長期間保持せず、Bootstrap後の変更をパイプライン経由にする方法は、資格情報の露出を減らすうえで有効です。
試験で区別するポイント
- CDKとCDK Pipelines:CDKはインフラをコードで定義しCloudFormationテンプレートを合成するフレームワーク。CDK PipelinesはCDKアプリのSynthと継続的なCloudFormationデプロイを構成するライブラリ。
- パイプラインStackとアプリケーションStack:前者はデプロイの仕組み、後者は実際のアプリケーションリソースを定義する。別Stackとして管理され、パイプラインがアプリケーションStackをDeployする。
- Bootstrapと初回デプロイ:Bootstrapは各アカウント・リージョンにアセット保管先やIAMロール等を用意する。最初のパイプラインStack作成には通常、
cdk deployなどの初回デプロイが必要。 - SynthとDeploy:SynthはCDKコードからCloud Assemblyを合成する工程。これ自体はアプリケーションStackを更新しない。Deploy段階でCloudFormationがStackを作成・更新する。
- アプリケーション変更とパイプライン変更:アプリ定義の変更はアプリケーションStackの更新、Stageや工程の変更はパイプラインStackのSelf-mutation。
- Self-mutation:パイプラインが自らのStackを更新する機能。通常のパイプライン定義の変更に手動の
cdk deployを不要にできるが、更新後の新しい構成が次回以降の実行で有効になることがある。 - Source接続と認可:リポジトリ・ブランチの指定に加え、GitHub接続を認可し、必要なアカウント・ロールに権限を与える。
公式ドキュメント
重要ポイント
- ▸CDK PipelinesはAWS CDKアプリケーションの継続的デリバリーを定義するConstruct Libraryであり、CDKアプリ内でパイプラインをコードとして構成する
- ▸パイプライン用Stackとデプロイ対象アプリケーション用Stackは別のCloudFormation Stackで、パイプラインがSynthしたCloud Assemblyを使って後者をデプロイする
- ▸Bootstrapはパイプラインの配置先と各デプロイ先のアカウント・リージョンごとに必要な基盤と権限を用意し、パイプラインStackの初回デプロイには通常cdk deployを使う
- ▸ソース変更後はSourceからSynth、必要なアセットの公開、アプリケーションStackのデプロイへ進み、通常の更新で開発者が毎回cdk deployを実行する必要はない
- ▸パイプライン定義の変更はSelf-mutationでパイプラインStackに反映され、新しいステージやStackを以降の実行で利用できるようになる
- ▸GitHubのSource接続にはAWS CodeConnectionsを使い、Synthのビルドコマンドは依存関係の導入、ビルド、cdk synthなどを明示する
- ▸CDK Pipelinesは高い権限を使ってCloudFormationでCDKアプリを配備するため、ソース・依存関係・IAM権限・本番承認を適切に管理する
このトピックの学習を完了しますか?
完了状態はいつでも切り替えられます
この試験ドメイン内で次の学習に進む
同じサービスの関連トピック
開発自動化と IaC に関連するトピックを続けて確認できます。