CI/CD Pipeline with AWS CDK

Kohei Yoshida
11 min readOct 8, 2021

--

Photo by T K on Unsplash

※本記事は AWS CDK を知っている人が読む前提で書いているため、CDK の概念や用語についての説明は省略している。

English version is also available here.

CDK Pipeline とは?

CDK Pipeline は AWS CDK によりデプロイされるアプリケーションの CI/CD Pipeline を CDK により管理するためのもの。

2021 年 7 月に GA (一般リリース) されたかなり新しい機能。(ただ、Developer Preview としてすでに 1 年前から試せる状態にはなっていた)
https://aws.amazon.com/about-aws/whats-new/2021/07/announcing-cdk-pipelines-ga-ci-cd-cdk-apps/?nc1=h_ls

簡単に言うと、CDK Application の Continuous Delivery を実現するために、@aws-cdk/pipelines construct library を使って AWS CodePipeline のリソースを作成するもの。

Pipeline の作成

この機能が GA になる前から blog post は公開されており、サンプルのコードもこちらに載っている。

しかし、現在は API モデルが大きく変更になっており、新しいものが推奨されている。
https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/pipelines/ORIGINAL_API.md

もちろん “古い API” も利用可能であり、実際ネット上でも当時のブログの内容を参考にしたものが多く、 “新しい API” で書かれたサンプルが少なかった。
自分は “新しい API” ですべて書いたため、この記事が誰かの参考になれば嬉しい。

コードを使った説明

このリポジトリで、CDK Application, Application code, CDK Pipeline のすべてを管理している。
サンプル用に作ったものではないのでそれほどシンプルではないが、実際に動いているものなのでリアルな例として参考になるかと思う。

app.ts

code: bin/app.ts

app.ts より一部抜粋

Pipeline Stack のみを作成している。Application Stack は、Pipeline の Stage 内で作成されるため、単一の Stack としてここで作成する必要はない。

Application Stack

code: lib/new-bmo-stack.ts

DynamoDB, Lambda, API Gateway を作成する Application Stack で、特に CDK Pipeline について考慮する必要はない。既存のものをそのまま利用できる。

Pipeline Stack

code: lib/bmo-pipeline-stack.ts

メインとなる Pipeline Stack がこれ。これにより Pipeline はもちろん、各ステージの設定やテストなどを定義できる。
GA 前のブログと見比べれば分かるが、“新しい API” では非常にシンプルに書けるようになっている。シンプルすぎて特に説明することがない。

強いて何か説明するとすれば、Dev と Prod に Application をデプロイする際は、new BMOPipelineStage() によりステージを作成 (その中でスタックも作成される) し、それを addStage() で追加しているところだろうか。
また、テストについても、addStage() のオプションである AddStageOpts にて pre または post を指定して step を追加できる。

bmo-pipeline-stack.ts より一部抜粋

Application Stage

code: lib/pipeline-stage.ts

この Stage の中で、デプロイ可能なユニットとして Application Stack を生成してる。ここから各ステージの CloudFormation Stack が生成される。

pipeline-stage.ts より一部抜粋

ちなみに、ここで Application Stack は stage という Property を受け取っているが、これは aws-cdk/coreStackProps にはもともと含まれておらず、自分で拡張した。
これは、ステージを Application Stack に渡してリソース名に使いたかったからであり、必須のものではない。

Application Stack (lib/new-bmo-stack.ts) より抜粋

Lambda Function code (Application code)

code: lambda/*

Lambda のコードが入ってる。これも、CDK Pipeline に対応するための変更等は必要ない。

ちなみに、TypeScript で Lambda のコードを書いてるが、tsc で Node.js に transpile されるため、特にそのあたりを意識する必要がないのがとても便利。

Pipeline のデプロイ

上記で準備は完了しており、これを一度 cdk synth して cdk deploy すると、self-mutating な Pipeline が AWS CodePipeline の pipeline として組まれるので、以降はリポジトリに push するだけで勝手に Application も Pipeline も更新してくれる。

CDK Pipeline の中では何が起きてるのか

ここからは、実際に作成された Pipeline がどうなっているのかを見ていく。
例として使ったパッケージ (new BMO) の場合 6 つのステージがパイプラインに含まれている。

Source Stage

ターゲットとなっているパッケージおよびブランチにコミットが追加・マージされると GitHub webhook が呼ばれる。

Build Stage

ビルドし、CloudFormation テンプレートと関連するファイルを生成する。

※ “synthesize” は実際何をしてるのか

cdk synthコマンドはデプロイに必要なファイルが含まれる cdk.out ディレクトリを生成する。
https://github.com/aws/aws-cdk-rfcs/blob/f0c2464450803d63f5eb6f9785c6e38b4ce09045/text/0049-continuous-delivery.md#synthesis

UpdatePipeline Stage

cdk deploy コマンドで Pipeline Stack をデプロイし、pipeline 自身を更新する。(Self-mutate)

Assets Stage

Asset とは、S3 にアップロードするファイルまたは ECR image のこと。
cdk-assets publish コマンドにより assets をデプロイ (e.g. packaging, upload to S3) する。
https://github.com/aws/aws-cdk-rfcs/blob/f0c2464450803d63f5eb6f9785c6e38b4ce09045/text/0049-continuous-delivery.md#asset-stores

Dev Stage

Dev 環境にリソースをデプロイする。

Prod Stage

Prod 環境にリソースをデプロイする。ここにはテストも含まれており、Prod 環境へのデプロイ前にテストされる。

FAQ

Q. どうやって Pipeline に permission を渡す?

CDK Pipeline を動かすために、以下の 2 つのステップが必要になる。

  • Bootstrap 環境の編集

cdk.json を編集し、機能を有効化する。

{
...
"context": {
"@aws-cdk/core:newStyleStackSynthesis": true
}
}

この機能を有効化することで、Bootstrap は CDK Pipelines が動作するために必要な、新しい (1.46.0 以降の) ものに切り替えられる。

  • CloudFormation execution policy の追加

以下のコマンドを実行。

$ cdk bootstrap --profile <awsProfile> --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess aws://<accountId>/ap-northeast-1

今までは CLI を利用するユーザーと同じ権限を使っていたが、新しい Bootstrap を使用する場合、このコマンドで CDK が利用する権限を渡す事ができる。

https://docs.aws.amazon.com/ja_jp/cdk/latest/guide/bootstrapping.html#bootstrapping-customizing

Q. 新しく作った CDK Pipeline に既存の stack を追加できる?

多分、通常の方法ではできない。なぜなら、Pipeline にステージを追加する addStage method では Stage construct を渡す必要があるため。そして多分新しい Stage に既存のスタックやリソースを追加はできないと思われる。

もしどうしてもやりたい場合、@aws-cdk/pipelines の代わりに@aws-cdk/aws-codepipelines を利用して自前で AWS CodePipeline のリソースを作り、自前でパイプライン・ステージ・アーティファクト・self-mutate・build-spec などなどを管理すればできるかも…?
ただ、これは CDK Pipeline のメリットをすべて失うことになるし、そもそも CDK で管理されているアプリケーションなら簡単に再利用・デプロイできるべきであるという気がする。

いずれにしても自前で管理するのは tech debt を増やすだけなので、新しく CDK Pipeline で環境を作って、どこかで切り替えるなどにしたほうが良いと思う。

自分も CDK Application だけ先に作っていて後から Pipeline に組み込みたいと思ったので、気持ちは分かる。ただ、自分も一回 destory して Pipeline に組み込んで deploy し直した。

リファレンス

--

--