コンテキスト値と AWS CDK - AWS Cloud Development Kit (AWS CDK) v2

これは AWS CDK v2 開発者ガイドです。旧版の CDK v1 は 2022 年 6 月 1 日にメンテナンスを開始し、2023 年 6 月 1 日にサポートを終了しました。

コンテキスト値と AWS CDK

コンテキスト値は、アプリ、スタック、またはコンストラクトに関連付けることのできるキーと値のペアです。これらは、ファイル (通常はプロジェクトディレクトリ内の cdk.json または cdk.context.json) またはコマンドラインからアプリに提供できます。

CDK Toolkit は、コンテキストを使用して、合成中に AWS アカウントから取得した値をキャッシュします。値には、アカウントのアベイラビリティーゾーン、または Amazon EC2 インスタンスで現在利用可能な Amazon マシンイメージ (AMI) ID が含まれます。これらの値は AWS アカウントによって提供されるため、CDK アプリケーションの実行ごとに変更される可能性があります。これにより、意図しない変更が発生する可能性があります。CDK Toolkit のキャッシュ動作は、新しい値を受け入れることを決定するまで、CDK アプリのこれらの値を「凍結」します。

コンテキストキャッシュを無効にした場合の以下のシナリオを想像してください。Amazon EC2 インスタンスの AMI として「最新の Amazon Linux」を指定し、この AMI の新しいバージョンがリリースされたとします。そうすると、次に CDK スタックをデプロイするときには、デプロイ済みのインスタンスが古い (「間違った」) AMI を使用していることになるため、アップグレードが必要になります。アップグレードすると、既存のすべてのインスタンスが新しいインスタンスに置き換えられますが、これはおそらく予期せぬ望ましくない結果でしょう。

そうする代わりに、CDK はアカウントで使用可能な AMI をプロジェクトの cdk.context.json ファイルに記録し、今後合成オペレーションに保存された値を使用します。これにより、AMI のリストは潜在的な変更の原因ではなくなります。また、スタックが常に同じ AWS CloudFormation テンプレートに合成されるようにもできます。

すべてのコンテキスト値が AWS 環境からのキャッシュ値あるとは限りません。AWS CDK 機能フラグ もまたコンテキスト値です。また、アプリケーションやコンストラクトで使用する独自のコンテキスト値を作成することもできます。

コンテキストキーは文字列です。値は、数値、文字列、配列、オブジェクトなど、JSON でサポートされている任意のタイプにすることができます。

ヒント

コンストラクトが独自のコンテキスト値を作成する場合は、ライブラリのパッケージ名をキーに組み込み、他のパッケージのコンテキスト値と競合しないようにします。

多くのコンテキスト値は特定の AWS 環境に関連付けられており、特定の CDK アプリは複数の環境にデプロイできます。このような値のキーには、異なる環境の値が競合しないように、AWS アカウントと リージョンが含まれます。

以下のコンテキストキーは、アカウントとリージョンを含む、AWS CDK で使用される形式を示しています。

availability-zones:account=123456789012:region=eu-central-1
重要

キャッシュされたコンテキスト値は、AWS CDK とそのコンストラクトによって管理されます。これには、書き込み可能なコンストラクトも含まれます。ファイルを手動で編集することで、キャッシュされたコンテキスト値を追加または変更してはなりません。ただし、キャッシュされている値を確認するために時々 cdk.context.json を確認することは有用です。キャッシュされた値を表さないコンテキスト値は、cdk.jsoncontext キーの下に保存する必要があります。これにより、キャッシュ値がクリアされたときでもそれらはクリアされません。

コンテキスト値のソース

コンテキスト値を AWS CDK アプリに提供する方法は、以下の 6 つです。

  • 現在の AWS アカウントから自動的に

  • cdk コマンドの --context オプションを通して (これらの値は常に文字列です)

  • プロジェクトの cdk.context.json ファイル

  • プロジェクトの cdk.json ファイルの context キー

  • ~/.cdk.json ファイルの context キー

  • AWS CDK アプリで construct.node.setContext() メソッドを使用して

プロジェクトファイル cdk.context.json は、AWS アカウントから取得したコンテキスト値を AWS CDK がキャッシュする場所です。この方法により、新しいアベイラビリティーゾーンが導入されるなど、デプロイに予期しない変更が加えられるのを回避できます。AWS CDK は、リストされている他のファイルのいずれにもコンテキストデータを書き込みません。

重要

これらはアプリケーションの状態の一部であるため、cdk.jsoncdk.context.json は、アプリケーションのソースコードの残りの部分とともにソース管理にコミットする必要があります。そうしないと、他の環境 (CI パイプラインなど) にデプロイするとき、一貫性のない結果が生じる可能性があります。

コンテキスト値は、それらを作成したコンストラクトにスコープされます。子コンストラクトには表示されますが、親や兄弟には表示されません。AWS CDK Toolkit (cdk コマンド) によって設定されるコンテキスト値は、ファイルまたは --context オプションから自動的に設定できます。これらのソースのコンテキスト値は、App コンストラクトに暗黙的に設定されます。したがって、これらはアプリケーション内のすべてのスタックのすべてのコンストラクトに表示されます。

アプリケーションは、construct.node.tryGetContext メソッドを使用してコンテキスト値を読み取ることができます。リクエストされたエントリが現在のコンストラクトまたはその親のいずれにも見つからない場合、結果は undefined になります。(または、Python の None のように、使用言語での同等の値が得られる場合もあります。)

context メソッド

AWS CDK は、AWS CDK アプリケーションが AWS 環境からコンテキスト情報を取得できるようにする、いくつかのコンテキストメソッドをサポートしています。たとえば、Stack.availabilityZones メソッドを使用して、特定の AWS アカウントとリージョンで利用可能なアベイラビリティーゾーンのリストを取得できます。

コンテキストメソッドは以下のとおりです。

HostedZone.fromLookup

アカウントのホストゾーンを取得します。

stack.availabilityZones

サポートされているアベイラビリティーゾーンを取得します。

StringParameter.valueFromLookup

現在のリージョンの Amazon EC2 Systems Manager パラメータストアから値を取得します。

Vpc.fromLookup

アカウント内の既存の Amazon Virtual Private Clouds を取得します。

LookupMachineImage

Amazon Virtual Private Cloud の NAT インスタンスで使用するマシンイメージを検索します。

必要なコンテキスト値が使用できない場合、AWS CDK アプリケーションはコンテキスト情報が欠落していることを CDK Toolkit に通知します。次に、CLI は現在の AWS アカウントに情報についてのクエリを実行し、結果のコンテキスト情報を cdk.context.json ファイルに保存します。次に、コンテキスト値を使用して AWS CDK アプリケーションを再度実行します。

コンテキストの表示と管理

cdk context コマンドを使用して、cdk.context.json ファイル内の情報を表示および管理します。この情報を表示するには、オプションなしで cdk context コマンドを使用します。出力は以下のようになります。

Context found in cdk.json:

┌───┬─────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────┐
│ # │ Key                                                         │ Value                                                   │
├───┼─────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ 1 │ availability-zones:account=123456789012:region=eu-central-1 │ [ "eu-central-1a", "eu-central-1b", "eu-central-1c" ]   │
├───┼─────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ 2 │ availability-zones:account=123456789012:region=eu-west-1    │ [ "eu-west-1a", "eu-west-1b", "eu-west-1c" ]            │
└───┴─────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────┘

Run cdk context --reset KEY_OR_NUMBER to remove a context key. If it is a cached value, it will be refreshed on the next cdk synth.

コンテキスト値を削除するには、値に対応するキーまたは数値を指定して cdk context --reset を実行します。以下の例では、前の例の 2 番目のキーに対応する値を削除します。この値は、欧州 (アイルランド) リージョンのアベイラビリティーゾーンのリストを表します。

cdk context --reset 2
Context value
availability-zones:account=123456789012:region=eu-west-1
reset. It will be refreshed on the next SDK synthesis run.

したがって、Amazon Linux AMI の最新バージョンに更新する場合は、前の例を使用してコンテキスト値の制御された更新を行い、リセットします。次に、アプリを合成して再度デプロイします。

cdk synth

アプリケーションの保存されたコンテキスト値をすべてクリアするには、以下のように cdk context --clear を実行します。

cdk context --clear

リセットまたはクリアできるのは、cdk.context.json に保存されているコンテキスト値のみです。AWS CDK は他のコンテキスト値には触れません。したがって、これらのコマンドを使用してコンテキスト値がリセットされないように保護するために、値を cdk.json にコピーできます。

AWS CDK ツールキットの --context フラグ

--context (略して -c) オプションを使用して、合成またはデプロイ中にランタイムコンテキスト値を CDK アプリケーションに渡します。

cdk synth --context key=value MyStack

複数のコンテキスト値を指定するには、--context オプションを何回でも繰り返し、毎回 1 つのキーと値のペアを指定します。

cdk synth --context key1=value1 --context key2=value2 MyStack

複数のスタックを合成すると、指定されたコンテキスト値がすべてのスタックに渡されます。個々のスタックに異なるコンテキスト値を指定するには、値に異なるキーを使用するか、複数の cdk synth コマンドまたは cdk deploy コマンドを使用します。

コマンドラインから渡されるコンテキスト値は、常に文字列です。通常、値が他のタイプである場合は、コードを変換または解析する準備を整える必要があります。文字列以外のコンテキスト値は、他の方法 (cdk.context.json など) で提供される場合があります。この種の値が期待どおりに動作することを確認するには、変換する前に値が文字列であることを確認します。

AWS CDK コンテキストを使用して既存の Amazon VPC を使用する例を以下に示します。

TypeScript
import * as cdk from 'aws-cdk-lib'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import { Construct } from 'constructs'; export class ExistsVpcStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const vpcid = this.node.tryGetContext('vpcid'); const vpc = ec2.Vpc.fromLookup(this, 'VPC', { vpcId: vpcid, }); const pubsubnets = vpc.selectSubnets({subnetType: ec2.SubnetType.PUBLIC}); new cdk.CfnOutput(this, 'publicsubnets', { value: pubsubnets.subnetIds.toString(), }); } }
JavaScript
const cdk = require('aws-cdk-lib'); const ec2 = require('aws-cdk-lib/aws-ec2'); class ExistsVpcStack extends cdk.Stack { constructor(scope, id, props) { super(scope, id, props); const vpcid = this.node.tryGetContext('vpcid'); const vpc = ec2.Vpc.fromLookup(this, 'VPC', { vpcId: vpcid }); const pubsubnets = vpc.selectSubnets({subnetType: ec2.SubnetType.PUBLIC}); new cdk.CfnOutput(this, 'publicsubnets', { value: pubsubnets.subnetIds.toString() }); } } module.exports = { ExistsVpcStack }
Python
import aws_cdk as cdk import aws_cdk.aws_ec2 as ec2 from constructs import Construct class ExistsVpcStack(cdk.Stack): def __init__(scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) vpcid = self.node.try_get_context("vpcid") vpc = ec2.Vpc.from_lookup(self, "VPC", vpc_id=vpcid) pubsubnets = vpc.select_subnets(subnetType=ec2.SubnetType.PUBLIC) cdk.CfnOutput(self, "publicsubnets", value=pubsubnets.subnet_ids.to_string())
Java
import software.amazon.awscdk.CfnOutput; import software.amazon.awscdk.services.ec2.Vpc; import software.amazon.awscdk.services.ec2.VpcLookupOptions; import software.amazon.awscdk.services.ec2.SelectedSubnets; import software.amazon.awscdk.services.ec2.SubnetSelection; import software.amazon.awscdk.services.ec2.SubnetType; import software.constructs.Construct; public class ExistsVpcStack extends Stack { public ExistsVpcStack(Construct context, String id) { this(context, id, null); } public ExistsVpcStack(Construct context, String id, StackProps props) { super(context, id, props); String vpcId = (String)this.getNode().tryGetContext("vpcid"); Vpc vpc = (Vpc)Vpc.fromLookup(this, "VPC", VpcLookupOptions.builder() .vpcId(vpcId).build()); SelectedSubnets pubSubNets = vpc.selectSubnets(SubnetSelection.builder() .subnetType(SubnetType.PUBLIC).build()); CfnOutput.Builder.create(this, "publicsubnets") .value(pubSubNets.getSubnetIds().toString()).build(); } }
C#
using Amazon.CDK; using Amazon.CDK.AWS.EC2; using Constructs; class ExistsVpcStack : Stack { public ExistsVpcStack(Construct scope, string id, StackProps props) : base(scope, id, props) { var vpcId = (string)this.Node.TryGetContext("vpcid"); var vpc = Vpc.FromLookup(this, "VPC", new VpcLookupOptions { VpcId = vpcId }); SelectedSubnets pubSubNets = vpc.SelectSubnets([new SubnetSelection { SubnetType = SubnetType.PUBLIC }]); new CfnOutput(this, "publicsubnets", new CfnOutputProps { Value = pubSubNets.SubnetIds.ToString() }); } }

cdk diff を使用して、コマンドラインでコンテキスト値を渡す効果を確認できます。

cdk diff -c vpcid=vpc-0cb9c31031d0d3e22
Stack ExistsvpcStack
Outputs
[+] Output publicsubnets publicsubnets: {"Value":"subnet-06e0ea7dd302d3e8f,subnet-01fc0acfb58f3128f"}

結果のコンテキスト値は、ここに示すように表示できます。

cdk context -j
{
  "vpc-provider:account=123456789012:filter.vpc-id=vpc-0cb9c31031d0d3e22:region=us-east-1": {
    "vpcId": "vpc-0cb9c31031d0d3e22",
    "availabilityZones": [
      "us-east-1a",
      "us-east-1b"
    ],
    "privateSubnetIds": [
      "subnet-03ecfc033225be285",
      "subnet-0cded5da53180ebfa"
    ],
    "privateSubnetNames": [
      "Private"
    ],
    "privateSubnetRouteTableIds": [
      "rtb-0e955393ced0ada04",
      "rtb-05602e7b9f310e5b0"
    ],
    "publicSubnetIds": [
      "subnet-06e0ea7dd302d3e8f",
      "subnet-01fc0acfb58f3128f"
    ],
    "publicSubnetNames": [
      "Public"
    ],
    "publicSubnetRouteTableIds": [
      "rtb-00d1fdfd823c82289",
      "rtb-04bb1969b42969bcb"
    ]
  }
}