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)