AWS CLI and CDK Setup Journey - Part 2
Continuing from yesterday, I'm diving deeper into AWS CLI and CDK setup today!
Yesterday's post π
https://dev.to/tofu1216/setting-up-aws-cli-and-cdk-2onp
Still following this awesome AWS official documentation:
https://docs.aws.amazon.com/cdk/v2/guide/hello-world.html
Here's my real experience going through Steps 5-12, including the bumps I hit along the way.
Step 5: Check Your CDK Stack List
Yesterday I got AWS CDK and local bootstrap all set up, so we're ready to deploy!
Let's check what Stacks we have (Stacks are basically how CDK groups and manages AWS resources together).
Run this command:
cdk list
You should see just one Stack:
HelloCdkStack
Step 6: Define Your Lambda Function
Time to update lib/hello-cdk-stack.ts
with this code:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
// Import the Lambda module
import * as lambda from 'aws-cdk-lib/aws-lambda';
export class HelloCdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define the Lambda function resource
const myFunction = new lambda.Function(this, "HelloWorldFunction", {
runtime: lambda.Runtime.NODEJS_20_X, // Provide any supported Node.js runtime
handler: "index.handler",
code: lambda.Code.fromInline(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
});
}
}
As Claude explained to me:
Constructs are basically AWS resources (like Lambda or S3) represented as TypeScript classes.
Think of them as blueprints that include settings and dependencies.
This Function construct needs three key arguments:
- scope: Where to place this function in the parent hierarchy (I'm still wrapping my head around this one - someone please help! π€²)
- id: Unique identifier for this function
-
props: The actual function settings
- runtime: The language and version Lambda runs on
- handler: Which function to execute
- code: The actual function code
Step 7: Define the Lambda Function URL
We'll use the Function
construct's addFunctionUrl
helper method to create a Lambda function URL. To output this URL value when we deploy, we'll create an AWS CloudFormation output using the CfnOutput
construct. (Still figuring this part out too, but apparently Lambda needs a URL to run!)
Add this code to lib/hello-cdk-stack.ts
:
export class HelloCdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define the Lambda function resource
// ...
// Define the Lambda function URL resource
const myFunctionUrl = myFunction.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
});
// Define a CloudFormation output for your URL
new cdk.CfnOutput(this, "myFunctionUrlOutput", {
value: myFunctionUrl.url,
})
}
}
Step 8: Synthesize the CloudFormation Template
Now let's run this command to convert our TypeScript code into a CloudFormation template:
cdk synth
If successful, you'll see the CloudFormation template output like this:
Resources:
HelloWorldFunctionServiceRole<unique-identifier>:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Metadata:
aws:cdk:path: HelloCdkStack/HelloWorldFunction/ServiceRole/Resource
HelloWorldFunction<unique-identifier>:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: "
\ exports.handler = async function(event) {
\ return {
\ statusCode: 200,
\ body: JSON.stringify('Hello World!'),
\ };
\ };
\ "
Handler: index.handler
Role:
Fn::GetAtt:
- HelloWorldFunctionServiceRole<unique-identifier>
- Arn
Runtime: nodejs20.x
DependsOn:
- HelloWorldFunctionServiceRole<unique-identifier>
Metadata:
aws:cdk:path: HelloCdkStack/HelloWorldFunction/Resource
HelloWorldFunctionFunctionUrl<unique-identifier>:
Type: AWS::Lambda::Url
Properties:
AuthType: NONE
TargetFunctionArn:
Fn::GetAtt:
- HelloWorldFunction<unique-identifier>
- Arn
Metadata:
aws:cdk:path: HelloCdkStack/HelloWorldFunction/FunctionUrl/Resource
HelloWorldFunctioninvokefunctionurl<unique-identifier>:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunctionUrl
FunctionName:
Fn::GetAtt:
- HelloWorldFunction<unique-identifier>
- Arn
FunctionUrlAuthType: NONE
Principal: "*"
Metadata:
aws:cdk:path: HelloCdkStack/HelloWorldFunction/invoke-function-url
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:<unique-identifier>
Metadata:
aws:cdk:path: HelloCdkStack/CDKMetadata/Default
Condition: CDKMetadataAvailable
Outputs:
myFunctionUrlOutput:
Value:
Fn::GetAtt:
- HelloWorldFunctionFunctionUrl<unique-identifier>
- FunctionUrl
Parameters:
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/<unique-identifier>/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
Now we're ready to deploy!
Step 9: Deploy the CDK Stack
Let's deploy our CDK stack! This takes the CloudFormation template we just generated and deploys it through AWS CloudFormation.
cdk deploy --profile your-profile-name
β οΈ Don't forget to specify your --profile!
Once it's done, head over to the AWS Console and check out your resources in both Lambda and CloudFormation.
How CloudFormation Templates and CDK Work Together π
Let me break down what's happening behind the scenes:
What is a CloudFormation Template?
- A file written in JSON/YAML format that describes AWS resource configurations
- Think of it as a blueprint that tells AWS "how to build what"
- AWS CloudFormation service reads this and creates the actual resources
What is CloudFormation?
- A service that reads JSON/YAML files and provisions actual AWS resources
- It's like a "converter/execution engine"
How CDK Works:
- CDK is a tool that includes CloudFormation service
- Write code in TypeScript
-
cdk synth
converts your program code into CloudFormation template (JSON/YAML format) -
cdk deploy
uses CloudFormation to deploy
Your CDK Code (TypeScript)
β cdk synth
CloudFormation Template (JSON)
β cdk deploy
CloudFormation Service (AWS)
β executes
Actual AWS Resources (Lambda, etc.)
Step 10: Test Your Application
Use the URL that was displayed when you ran the cdk deploy
command to test your function:
curl https://<api-id>.lambda-url.<Region>.on.aws/
Here's my actual execution - it worked perfectly! π
Step 11: Make Changes to Your Application
Let's modify our Lambda code a bit. I changed myFunction
like this:
// Define the Lambda function resource
const myFunction = new lambda.Function(this, "HelloWorldFunction", {
runtime: lambda.Runtime.NODEJS_20_X, // Provide any supported Node.js
handler: "index.handler",
code: lambda.Code.fromInline(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello CDK I'm AWS Lambda!!'),
};
};
`),
});
To preview your changes, run:
cdk diff --profile your-profile-name
Then deploy again:
cdk deploy --profile your-profile-name
And test the URL again:
curl https://<api-id>.lambda-url.<Region>.on.aws/
But here's where I hit a snag:
Internal Server Error%
I checked the Lambda function logs in CloudWatch and found a syntax error!
Turns out the culprit was the apostrophe in I'm
! Since I was using single quotes to wrap the string, the '
in I'm
was being interpreted as the end of the string, causing a syntax error. Changed it to I am
and everything worked perfectly! βοΈ
Step 12: Clean Up Your Application
Finally, let's clean up. This command will delete all the resources we created:
cdk destroy --profile your-profile-name
Run the command and check the AWS Console. The Lambda function should be gone.
In CloudFormation, you'll notice the stack is still there. Apparently this is normal behavior. If you're not using CDK anymore, you might want to delete it manually.
If you do delete it, you can always bring it back with:
cdk bootstrap --profile your-profile-name
Wrap Up
That's it! AWS CDK setup is complete. Now if I set up CDK in other environments within IAM Identity Center, I can easily switch between environments using command line profiles.
This is incredibly convenient!!
See you tomorrow! π
Top comments (0)