実践!AWS CDK #4 Context
はじめに
今回は AWS CDK の Context について学んでいきましょう。
簡単に言うとこれは CFn の パラメータ のように使える機能です。
前回の記事はこちら。
Context とは
ざっくり解説。
- スタックや Construct に関連付けできるキーと値のペア
- キーと値の型は
string
- 他の型にしたい場合は変換処理が必要
- 6 つ の異なる方法で CDK アプリに提供される
- 現在の AWS アカウントから自動的に
- CDK コマンドの
--context
オプション - プロジェクトの
cdk.context.json
ファイル - プロジェクトの
cdk.json
ファイル ~/.cdk.json
ファイルのcontext
キーconstruct.node.setContext
メソッド
この機能を利用してシステム名や環境を動的に変更してみましょう。
パラメータじゃダメなの?
ダメです。Context を使いましょう。
CfnParameter というクラスも存在するのですが、AWS 公式から 非推奨 というお言葉をいただいております。
In general, we recommend against using AWS CloudFormation parameters with the AWS CDK. Unlike context values or environment variables, the usual way to pass values into your AWS CDK apps without hard-coding them, parameter values are not available at synthesis time, and thus cannot be easily used in other parts of your AWS CDK app, particularly for control flow.
not available at synthesis time、つまり cdk synth
コマンド実行時に値が取得できません。(cdk deploy
コマンド実行時には取得できるのですが)
それでもオレはパラメータを使いたいんだ!という方は以下のリンクから利用方法を習得してください。
私は Context を使います。
使い方
ここから Context の利用方法を見ていきましょう。
値の設定
本シリーズでは次の方法で値を設定していきます。
- プロジェクトの
cdk.json
ファイル- デフォルト値の設定に利用
- このファイルはプロジェクト作成時に自動生成される(既にある)
- CDK コマンドの
--context
オプション- デフォルト値以外の設定に利用
cdk synth
やcdk deploy
実行時に使用する-c
でも可
値の取得
値の取得には以下のメソッドを利用します。
construct.node.tryGetContext
先頭の construct
はインスタンスです。上記 6 つの方法はいずれも暗黙的に App Construct に設定されるため、アプリ内のすべての Construct インスタンスで Context の値を取得することができます。
また、値を取得できなかった場合の結果は undefined
となります。
実装
では実際に値の設定と取得を試してみましょう。
cdk.json
を以下のように編集します。
既にいくつか値が設定されているところに追記します。(14 行目の行末カンマもお忘れなく)
{ "app": "npx ts-node --prefer-ts-exts bin/devio.ts", "context": { "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, "@aws-cdk/core:enableStackNameDuplicates": "true", "aws-cdk:enableDiffNoFail": "true", "@aws-cdk/core:stackRelativeExports": "true", "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, "@aws-cdk/aws-kms:defaultKeyPolicies": true, "@aws-cdk/aws-s3:grantWriteWithoutAcl": true, "@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true, "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, "@aws-cdk/aws-efs:defaultEncryptionAtRest": true, "systemName": "devio", "envType": "stg" } }
これがデフォルト値となります。
次にコードを修正します。
import * as cdk from '@aws-cdk/core'; import { CfnVPC } from '@aws-cdk/aws-ec2'; export class DevioStack extends cdk.Stack { constructor(scope: cdk.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` }] }); } }
これでリソース名に設定していた システム名
と 環境
が動的に変更可能となりました。
確認
まずは cdk synth
コマンドを実行してみましょう。
$ cdk synth Resources: Vpc: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 Tags: - Key: Name Value: devio-stg-vpc ~ 省略 ~
デフォルト値が取得され、リソース名が正しく設定されています。
次に --context
オプションありで cdk synth
コマンドを実行してみます。
$ 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 ~ 省略 ~
すばらしい!
きちんと指定したとおりにプログラムが動いていますね。
デプロイ時にも適用する場合は cdk deploy
コマンドに同じオプションを指定してください。
このように CFn でいうパラメータのように利用できる機能が、今回ご紹介した Context
となります。
注意
この Context ですが、テスト実行時には値が取得できません。(cdk.json
が読み込まれないようです)
また、テストの実行は npm
コマンドであり cdk
のコマンドではないため --context
オプションも当然ながらサポートされていません。よってテスト時の Context の値は undefined
が来ることを想定したものにしましょう。
VPC のテストの場合はこのような形になります。
test('Vpc', () => { const app = new cdk.App(); const stack = new Devio.DevioStack(app, 'DevioStack'); expect(stack).to(countResources('AWS::EC2::VPC', 1)); expect(stack).to(haveResource('AWS::EC2::VPC', { CidrBlock: '10.0.0.0/16', Tags: [{ 'Key': 'Name', 'Value': 'undefined-undefined-vpc' }] })); });
少し気持ち悪いですが、ここは我慢するしかなさそうです。
どうしてもテスト時に Context を設定したい場合は cdk.App()
のイニシャライザーに Context を指定することができます。これを利用した Context 用のテストコードを 1 つ追加し、今回はおしまいにしたいと思います。
test('Context', () => { const app = new cdk.App({ context: { 'systemName': 'starwars', 'envType': 'prd' } }); const stack = new Devio.DevioStack(app, 'DevioStack'); expect(stack).to(haveResource('AWS::EC2::VPC', { Tags: [{ 'Key': 'Name', 'Value': 'starwars-prd-vpc' }] })); });
GitHub
今回のソースコードは コチラ です。
おわりに
今回は Context
というこちらも AWS CDK ならではの機能紹介でした。CFn と違う部分はありますが、実際に使っていきながら徐々に慣れていきたいと思います。
さて、ベースが固まってきたので環境構築を再開していきましょう。
次回のお題は「サブネット
」です。