AWS CDK 触る
目標
- CDK で実用するものを動かす
-
毎日定時で AWS の料金を Slack で通知するやつ作る
- 料金ではないけど CDK で定時で API 叩いて Slack 通知するやつを作った
- CDK で EventBridge、Lambda、CloudWatch Logs の連携をしたリソースをデプロイできるようにした
いきなりドキュメントのタイトルがかわいそうなことになってる
CFn のテンプレートを自動生成するためのコードを書くってことか
- App
- Stack
- Construct
- Stack
リポジトリ
API ドキュメント
概念
AWS のドキュメント日本語訳ひどいからありがたい
AWS CDK の役割と Construct
AWS CDK は、AWS リソースを抽象化した、App > Stack > AWS_Resource で構成される木構造を定義し、これをデプロイする役割を担う。
- Construct
- App, Stack AWS_Resource の基底クラス
App Construct
Appは construct tree のルートとして使用することができる唯一の Construct だから、App は、任意の初期化引数を必要としません。App は、Stack インスタンスを定義するための Scope として使用できます。
App lifecycle
ref: https://zenn.dev/yamatatsu/books/aws-cdk-documentation-jp/viewer/03-concepts-apps#app-lifecycle
cdk deploy
を実行したときに CDK app(ソースコード)が通過するフェーズ
- CDK App を実装する(TypeScript、Go、Python、...)
-
cdk deploy
を実行 - CDK CLI が CDK App を呼び出す
- Construct → Prepare → Validate → Synthesize
- 初期化 → 準備 → 検証 → 合成
- Construct フェーズでは、定義された全ての Construct のインスタンス化、リンクが行われる。全ての Construct(App, Stack, それらの子 Construct)がインスタンス化され、constructor chain が実行される。
- Prepare フェーズは
prepare
メソッドを実装した Construct のみ参加する。 - Validate フェーズは
validate
メソッドを実装した Construct のみ参加する。Construct を検証して正しくデプロイされる状態にあるかを確認できる。 - Synthesis フェーズは
app.synth()
の呼び出しでトリガーされる。Construct tree(CDK で定義する AWS リソース群の木構造)をトラバースし、全ての Construct についてsynthesize
メソッドを呼び出す。 - ここまででデプロイアーティファクトが作られる。
- デプロイアーティファクト
- AWS CloudFormation テンプレート
- AWS Lambda アプリケーションバンドル
- ファイルと Docker イメージアセット
- その他のデプロイアーティファクト
- デプロイアーティファクト
- デプロイ
- Synthesize フェーズで生成されたデプロイアーティファクトを取得し、AWS 環境へデプロイする。
Stack, Stack API
ref: https://zenn.dev/yamatatsu/books/aws-cdk-documentation-jp/viewer/04-concepts-stacks
AWS CDK でのデプロイの単位を Stack と呼ぶ。
Stack の Scope 内で直接または間接的に定義された全ての AWS リソースは単一のユニットとしてプロビジョニングされる。
Stack は AWS CloudFormation Stack を介して実装されているので、AWS CFn と同じ制限に従う。
CDK App では、任意の数の Stack を定義できる。
CDK では CFn のパラメータの扱いとは考え方が異なる
- AWS CDK
- 具体的なテンプレートが合成時に決定されるアプローチを取っている
- AWS CFn
- CloudFormation パラメータはデプロイ時にのみ解決される(つまり app のプログラム中でパラメータの値を参照できない)
AWSTemplateFormatVersion: 2010-09-09
Parameters:
EnvType:
Description: Environment type.
Default: test
Type: String
AllowedValues:
- prod
- test
ConstraintDescription: must specify prod or test.
## デプロイ時に解決される Conditions
Conditions:
CreateProdResources: !Equals
- !Ref EnvType
- prod
Resources:
EC2Instance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: ami-0ff8a91507f77f867
MountPoint:
Type: 'AWS::EC2::VolumeAttachment'
Condition: CreateProdResources
Properties:
InstanceId: !Ref EC2Instance
VolumeId: !Ref NewVolume
Device: /dev/sdh
NewVolume:
Type: 'AWS::EC2::Volume'
Condition: CreateProdResources
Properties:
Size: 100
AvailabilityZone: !GetAtt
- EC2Instance
- AvailabilityZone
Stack の命名規則
AWS CloudFormation stack の物理名は、ツリー内の Stack の Construct path パスに基づいて AWS CDK によって自動的に決定されます。デフォルトでは、Stack の名前は Stack オブジェクトの construct ID から派生しますが、次のように stackName prop を使用して明示的な名前を指定できます。
new MyStack(this, "not:a:stack:name", { stackName: "this-is-stack-name" });
Environments 環境
ref: https://zenn.dev/yamatatsu/books/aws-cdk-documentation-jp/viewer/05-concepts-environments
デプロイ先の AWS アカウントやリージョンを切り替える方法や、それぞれの方法のメリットが説明されています。
app の各 Stack インスタンスは、明示的または暗黙的に環境(env
)に関連付けられている。環境は、
- スタックがデプロイされる予定のターゲット AWS アカウント
- スタックがデプロイされる予定のターゲットリージョン
Stack をインスタンス化するときに環境を指定しない場合、Stack は environment-agnostic(環境非依存) と言われる。
このような environment-agnostic Stack から合成された AWS CloudFormation テンプレートは、stack.account, stack.region, stack.availabilityZones などの環境関連の属性について、デプロイ時に解決しようとする。
cdk deploy
実行時のデプロイ先の解決
cdk deploy
を使用して環境を問わない Stack をデプロイする場合、AWS CDK CLI は指定された AWS CLI プロファイル(または何も指定されていない場合はデフォルトプロファイル)を使用して、デプロイ先を決定する。
AWS CDK CLI は、AWS CLI と同様のプロトコルに従って、AWS アカウントで操作を実行するときに使用する AWS credentials を決定する。
本番環境における「環境」の設定
なるほど
本番用 Stack では、env プロパティを使用してアプリ内の各 Stack の環境を明示的に指定することをお勧めします。次の例では、その 2 つの異なる Stack に対して異なる環境を指定しています。
const envEU = { account: "2383838383", region: "eu-west-1" };
const envUSA = { account: "8373873873", region: "us-west-2" };
new MyFirstStack(app, "first-stack-us", { env: envUSA });
new MyFirstStack(app, "first-stack-eu", { env: envEU });
訳者の追記なるほど
ref: https://zenn.dev/yamatatsu/books/aws-cdk-documentation-jp/viewer/05-concepts-environments#ヤマタツ追記
ヤマタツ追記
秘匿情報でない限り、TS を使う場合には環境値も TS 内で定義するほうが一貫性があって扱いやすいと、個人的には思っています。その場合、デプロイ先の環境名をキーにして環境固有値を引けるようにすると扱いやすいと思います。
const ENV_NAMES = ["dev", "stg", "prd"] as const;
type EnvName = typeof ENV_NAMES[number];
type EnvValues = {
envName: string;
domainName: string;
externalServiceEndpoint: string;
};
export function getEnv(): EnvValues {
const envName = (process.env.ENV_NAME || "dev") as EnvName;
switch (envName) {
case "dev":
return {
envName,
domainName: "dev.example.com",
externalServiceEndpoint: "https://dev.external.example.com",
};
case "stg":
return {
envName,
domainName: "stg.example.com",
externalServiceEndpoint: "https://stg.external.example.com",
};
case "prd":
return {
envName,
domainName: "example.com",
externalServiceEndpoint: "https://external.example.com",
};
default:
const _: never = envName;
throw new Error(
`Invalid environment variable ENV_NAME has given. ${envName}`
);
}
}
環境変数を cdk deploy
時に渡す
ENV_NAME=prd cdk deploy
cdk の context という機能もあるみたい。
cdk deploy -c ENV_NAME=prd
使ってみないとわからんね。context に他の用途があるかもしれない。
でも、多言語ならいざしらず、使い勝手が同じなら、Node.js が純粋にできること(環境変数の取得)をわざわざ CDK 独自機能で解決する必要はない、というのが個人的な考え方ではあります。
続きここから
なかなか長い
-
07 Concepts - Resources
- 読んどいた方が良さそう
-
AWS CDK を書いてて、ハマるケースの多くがこの章に書かれていると思う。
コードブロックだけでも良いので眺めていって、気になるところを文章読んでみてもいいかも。 -
とにかく読んでほしい。
-
08 Concepts - Identifiers
- Construct IDs は必読
-
Construct IDsは読んでおいて損はないかと思う。第 2 引数に渡されるidの説明。重複が怒られるケースと怒られないケース(scope の概念)がわかる。
-
それ以降の項は全く知らなくても何ら問題ないと思う。
- 09 Concepts - Tokens
-
10 Concepts - Parameters
- ここらへん読み直して思い出そう。たぶん CDK では使わないのだろう。
-
CFn の Parameters。CFn と同じように使えるけど、環境変数やコンテキストの方を使うことが推奨されている。つまりあんまり読まなくても OK。
-
11 Concepts - Tagging
- すぐ必要にならないと思うけどどうせ必要になるから読んでおく
-
CDK でのタグの付け方。オプションとかも含めて学びが多い。タグ付けが必要になったときには読み直したい。
-
12Concepts - Assets
-
CDK の Assets を知らない場合は是非読んで欲しい。インフラデプロイとアプリケーションデプロイの境目を消して、CD の構成を容易にし、フルサイクルエンジニアが DevOps で働くのを大いに助ける、CDK における重要な機能の説明。
-
-
13 Concepts - Permissions
- 訳者強く推奨
-
CDK を始める方は読んでおくことを強く推奨します。
-
CDK では L2 以上のコンストラクト(Cfnで始まってるクラス以外)を使っていれば、勝手に最小限の権限が与えられた Role が生成されて割り当てられるので、Terraform や CFn と違って Role をいくつも宣言する必要がありません。それでもリソースからリソースへ権限を渡すのにgrantメソッドをよく使うので、読んでおくとコーディングが捗ります。
- 14Concepts - Context
- <s>15 Concepts - Feature Flags</s>
- 16 Concepts - Aspects
- <s>17 Concepts - Escape Hatches</s>
- 18 Concepts - Bootstrapping
読まなくて良さそう
ざっと目を通して今は必要なさそうな章
- 15 Concepts Feature Flags
- https://zenn.dev/yamatatsu/books/aws-cdk-documentation-jp/viewer/14-concepts-feature-flags
-
今から CDK を使い始める場合、v2 を使うことになると思うので、知らなくても大丈夫と思います。
- 17 Concepts Escape Hatches
- https://zenn.dev/yamatatsu/books/aws-cdk-documentation-jp/viewer/16-concepts-escape-hatches
-
「このクラス、Props にあの機能生えてないじゃん!CloudFormation ならできるのに!」ってときに読む。
- このときが来たら読もう。使い始めていきなりは来ないはず。
-
もしその機能が AWS CloudFormation を通してではなく、直接の API コールを通してのみ利用できる場合、唯一の解決策は、必要な API コールを行うために AWS CloudFormation Custom Resource を書くことです。AWS CDK はこれらを書くことを容易にし、それらを通常のコンストラクトインターフェイスにラップするので、他のユーザーの観点から、機能はネイティブに感じられるのです。