CreatHoing an aws instance in windows and setup
how aws cdk generates code
cdk Code —synth-> CF Template —deploy->AWS CF
1)Need to create an account in aws
2)Add the creds
3)Go to Identity and Access Management (IAM)
4)Click on users and create a user giving any random name give policy access and give administrator access
5)Add aws cli interface in the system
6)Check version with aws —v and also add aws configure
7)Paste the access id and secret key and also default region, with json format
8)Check with command aws s3 -l, to check the right installation, done
Installation of cdk
1)bun i -g aws-cdk
2)check version cdk —v
Initialisiing a cdk-aws
1)cdk init
Note:- Contains 3 types, 1)app, sample-app,bin(inside it there is cdk-starter.ts , which initialies our application),lib(which has cdk-starter-stack.ts which has actual Cloud Formation stacks), cdk.json configures the file
2)cdk init —language=typescipt
To deploy the cdk
1)cdk bootstrap (because cdk requires some preparation and these preparations are given by bootstrap command or require some resources to run the bucket or take it as a staging bucket and this bucket will contain the files required by aws-cdk in order to deploy)
2)cdk deploy
note- it will create a new folder cdk.out and also some files which will contain the cloud formation template that is actually deployed
2a)cdk synth - will only generate a template that is required by cloud formation template exactly like cdk deploy ,it checks if CF is valid formation and will not deploy anything
3)Check in the cloud formation
4)Note cdk.out will be created and the files inside will be deployed to aws cdk formation cloud
Note - cdk synth will only generate a template
Note- aws cloud formation stack cant be deleted because first we need to empty s3 bucket, and then delete the stack
CDK Constructs
-cdk constructs are basic building blocks of cdk application
-3 types of constructs are there,
1)Level 1 — offers no abstraction need to configure everything
2)Level 2 — preferably used, offers additional functionality, offers high level of abstraction, lot of bolier plate code and safety for many parameters
3)Level 3 — commonly called patterns , combine multiple types of resources and help with the common tasks in aws, this is used for prefernce of company policy
Creating a demo cdk with three options
import * as cdk from "aws-cdk-lib";
import { CfnOutput, CfnParameter, Duration } from "aws-cdk-lib";
import { Bucket, CfnBucket } from "aws-cdk-lib/aws-s3";
import { Construct } from "constructs";
class L3Bucket extends Construct { // Construct is a class, we will either override or use existing interface
constructor(scope: Construct, id: string, expiration: number) {
super(scope, id);
new Bucket(this, "L3Bucket", {
lifecycleRules: [
{
expiration: Duration.days(expiration),
},
],
});
}
}
export class CdkStarterStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
//create a s3 bucket 3 ways
//this is the L1 way by adding CfnBucket from aws-cdk
new CfnBucket(this, "MyL1Bucket", {
lifecycleConfiguration: {
rules: [
{
expirationInDays: 1,
status: "Enabled", // if the typo is wrong, if it is added enabled to Enabled
},
],
},
});
// this is the L2 way and bucket refers to cdkStarterStack and this refers to scope
new Bucket(this, "MyL2Bucket", {
lifecycleRules: [
{
expiration: Duration.days(2),
},
],
});
// this is the L3 way of constructing a bucket
new L3Bucket(this, "MyL3Bucket", 3);
}
}
Note- the name of the resources is the same as Physical ID
adding just
value: myL2Bucket.bucketName,
Above command will not give the right bucket name
right way to call is
new CfnOutput(this, "myL2BucketName", { value: myL2Bucket.bucketName, description: "The name of the L2 bucket", });
The above command will be give the name of the bucket and this will be shown in the cloud formation by clicking on output as
key: myL2Bucket.bucketName,
value: cdkStarterStack-myL2Bucket(somerandomId)
CfnParameter → we can add the parameters for like expiration date shown below
const duration = new CfnParameter(this, "duration", {
default: 6,
minValue: 1,
maxValue: 10,
type: "Number", // add upper case letters only
});
// initial way
const myL2Bucket = new Bucket(this, "MyL2Bucket", {
lifecycleRules: [
{
expiration: Duration.days(duration.valueAsNumber),
},
],
});
Note: cdk deploy —parameter duartion=11,will throw error, as maxValue is 10
Note: When even stack is deleted , l2 and L3 buckets are not deleted because cdk generates L2 and L3 bucket with different retention policy, as also will have a orphaned policy.
In order to delete it L2 and L3 , clean up the policies in s3 and delete it
Logical Id is required by CLoud Formation to identify Cloud Formation , Physical IDs required by aws, when we reference outside the Cloud Formation we reference it by Physical ID, it is same as ARN(Amazon Resource Name)
Note- If we change the logical id, it will create the new resource and delete the old one, and also will loose data, and get error like photobucket already exists in stack.
// another way to override the logical id // (myBucket.node.defaultChild as CfnBucket).overrideLogicalId( // "PhotosBucket42425" // );
Intrinsic Functions
—> buildin functions to help manage our stacks
Why we need for multiple stacks
—>Some stacks may contain sensitive info(IAM roles, secrets,…)
—>Some stacks may take a lot of time for deployment od deletion
—>Resources get big and the need organization
How to organize stacks
—>There are no documented rules, not even best practices
—> Separate stacks with resources with state(databases,buckets)
—>Separate stacks for IAM roles, policies, secrets
—> Separate stacks for resources with complex initializattion (VPCs, DNS)
*Lambda fn:→ it is a basic function that aws cdk uses to run the code, example of lambda fucntion below
import {
Code,
Function as LambdaFunction,
Runtime,
} from "aws-cdk-lib/aws-lambda";
// referencing from other file
// this is written in other stack CfnOutput
new CfnOutput(this, "photos-bucket", {
value: photosBucket.bucketArn,// the value will get from target function below
exportName: "photos-bucket",
});
// lambda function requires a reference to the bucket
const targetBucket = cdk.Fn.importValue("photos-bucket");
// this is a helper function to get the suffix of the stack and give meaningful name to the stack and also no collision with other stacks
new LambdaFunction(this, "PhotoHandler", {
runtime: Runtime.NODEJS_20_X,
handler: "index.handler",
code: Code.fromInline(
`exports.handler = async (event) => {
console.log("hello!:zxzxzxz", + process.env.TARGET_BUCKET);
}`
),
environment: {
TARGET_BUCKET: targetBucket,
},
});
cdk deploy will not deploy the stack , even if we write cdk deploy —all because the cdk will first deploy the PhotoHandlerStack and bucket doesnt exist as there is no export name photos-buckets found, so in order to solve this deploy each other separately like cdk deploy photosStack and photoHandlerStack
Sharing resources with stack example
#!/usr/bin/env node
// initialize the app
import * as cdk from "aws-cdk-lib";
import { PhotosHandlerStack } from "../lib/PhotoHandlerStack";
import { PhotosStack } from "../lib/PhotoStack";
const app = new cdk.App();
const photosStack = new PhotosStack(app, "PhotosStack"); // this is the stack that creates the bucket
new PhotosHandlerStack(app, "PhotosHandlerStack", {
targetBucketArn: photosStack.photosBucketArn,
}); // this is the stack that puts data or resources to the bucket
import * as cdk from "aws-cdk-lib";
import {
Code,
Function as LambdaFunction,
Runtime,
} from "aws-cdk-lib/aws-lambda";
import { Construct } from "constructs";
interface PhotosHandlerStackProps extends cdk.StackProps {
targetBucketArn: string;
}
export class PhotosHandlerStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: PhotosHandlerStackProps) {
super(scope, id, props);
// lambda function requires a reference to the bucket
// const targetBucket = cdk.Fn.importValue("photos-bucket");
// this is a helper function to get the suffix of the stack and give meaningful name to the stack and also no collision with other stacks
new LambdaFunction(this, "PhotoHandler", {
runtime: Runtime.NODEJS_20_X,
handler: "index.handler",
code: Code.fromInline(
`exports.handler = async (event) => {
console.log("hello!:zxzxzxz", + process.env.TARGET_BUCKET);
}`
),
environment: {
TARGET_BUCKET: props.targetBucketArn,
},
});
}
}
import * as cdk from "aws-cdk-lib";
import { Bucket } from "aws-cdk-lib/aws-s3";
import { Construct } from "constructs";
export class PhotosStack extends cdk.Stack {
private stackSuffix: string;
public readonly photosBucketArn: string;
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
this.initializeSuffix();
const photosBucket = new Bucket(this, "PhotosBucket", {
bucketName: `photos-bucket-${this.stackSuffix}`,
});
this.photosBucketArn = photosBucket.bucketArn;
// another way to override the logical id
// (myBucket.node.defaultChild as CfnBucket).overrideLogicalId(
// "PhotosBucket42425"
// );
/// create a new resource
// delete the old one
// new CfnOutput(this, "photos-bucket", {
// value: photosBucket.bucketArn,
// exportName: "photos-bucket",
// });
}
// this is a helper function to get the suffix of the stack and give meaningful name to the stack and also no collision with other stacks
private initializeSuffix() {
// Fn is a intrinsic function in cdk
const shortStackId = cdk.Fn.select(2, cdk.Fn.split("/", this.stackId));
this.stackSuffix = cdk.Fn.select(4, cdk.Fn.split("-", shortStackId));
}
}
cdk aspects
—> check or modify resources after they were created
—> visitor pattern
—> simple usecases: add tags
—> popular usecase : enforce security or best practices
Basic Lambda with our own policies and deployment and stacks example below
import { Stack, StackProps } from "aws-cdk-lib";
import {
Code,
Function as LambdaFunction,
Runtime,
} from "aws-cdk-lib/aws-lambda";
import { Construct } from "constructs";
import { join } from "path";
export class LambdaStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props); // inheriting from the parent class to child class
new LambdaFunction(this, "HelloLambda", {
runtime: Runtime.NODEJS_LATEST, // NODEJS can be used any like 18,19,20,21,22
handler: "hello.main",// this is referenced from the js file in services
code: Code.fromAsset(join(__dirname, "../../", "services")),// make sure that the path is right, otherwise cdk synth will not work
});
}
}
Note:- once we deploy using cdk deploy—all, cdk will automatically generate some IAM rights by itself
API Gateway- it is a simple resource where we can access internet, rest api, websocket api, web api etc.,