今から始める CDK 入門 #4
今から始める CDK 入門シリーズの 4 回目です。
各回については以下のリンクからご覧ください。
前回は実践!AWS CDK #3 テスト | DevelopersIO を参考に以下の内容を実施しました。
- Fine-grained assertions でのテスト
今回は実践!AWS CDK #4 Context | DevelopersIO を実施します。
Context とは
ブログによると、CloudFormation におけるパラメータに該当するのが CDK の Context とのことです。
ドキュメントにもキー/バリューのペアである旨の記載があります。
ランタイムコンテキスト - AWS Cloud Development Kit (AWS CDK) v2
コンテキスト値は、アプリケーション、スタック、またはコンストラクトに関連付けることのできるキー/バリューペアをいいます。
CloudFormation のパラメータはスタック作成時や更新時に都度指定可能で、テンプレート内から参照できる機能です。
パラメータ - AWS CloudFormation
パラメーターを使用すると、スタックを作成または更新するたびにテンプレートにカスタム値を入力できます。
Context やパラメータの詳細についてはブログおよびドキュメントをご参照ください。
ブログでは以下の 2 つ方法を試しています。
- プロジェクトの
cdk.json
ファイル- デフォルト値の設定に利用
- CDK コマンドの
--context
オプション- デフォルト値以外の設定に利用
ブログ内でも紹介されている通り、値の取得には construct.node.tryGetContext
メソッドを使用します。
ドキュメントでは各プログラミング言語ごとでの値の取得方法も紹介されていますので、TypeScript 以外での実装については上述のドキュメントをご参照ください。
実装
まずは cdk.json
ファイルを使用する方法です。
ブログと同様に cdk.json
ファイルの context
オブジェクト内末尾にキー/バリューを追記します。
{
"app": "npx ts-node --prefer-ts-exts bin/devio.ts",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"**/*.d.ts",
"**/*.js",
"tsconfig.json",
"package*.json",
"yarn.lock",
"node_modules",
"test"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"systemName": "devio", 追記
"envType": "stg" 追記
}
}
続いて devio-stack.ts
で上記のデフォルト値を取得します。
なお、コードは CDK V2 用のコードですのでブログのコードとは異なる部分もあります。前回までのブログとの相違点については冒頭のこれまでのブログをご参照ください。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CfnVPC } from 'aws-cdk-lib/aws-ec2';
export class DevioStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const systemName = this.node.tryGetContext('systemName'); // 追記
const envType = this.node.tryGetContext('envType'); // 追記
new CfnVPC(this, 'Vpc', {
cidrBlock: '10.0.0.0/16',
tags: [{ key: 'Name', value: `${systemName}-${envType}-vpc` }] // 更新
});
}
}
前述した通り、値の取得には construct.node.tryGetContext
メソッドを使用します。
construct
については this
となっているだけです。
systemName
と envType
という変数に cdk.json
から取得したデフォルト値を格納し、tags
で結合しているだけです。
確認
cdk synth
で確認します。
$ cdk synth
Resources:
Vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Name
Value: devio-stg-vpc ← 想定通り
想定通り、タグの値に cdk.json
から取得したデフォルト値を結合した値が指定されています。
デフォルト値以外の値を使用する場合は cdk synth
に --context
オプションを付与します。
なお、--context
オプションは -c
と略しても機能するためブログ内では -c
を使用しています。
$ cdk synth -c systemName=starwars -c envType=prd
Resources:
Vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Name
Value: starwars-prd-vpc ← デフォルト値以外の値になっている
--context
オプションを付与することでデフォルト値をオーバーライドしていることが確認できました。
テスト時の注意
ブログにも記載されている通り、テスト実行時には Context の値を取得できないため回避策も紹介されています。
-
undefined
が来ることを想定してテストコードを記述する -
cdk.App()
のイニシャライザーに Context を指定する
試しに 'Value': 'undefined-undefined-vpc'
に変更しない状態でテストを実行したところ、テストが失敗しました。
$ npm run build && npm test
FAIL test/devio.test.ts (10.078 s)
✕ Vpc (51 ms)
● Vpc
Template has 1 resources with type AWS::EC2::VPC, but none match as expected.
The 1 closest matches:
Vpc :: {
"Properties": {
"CidrBlock": "10.0.0.0/16",
"Tags": [
{
"Key": "Name",
!! Expected devio-stg-vpc but received undefined-undefined-vpc
"Value": "undefined-undefined-vpc"
}
]
},
"Type": "AWS::EC2::VPC"
}
11 |
12 | template.resourceCountIs('AWS::EC2::VPC', 1)
> 13 | template.hasResourceProperties('AWS::EC2::VPC', {
| ^
14 | CidrBlock: '10.0.0.0/16',
15 | Tags: [{ 'Key': 'Name', 'Value': 'devio-stg-vpc' }]
16 | });
at Template.hasResourceProperties (node_modules/aws-cdk-lib/assertions/lib/template.js:1:2556)
at Object.<anonymous> (test/devio.test.ts:13:12)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 10.285 s
Ran all test suites.
ブログに記載されている通り、テストでは Context の値が undefined
になっていました。
ブログ内の回避策も試したところ、テストは成功したのでテスト時には一工夫必要なこともわかりました。
まとめ
今回の手順でブログと大きく異なる点はありませんでした。
ただし、テスト時には一工夫必要でした。
次回は実践!AWS CDK #5 サブネット | DevelopersIO を実施します。
Discussion