Amazon Web Services Cloud Development Kit (AWS CDK) is a powerful infrastructure-as-code (IaC) framework that allows developers to define cloud infrastructure using familiar programming languages. One essential concept within AWS CDK that plays a crucial role in configuring and customizing your infrastructure is "context." In this blog post, we will delve into the significance of context in AWS CDK and how it contributes to the flexibility and scalability of your cloud applications.
Context in AWS CDK
In AWS CDK, context refers to the external input provided during the synthesis phase of your application. This external input can be environmental variables, resource-specific configurations, or any changing parameter based on the deployment environment. Context allows you to dynamically adjust certain values in your CDK application without modifying the source code.
Using Context at the App Level
In this example we will set the context at our CDK App level:
import { Stack, StackProps, App } from 'aws-cdk-lib';
export class MyCdkStack extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);
console.log('accessing context here ', this.node.tryGetContext('fromApp'));
}
}
const app = new App({
// setting context in our cdk.App
context: {
fromApp: {name: 'Mikaeel', country: 'BE'},
},
});
const myStack = new MyCdkStack(app, 'my-cdk-stack', {
stackName: `my-cdk-stack`,
env: {
region: process.env.CDK_DEFAULT_REGION,
account: process.env.CDK_DEFAULT_ACCOUNT,
},
});
Let's synthesize our stack and look at the output:
cdk synth
We can see the output from the console.log
:
{ name: 'Mikaeel', country: 'BE' }
Context Managed by CDK
Now take a quick look at how CDK uses context to cache certain values that belong to our deployment environment.
If we open the cdk.context.json
file in the root directory of our CDK project, we can see that it's empty.
{}
Let's add a simple console.log
call and print the availability zones that belong to the region our stack is configured for:
import { Stack, StackProps, App } from 'aws-cdk-lib';
export class MyCdkStack extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);
console.log('context passed in App here ', this.node.tryGetContext('fromApp'));
// printing the availability zones
console.log(Stack.of(this).availabilityZones);
}
}
Now synthesize our stack with:
cdk synth
If we now open the cdk.context.json
file in the root of our project we'll see that CDK has cached the availability zones that correspond to our stack's region:
{
"availability-zones:account=123456789:region=us-east-1": [
"us-east-1a",
"us-east-1b",
"us-east-1c",
"us-east-1d",
"us-east-1e"
]
}
The cdk.context.json
file is where CDK caches values related to our deployment environment.
There is also a cdk.json file in the root directory of a CDK project.
The cdk.json
file looks similar to the following:
{
"app": "npx ts-node --prefer-ts-exts bin/aws-cdk-group-chat-app.ts",
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
]
}
}
Where the app
key indicates to the CDK CLI how to run our CDK code, which is mostly a compilation step that compiles the typescript code to javascript.
Then we have the context
key, which is composed of feature flags.
These feature flags enable us to opt in or out of breaking changes. Their names start with the name of the package that introduces the breaking change i.e:@aws-cdk/aws-lambda
.
false
.We can also use the cdk.json
file to pass in context into our CDK app, let's add another property to it:
{
"app": "npx ts-node --prefer-ts-exts bin/aws-cdk-group-chat-app.ts",
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
// adding a bucket property as context
"bucket": {
"region": "us-east-1",
"name": "my-s3-bucket"
}
}
}
Now let's access the bucket context in our CDK stack:
import { Stack, StackProps, App } from 'aws-cdk-lib';
export class MyCdkStack extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);
console.log('from cdk.json ', this.node.tryGetContext('bucket'));
}
}
Let's synth our cdk stack:
cdk synth
The output from the console.log
will look like this:
{ "region": "us-east-1", "name": "my-s3-bucket" }
Setting Context using the CDK CLI
The next option used for setting context in our CDK app is to use the CDK CLI.
We can set context key-value pairs during synthesis.
First, we'll access context values that we haven't yet set:
import { Stack, StackProps, App } from 'aws-cdk-lib';
export class MyCdkStack extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);
console.log('bucketName ', this.node.tryGetContext('bucketName'));
console.log('region ', this.node.tryGetContext('region'));
}
}
Now we'll synth the CDK application passing in the context values using the CLI:
cdk synth \
--context bucketName=myBucket \
--context region=us-east-1
The output from our console.log
statements will look like this.
bucketName myBucket
region us-east-1
string
values when we set the context using the CDK CLI. If we have to pass an object, we have to pass it as a string
and parse it in our application code.If we have multiple CDK stacks and want to set different context values using the CDK CLI, we can prefix the key-value pairs with the stack name, i.e.:
cdk synth \
--context stack-name1:bucketName=myBucket \
--context stack-name2:bucketName=yourBucket
Conclusion
Context is a combination of key-value pairs we can set and make available in our CDK application.
Context is similar to environment variables, in that both are accessible in synthesis time, as opposed to CDK parameters, which are only set at deployment time.
The most common ways to set context are:
At the CDK App level using the
context
propertyIn our
cdk.json
file adding key-value pairs to thecontext
objectUsing the CDK CLI with the
--context
flag
In our CDK applications, we can access the context values with a call tothis.node.tryGetContext('keyName')
.
CDK App level
, it's globally available, it's intuitive and we can set context values of any type.Setting context using the cdk.json
file is too implicit and hidden.
An alternative is using the CDK CLI, however, the CLI only allows us to pass in string values, so the most intuitive way is setting context at the cdk.App
level.