本記事は
IaCウィーク
2日目の記事です。
⚙️
1日目
▶▶ 本記事 ▶▶
3日目
💻

はじめに
こんにちは、新卒3年目の宇都木です。2年ぶりぐらいの投稿なので緊張しています。
IaCウィークということで、配属当初から使用しているCDKで、「え、そうなの」と感じた仕様についてクイズ形式で書きたいと思います。
そもそもCDKとは
AWS Cloud Development Kit(以下CDK)とは、TypeScript、Pythonといったプログラミング言語を使ってAWSインフラを構築できるInfrastructure as Code(以下IaC)ツールです。
CDKでは、Amazon Elastic Compute Cloud(以下EC2)やAmazon Simple Storage Service(以下S3)などのAWSリソースに対応したConstructというクラス(関数のようなもの)があらかじめ用意されており、これを呼び出すことでAWS CloudFormation(以下 CloudFormation)と比較してコード量を大幅に削減できます。
デプロイ時には自動的にCloudFormationテンプレートに変換され、CloudFormationスタックとして管理されます。

問題➀:リージョン
【問題】
東京リージョンと大阪リージョンそれぞれにS3バケットを作成したいと考えています。その場合、CDK上ではどのように定義するべきでしょうか。
- 同じスタック内でそれぞれのS3バケットを定義する
- リージョンごとにスタックを分けてS3バケットを定義する
- CDKでは対応できない
答えを見る
【正解】2. リージョンごとにスタックを分けてS3バケットを定義する
【解説】
1つのスタックは1つのリージョンにのみデプロイできます。
そのため異なるリージョンのリソースを作成したい場合は、スタックを分けて作成しましょう。
※同じスタックに別リージョンのリソースを作成するコードをデプロイしてもエラーにならない場合がありますが、正常に動作しないので注意しましょう。
しかし、グローバルリソース(リージョンの指定不要なリソース)であるIAMやCloudFrontなどは、別リージョンと同じスタック内で定義可能です。
問題➁:CDK
【問題】
CDKで値が「1111」のAWS Systems Manager(以下SSM)パラメータAをデプロイしました。値が間違っていたのでSSMのAWSマネジメントコンソール(以下マネコン)から値を「2222」に書き換えました。
その後、CDKコードに別のパラメータBを追加してデプロイしました。パラメータAにはどの値が登録されているでしょうか。
- 1111(CDKの値)
- 2222(マネコンで変更した値)
- エラーが発生する
new ssm.StringParameter(this, 'paramA', {
parameterName: 'paramA',
// マネコン上は2222
stringValue: '1111',
});
// 後からコメントインして、デプロイ
// new ssm.StringParameter(this, 'paramB', {
// parameterName: 'paramB',
// stringValue: 'test',
// });
答えを見る
【正解】2. 2222(マネコンで変更した値)
【解説】CDKはCloudFormationテンプレートとの差分のみを検知します。
マネコンからパラメータの値を変更しても、CDKコードやCloudFormationテンプレートには反映されません。
したがって、CloudFormationテンプレートで「1111」、CDKでも「1111」と定義されているため、変更なしとしてパラメータAのデプロイは実行されず、「2222」の値のままとなります。
パラメータAのCDKコード(変更後の値): 「1111」
CloudFormationテンプレート(現状の値): 「1111」
→ 変更なし
→ パラメータAはデプロイ対象にならない
→ マネコンで変更した「2222」がそのまま残る
しかし、パラメータAの値をCDKで「3333」に変更した場合は、CDKで定義した値で上書きされます。
パラメータAのCDKコード(変更後の値): 「3333」
CloudFormationテンプレート(現状の値): 「1111」
→ 変更あり
→ パラメータAはデプロイ対象になる
→ CDKで定義した「3333」で上書きされる
直接マネコンから変更すると、実際の値とCDK上の値に乖離が生まれて整合性が取れないため、CDKから変更を加えるようにしましょう。
実際の値とCloudFormationの値に乖離があるか(ドリフト)を確認するための機能として「ドリフトの検出」があります。
問題➂:EC2
【問題】
下記のコードを使って、EC2を作成しました。その後、同じスタックの別リソースのコードを改修し、久しぶりにcdk deployを実行しました。どんなことが起きたでしょうか。
const instance = new ec2.Instance(this, 'Instance', {
vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MICRO),
machineImage: ec2.MachineImage.latestAmazonLinux2023(),
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
});
答えを見る
【正解】EC2インスタンスが削除されて、新しいインスタンスが作成されました(置き換えられました)。
【解説】
原因はlatestAmazonLinux2023()です。
machineImage: ec2.MachineImage.latestAmazonLinux2023()は、常に最新のAMIを取得します。最新AMIが更新されていたため、久しぶりにデプロイしたタイミングで、意図せずEC2のAMIが更新され、既存のインスタンスが削除されて新しいインスタンスに置き換えられました。
直接的にEC2に対しての更新を行っていなくとも同じスタックに対して変更があった場合には、この事象が発生するため注意が必要です。
回避策として、AMIは固定にしておくのが良いでしょう。念のため、デプロイ前にcdk diffで意図しない変更がないか確認するのも大切です。
const instance = new ec2.Instance(this, 'Instance', {
vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MICRO),
// AMI IDを明示的に指定
machineImage: ec2.MachineImage.genericLinux({ 'ap-northeast-1': 'ami-0ab0bbbd329f565e6' }),
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
});
さいごに
正答率はいかがでしたか?
実際にコードを書いてみると想像通りに動かなかったり、思いがけない動作をしたりなどあるかと思います。
事前に仕様を理解しておくことも大事ですが、実際に動かしてみないと分からないこと、発見できないことなどあるかと思いますので、
たくさん書いて、たくさん動かしていきましょう。