This is a hands-on guide for AWS CDK created with ChatGPT. It may contain errors.
Chapter 1: Introduction
In this book, we will learn AWS CDK v2 using Python, through practical, code-driven exercises. Yukkuri characters will appear as friendly guides throughout the text.
1.1 What is Infrastructure as Code (IaC)?
📘 Technical Explanation
Infrastructure as Code (IaC) is the practice of managing cloud infrastructure using source code instead of clicking through the AWS console.
Key Characteristics
- Automatable
- Repeatable
- Version-controlled
- Testable and reviewable
- Enables CI/CD and DevOps practices
Example: instead of clicking to create an EC2 instance, we express it in code.
from aws_cdk import ( Stack, aws_ec2 as ec2, ) from constructs import Construct class SimpleServerStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) ec2.Instance( self, "ExampleInstance", instance_type=ec2.InstanceType("t3.micro"), machine_image=ec2.MachineImage.latest_amazon_linux(), vpc=ec2.Vpc.from_lookup(self, "DefaultVPC", is_default=True) )
🗣️ Yukkuri Commentary
Reimu: So IaC means we stop clicking buttons?
Marisa: Yes! Clicking is pain. Code is love. Code is life.
Reimu: Predictable deployments sound nice.
Marisa: And when everything breaks, we can rebuild it instantly! very professional
1.2 Why use CDK v2 and why Python?
📘 Technical Explanation
Why CDK v2?
- Official AWS development framework
- One unified library:
aws-cdk-lib - Faster updates for new AWS services
- Construct-based architecture = high-level abstractions
- Reusable components across projects
Why Python?
- Clean syntax & fast to learn
- Widely used in automation and serverless
- Works well with AWS Lambda
- Rich tooling ecosystem:
pip,venv,pytest
cdk init app --language python
Creates a structure like:
. ├─ app.py └─ <project_name>/ └─ <project_name>_stack.py
🗣️ Yukkuri Commentary
Reimu: Why not Terraform?
Marisa: Terraform is great, but CDK is extra spicy AWS-native magic power!
Reimu: And Python is easier to read than YAML.
Marisa: YAML indentation boss fight is over. Python wins.
1.3 How this book is structured & how to use it
📘 Structure
| Section | Focus |
|---|---|
| Foundations | IaC basics, CDK concepts |
| Hands-on Labs | Build real AWS architectures |
| Advanced Topics | CI/CD, multi-stack, security |
| Operations | Monitoring, debugging, cost controls |
| Appendix | Cheatsheets & reusable patterns |
Suggested Workflow
Read → Write code → Deploy → Break → Debug → Deploy again
Mental model: Treat infrastructure like software. It has versions, tests, refactors, and pull requests.
🗣️ Yukkuri Commentary
Reimu: So I need to actually type the code?
Marisa: Yes. Copy-pasting is fine… but debugging is the true dojo!
Reimu: Break things to learn, huh. Sounds like real DevOps.
Marisa: If you never broke production, you haven't lived.
1.4 Prerequisites
✅ Before you start, you should have:
| Requirement | Notes |
|---|---|
| AWS account | Free tier works |
| Python 3.8+ | Virtual env recommended |
| Node.js | Required for CDK CLI |
| AWS CLI | Auth & config |
| Git | Version control |
Install CDK & Setup Project
npm install -g aws-cdk mkdir cdk-intro && cd cdk-intro cdk init app --language python
Activate virtual environment:
python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt
Configure AWS credentials:
aws configure
🗣️ Yukkuri Commentary
Reimu: Why do I need Node.js if I'm writing Python?
Marisa: CDK CLI runs on Node. The CDK gods demand tribute.
Reimu: And AWS CLI config… always terrifying.
Marisa: Type the credentials correctly, and pray. Always pray.
✅ Chapter Summary
You learned:
- What IaC is and why it matters
- Why CDK v2 is powerful
- Why this book uses Python
- How to prepare your environment
Next: We will deploy our first CDK stack.
Reimu: Finally some action!
Marisa: Yes. Time to spawn real AWS resources.
Reimu: And hopefully not get billed into oblivion.
Marisa: Free tier is our shield. Mostly.
Chapter 2: Getting Started with CDK v2 in Python
2.1 Overview of CDK v2: Changes from v1, Benefits
AWS CDK v2 introduces a simplified, unified experience:
| Feature | CDK v1 | CDK v2 |
|---|---|---|
| Library | Many npm modules | Single module: aws-cdk-lib |
| Constructs | @aws-cdk/core |
constructs package |
| Stability | Mix of versioned and unstable APIs | Stable API Guarantees |
| Maintenance | Legacy | Actively maintained |
Key benefits:
- Simpler installation & imports
- Faster updates for new AWS features
- Community adoption + examples everywhere
- Predictable API stability
# CDK v2 import example from aws_cdk import ( Stack, aws_s3 as s3, )
🗣 Yukkuri Commentary
Reimu: So v2 is like “CDK but not suffering”?
Marisa: Exactly. Less dependency chaos, more cloud magic.
Reimu: Developers love less pain.
Marisa: Yes. Pain is for runtime bugs, not setup.
2.2 Setting Up the Development Environment
Install Node.js
Required for the CDK CLI (even with Python CDK apps)
brew install node # macOS sudo apt-get install nodejs npm # Ubuntu/Debian
Install CDK CLI
npm install -g aws-cdk
Verify installation
cdk --version
Install Python 3.8+
python3 --version
Virtual Environment
python3 -m venv .venv source .venv/bin/activate # macOS / Linux .venv\Scripts\activate # Windows
🗣 Yukkuri Commentary
Reimu: Why do we need Node.js again if we use Python?
Marisa: Because CDK CLI runs on Node. Respect the multi-language gods.
Reimu: Multilingual pain…
Marisa: The cloud demands blood— and toolchains.
2.3 Create Your First CDK Python Project
mkdir my-first-cdk && cd my-first-cdk cdk init app --language python
Install dependencies:
source .venv/bin/activate pip install -r requirements.txt
🗣 Yukkuri Commentary
Reimu: That generated a lot of files.
Marisa: Yes. Scaffolding magic. Like a cookie cutter but for cloud things.
Reimu: I see folder, I trust.
2.4 CDK Project Structure & Lifecycle
Generated structure:
my-first-cdk/
├── app.py
├── requirements.txt
└── my_first_cdk
└── my_first_cdk_stack.py
CDK Lifecycle
| Step | Command | Purpose |
|---|---|---|
| Synthesize | cdk synth |
Generate CloudFormation |
| Diff | cdk diff |
Show what will change |
| Deploy | cdk deploy |
Build & deploy stack |
| Destroy | cdk destroy |
Clean resources |
First Stack Example
from aws_cdk import ( Stack, aws_s3 as s3, ) from constructs import Construct class MyFirstCdkStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) s3.Bucket(self, "MyBucket", versioned=True )
🗣 Yukkuri Commentary
Marisa: Synth! Diff! Deploy! Destroy!
Reimu: Are those AWS spells?
Marisa: Yes. Deploy is Fireball. Destroy is Meteor.
2.5 Understanding aws_cdk / aws-cdk-lib & Constructs
CDK Key Concepts
| Concept | Description |
|---|---|
| Construct | Cloud component (S3 bucket, Lambda, VPC) |
| Stack | Deployment unit |
| App | Collection of stacks |
| Construct Library | Ready-to-use AWS components |
Import Patterns
from aws_cdk import ( Stack, aws_lambda as _lambda, aws_dynamodb as dynamodb, ) from constructs import Construct
Creating a Lambda and DynamoDB Table
_lambda.Function(
self, "MyFunction",
runtime=_lambda.Runtime.PYTHON_3_9,
handler="handler.main",
code=_lambda.Code.from_asset("lambda")
)
dynamodb.Table(
self, "Table",
partition_key={"name": "id", "type": dynamodb.AttributeType.STRING}
)
🗣 Yukkuri Commentary
Reimu: Construct library is like LEGO blocks?
Marisa: Exactly. Except the bricks create real bills if you forget to delete them.
Reimu: Gently puts wallet behind back
2.6 Bootstrapping & Cost Basics
What is Bootstrapping?
CDK needs AWS resources for deployments (S3 bucket, roles).
Run once per region/account:
cdk bootstrap
Basic AWS Billing Safety
- Use Free Tier resources when possible
- Avoid unnecessarily large instances (e.g.,
m5.4xlarge) - Delete stacks when finished:
cdk destroy
🗣 Yukkuri Commentary
Reimu: Bootstrapping feels like setting the stage.
Marisa: Yes. Before the cloud musical begins!
Reimu: And destroy stacks to avoid sadness from AWS bills.
Marisa: Financial death is real. Respect the billing gods.
✅ Chapter 2 Summary
You now know how to:
- Understand CDK v2 advantages
- Install CDK CLI, Python env
- Initialize a CDK project
- Understand the CDK lifecycle
- Use Construct Library
- Bootstrap and avoid cost disasters
Chapter 3: Core Concepts and Abstractions
In this chapter we explore fundamental CDK abstractions. Master these concepts, and you unlock the full power of CDK.
3.1 Constructs: L1, L2, L3 — What They Are & When to Use
CDK defines AWS resources in layers:
| Level | Name | Description | Example |
|---|---|---|---|
| L1 | CloudFormation bindings | Direct 1:1 mapping | CfnBucket |
| L2 | Opinionated high-level constructs | Best-practice defaults | Bucket |
| L3 | Patterns | Complete architectures | aws_s3_deployment.BucketDeployment |
Example: L1 vs L2
L1 Construct
from aws_cdk import aws_s3 as s3 s3.CfnBucket(self, "RawBucket", bucket_name="my-low-level-bucket" )
L2 Construct
s3.Bucket(self, "NiceBucket", versioned=True, encryption=s3.BucketEncryption.S3_MANAGED )
L2 saves time, L1 gives ultimate control.
🗣 Yukkuri Commentary
Reimu: So L2 is “safe defaults,” and L1 is “danger mode”?
Marisa: Exactly! L1 is like driving without seatbelts—fast, scary, and sometimes necessary.
Reimu: L3 sounds like pre-made lunch boxes.
Marisa: Bento DevOps.
3.2 Stacks, Apps, and Assemblies
Definitions
| Term | Meaning |
|---|---|
| App | Entry point to CDK execution |
| Stack | Deployment unit (CloudFormation stack) |
| Assembly | Synthesis output (CloudFormation templates + metadata) |
Example Project Entry: app.py
#!/usr/bin/env python3 from aws_cdk import App from my_app.my_stack import MyStack app = App() MyStack(app, "MyStack") app.synth()
Stack Example
from aws_cdk import Stack, aws_sqs as sqs from constructs import Construct class MyStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) sqs.Queue(self, "MyQueue")
🗣 Yukkuri Commentary
Reimu: So the app summons stacks?
Marisa: Yes. The app is the summoner. The stacks are the creatures.
Reimu: Cloud Pokémon.
Marisa: But AWS charges per summon.
3.3 Context, Environment, and Cross-Account / Cross-Region
Context
Load parameters at runtime:
cdk deploy --context stage=prod
Inside Python:
stage = self.node.try_get_context("stage") print(f"Deploying to {stage}")
Environment
Specify account & region:
from aws_cdk import Environment MyStack(app, "ProdStack", env=Environment(account="123456789012", region="us-east-1") )
Cross-Account Notes
- Bootstrapping required per account
- Deploy roles needed
- Avoid passing secrets across stacks
🗣 Yukkuri Commentary
Reimu: Multi-account deployments sound scary.
Marisa: They are. Like AWS billing demons spawning across universes.
Reimu: I shall respect the context spell.
3.4 Assets, Bundling, Deployment Artifacts
CDK packages local files as assets (Lambda code, Web assets, Docker build contexts).
Lambda with assets
from aws_cdk import aws_lambda as _lambda _lambda.Function( self, "Handler", runtime=_lambda.Runtime.PYTHON_3_9, handler="index.handler", code=_lambda.Code.from_asset("lambda") )
Bundling Example (Container build)
from aws_cdk import BundlingOptions _lambda.Function( self, "BundledLambda", runtime=_lambda.Runtime.PYTHON_3_9, handler="app.handler", code=_lambda.Code.from_asset("./src", bundling=BundlingOptions( image=_lambda.Runtime.PYTHON_3_9.bundling_image, command=["bash", "-c", "pip install -r requirements.txt -t /asset-output && cp -r . /asset-output"] ) ) )
🗣 Yukkuri Commentary
Reimu: So bundling is like packing lunch for Lambda?
Marisa: Yes, we send it to the cloud school.
Reimu: Do we include dependencies?
Marisa: Always. Cloud children get hungry.
3.5 Versioning & Dependencies of aws-cdk-lib in Python
Install specific version:
pip install "aws-cdk-lib==2.1.0" pip install "constructs>=10.0.0,<11.0.0"
Check versions:
pip list | grep cdk
Upgrade strategy
- Pin versions in
requirements.txt - Upgrade regularly
- Test in sandbox environment
🗣 Yukkuri Commentary
Reimu: Dependency version hell?
Marisa: Not as bad as npm hell.
Reimu: True. Python hell is warm, not flaming.
3.6 Naming Conventions, snake_case & Type Hints
CDK uses snake_case for Python APIs:
bucket = s3.Bucket(self, "MyBucket",
removal_policy=s3.RemovalPolicy.DESTROY
)
Type Hint Example
from typing import Optional def build_bucket(self, name: str, versioned: Optional[bool] = True): ...
Common Gotcha
Construct IDs use PascalCase, resource props use snake_case.
bucket = s3.Bucket(self, "AppDataBucket") # ID
🗣 Yukkuri Commentary
Reimu: snake_case + PascalCase… mixed conventions!
Marisa: Yes. Fear not. Embrace the duality.
Reimu: Dual-case discipline: required for cloud enlightenment.
✅ Chapter Summary
In this chapter you learned:
- L1/L2/L3 constructs & when to use them
- Stacks, Apps, and Assembly outputs
- Context & environments
- Assets & bundling
- Version pinning & dependency discipline
- Naming rules + type hint discipline
Chapter 4: Hands-On Project I — Simple Web Application Infrastructure
In this chapter we build a simple web application using:
- S3 (static hosting)
- CloudFront (CDN)
- Lambda (serverless API)
- API Gateway (HTTP entry point)
- DynamoDB (storage)
4.1 Requirements: static website or simple REST API
We will create:
- A static website (HTML/JS) hosted in S3
- A CloudFront distribution for global caching
- A serverless API endpoint (
/hello) - Python Lambda that writes to DynamoDB
- CloudFormation + CDK automation
Project architecture:
Client Browser -> CloudFront -> S3 (static site)
\
-> API Gateway -> Lambda -> DynamoDB
🗣️ Yukkuri Commentary
Reimu: Building a whole app already?
Marisa: Yes! Real cloud isn’t for looking — it's for deploying!
Reimu: As long as it doesn't summon bills.
Marisa: Free tier is our shield. Mostly.
4.2 S3 Bucket for Website + CloudFront Distribution
Install CDK S3 Deployment
pip install aws-cdk-lib constructs pip install aws-cdk.aws-s3-deployment
Define Bucket + CloudFront
infrastructure/web_stack.py
from aws_cdk import ( Stack, aws_s3 as s3, aws_cloudfront as cloudfront, aws_s3_deployment as s3deploy, ) from constructs import Construct class WebStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) self.bucket = s3.Bucket(self, "WebBucket", website_index_document="index.html", public_read_access=False ) self.distribution = cloudfront.CloudFrontWebDistribution( self, "WebDistribution", origin_configs=[ cloudfront.SourceConfiguration( s3_origin_source=cloudfront.S3OriginConfig( s3_bucket_source=self.bucket ), behaviors=[cloudfront.Behavior(is_default_behavior=True)] ) ] ) s3deploy.BucketDeployment( self, "DeployStaticSite", destination_bucket=self.bucket, sources=[s3deploy.Source.asset("./web")] )
Place your HTML file in web/index.html.
🗣️ Yukkuri Commentary
Reimu: So CloudFront makes my website fast worldwide?
Marisa: Yes. It is CDN magic.
Reimu: Like teleportation but for packets.
Marisa: Exactly. AWS sorcery.
4.3 Lambda (Python) + API Gateway Endpoint
Lambda Code
lambda/handler.py
import json import boto3 import os dynamodb = boto3.resource("dynamodb") table = dynamodb.Table(os.environ["TABLE_NAME"]) def handler(event, context): name = event.get("queryStringParameters", {}).get("name", "visitor") table.put_item(Item={"id": name}) return { "statusCode": 200, "body": json.dumps({"message": f"Hello, {name}!"}) }
CDK Stack for API
from aws_cdk import ( aws_lambda as _lambda, aws_apigateway as apigw, ) class ApiStack(Stack): def __init__(self, scope: Construct, id: str, table, **kwargs): super().__init__(scope, id, **kwargs) self.func = _lambda.Function( self, "HelloFunction", runtime=_lambda.Runtime.PYTHON_3_9, handler="handler.handler", code=_lambda.Code.from_asset("lambda"), environment={"TABLE_NAME": table.table_name} ) self.api = apigw.LambdaRestApi( self, "ApiGateway", handler=self.func, proxy=True ) table.grant_write_data(self.func)
🗣️ Yukkuri Commentary
Reimu: Lambda with DynamoDB… feels legit.
Marisa: Yes, true serverless vibes.
Reimu: No servers to maintain!
Marisa: Only feelings to maintain.
4.4 Define DynamoDB Table
from aws_cdk import aws_dynamodb as dynamodb class DatabaseStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) self.table = dynamodb.Table( self, "VisitTable", partition_key={"name": "id", "type": dynamodb.AttributeType.STRING} )
🗣️ Yukkuri Commentary
Reimu: So every visitor gets stored?
Marisa: Yes. We remember EVERYTHING.
Reimu: That's creepy but… scalable?
4.5 Wiring Everything Together
App Entry
app.py
from aws_cdk import App from infrastructure.web_stack import WebStack from infrastructure.db_stack import DatabaseStack from infrastructure.api_stack import ApiStack app = App() db = DatabaseStack(app, "DatabaseStack") web = WebStack(app, "WebStack") api = ApiStack(app, "ApiStack", table=db.table) app.synth()
🗣️ Yukkuri Commentary
Reimu: So this connects everything?
Marisa: Yes. This is the “glue.”
Reimu: Glue like in AWS Glue?
Marisa: Don't summon those horrors yet. Too early.
4.6 cdk synth, cdk deploy, Review CloudFormation
Commands
cdk synth cdk diff cdk deploy --all
Go check AWS Console:
- ✅ S3 bucket created
- ✅ CloudFront distribution deployed
- ✅ API Gateway URL printed
- ✅ DynamoDB table created
Test API:
curl "$(cdk output ApiStack.ApiEndpoint)/?name=Reimu"
🗣️ Yukkuri Commentary
Reimu: My cloud app lives!
Marisa: It breathes digital air.
Reimu: Fear me, mere mortals! I deploy serverless now!
Marisa: Calm down, you’re still on free tier.
4.7 Cleanup / Teardown
cdk destroy --all
Also empty S3 deployment buckets if deletion fails.
🗣️ Yukkuri Commentary
Reimu: Important step: delete things so AWS doesn't eat my wallet.
Marisa: True. The cloud giveth and the cloud taketh your credit card.
✅ End of Chapter Summary
You built:
- Static hosting in S3 + CloudFront
- Lambda REST API + API Gateway
- DynamoDB persistence
- Full CDK stack integration
- Deploy + test + cleanup cycles
This was a real cloud app — congratulations!
Chapter 5: Hands-On Project II
Multi-Stack Architecture & Networking
With Yukkuri Reimu & Marisa Commentary
In this chapter, we expand our AWS CDK skills into networking and multi-stack design.
We will build:
- A VPC with public/private subnets
- Security Groups
- A shared infrastructure stack
- A service stack that consumes shared resources
- Cross-stack outputs/imports
- Tags and Aspects
- Multi-region/multi-account notes
- Deploy and validate everything
5.1 Why Multiple Stacks?
Motivation
| Reason | Benefit |
|---|---|
| Organizational boundaries | Separate team ownership |
| Security | Least privilege isolation |
| Performance | Parallel deploys & modular updates |
| Scalability | Manage large infrastructure |
| Reusability | Core/shared infra stack |
Think microservices, but for infrastructure.
🗣️ Yukkuri Commentary
Reimu: So stacks are like “microcloud services”?
Marisa: Yes! Micro-infra! Small pieces, loosely coupled!
Reimu: And bills distributed evenly?
Marisa: laughs in CloudWatch charges
5.2 Defining a VPC, Subnets, Security Groups
VPC & Subnets
infrastructure/network_stack.py
from aws_cdk import ( Stack, aws_ec2 as ec2, ) from constructs import Construct class NetworkStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) self.vpc = ec2.Vpc( self, "AppVpc", max_azs=2, subnet_configuration=[ ec2.SubnetConfiguration( name="Public", subnet_type=ec2.SubnetType.PUBLIC ), ec2.SubnetConfiguration( name="Private", subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS ), ] )
Security Group
self.api_sg = ec2.SecurityGroup(
self, "ApiSecurityGroup",
vpc=self.vpc,
allow_all_outbound=True
)
self.api_sg.add_ingress_rule(
ec2.Peer.any_ipv4(), ec2.Port.tcp(443),
"Allow HTTPS"
)
🗣️ Yukkuri Commentary
Reimu: Wait, network configs… that means complexity approaching?
Marisa: Yes, networking is where souls are tested.
Reimu: But we have CDK magic!
Marisa: True. Less pain — still some pain.
5.3 Shared Infra Stack vs Service-Specific Stack
We separate infrastructure:
| Stack | Purpose |
|---|---|
| NetworkStack | VPC + SGs |
| ServiceStack | Lambda + API that uses VPC |
5.4 Inter-Stack References (Exports/Imports)
Service Stack
infrastructure/service_stack.py
from aws_cdk import ( Stack, aws_lambda as _lambda, aws_apigateway as apigw, ) from constructs import Construct class ServiceStack(Stack): def __init__(self, scope: Construct, id: str, vpc, api_sg, **kwargs): super().__init__(scope, id, **kwargs) self.func = _lambda.Function( self, "VpcLambda", runtime=_lambda.Runtime.PYTHON_3_9, handler="handler.handler", code=_lambda.Code.from_asset("lambda"), vpc=vpc, security_groups=[api_sg] ) self.api = apigw.LambdaRestApi( self, "VpcApi", handler=self.func )
App Entry
app.py
from aws_cdk import App from infrastructure.network_stack import NetworkStack from infrastructure.service_stack import ServiceStack app = App() net = NetworkStack(app, "NetworkStack") ServiceStack(app, "ServiceStack", vpc=net.vpc, api_sg=net.api_sg ) app.synth()
🗣️ Yukkuri Commentary
Reimu: So we pass resources like sharing noodles?
Marisa: Exactly — but you can isolate packets instead of ramen.
Reimu: Cloud ramen security!
Marisa: Delicious. Secure. Scalable.
5.5 Multi-Region / Multi-Account Considerations
Basic Practice
from aws_cdk import Environment ServiceStack(app, "ServiceStack", env=Environment( account="123456789012", region="us-east-1" ), vpc=net.vpc, api_sg=net.api_sg )
Notes
- Bootstrap each account/region
- Cross-region reference limitations
- Prefer messaging (SNS/SQS/EventBridge) for cross-region architectures
🗣️ Yukkuri Commentary
Reimu: Deploy to multiple regions? Sounds fancy.
Marisa: Fancy and terrifying. Like multi-dimensional cloud chess.
Reimu: I will practice in one region first…
5.6 Aspects for Tagging & Validation
from aws_cdk import Tags, Aspects Tags.of(app).add("Project", "CloudTraining") Tags.of(app).add("Environment", "Dev")
Custom Aspects Example
from constructs import IConstruct class NoPublicIngressAspect: def visit(self, node: IConstruct): if isinstance(node, ec2.SecurityGroup): # enforce no public ingress here pass Aspects.of(app).add(NoPublicIngressAspect())
🗣️ Yukkuri Commentary
Reimu: Tag everything?
Marisa: Yes. Tags are love. Tags are billing clarity.
Reimu: Ah yes. Avoid “mystery charges.”
Marisa: Never anger the billing gods.
5.7 Deploy & Verify
Deploy
cdk synth cdk diff cdk deploy --all
Verify
- VPC created
- Subnets created
- Security group configured
- Lambda in VPC
- API works
- CloudFormation stacks separated
Cleanup
cdk destroy --all
🗣️ Yukkuri Commentary
Reimu: Everything deployed! It lives!
Marisa: It breathes VPC air now.
Reimu: And then we destroy it?
Marisa: Yes. Destruction is cloud hygiene.
✅ Chapter Summary
You learned how to:
- Architect multiple stacks
- Build VPC networks & security groups
- Separate shared vs service stacks
- Pass resources between stacks
- Plan for multi-region & multi-account
- Use Aspects and tagging
- Deploy + verify infrastructure
You are now a CDK networking practitioner.
Chapter 6: Hands-On Project III — Serverless Event-Driven Application
In this chapter, you will build an event-driven system using:
- SQS OR SNS OR EventBridge
- Lambda consumers
- DynamoDB persistence
- Step Functions for orchestration (optional path)
- CloudWatch logging & metrics
- Cost & scaling considerations
6.1 Overview of Serverless Patterns
Event-driven architectures use events to trigger compute.
| Pattern | Example | Purpose |
|---|---|---|
| Pub/Sub | SNS → multiple Lambdas | Fan-out |
| Queue processing | SQS → Lambda | Decoupling, retries |
| Event bus | EventBridge | SaaS integration, routing |
| State machines | Step Functions | Complex workflows |
| Streams | Kinesis / Firehose → Lambda | Real-time data |
🗣️ Yukkuri Commentary
Reimu: So serverless is like summoning compute only when needed?
Marisa: Exactly. Like a ninja — appears, executes, vanishes, leaves no traces.
Reimu: Except CloudWatch logs.
Marisa: True. Ninjas log everything in CloudWatch. For billing.
6.2 Create SQS Queue + SNS Topic + EventBridge Bus
Imports
from aws_cdk import ( Stack, aws_sqs as sqs, aws_sns as sns, aws_sns_subscriptions as subs, aws_events as events, aws_events_targets as targets, ) from constructs import Construct
Define Queue / Topic / Event Bus
class MessagingStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) self.queue = sqs.Queue(self, "AppQueue") self.topic = sns.Topic(self, "AppTopic") self.topic.add_subscription( subs.SqsSubscription(self.queue) ) self.bus = events.EventBus(self, "AppEventBus")
Architecture created:
SNS → SQS → Lambda
↘ EventBridge
🗣️ Yukkuri Commentary
Reimu: SNS fans out events like a gossip network!
Marisa: Yes, SNS is cloud rumor system.
Reimu: And SQS makes rumors wait in a line.
Marisa: FIFO gossip queue — premium drama.
6.3 Lambda Consumers Writing to DynamoDB
Lambda Code
lambda/worker.py
import json, boto3, os ddb = boto3.resource("dynamodb").Table(os.environ["TABLE_NAME"]) def handler(event, context): for record in event["Records"]: body = json.loads(record["body"]) ddb.put_item(Item={"id": body["id"], "event": body}) return "OK"
Define Table + Lambda + Event Trigger
from aws_cdk import ( aws_lambda as _lambda, aws_lambda_event_sources as sources, aws_dynamodb as dynamodb, ) class ProcessingStack(Stack): def __init__(self, scope: Construct, id: str, queue, **kwargs): super().__init__(scope, id, **kwargs) table = dynamodb.Table( self, "EventsTable", partition_key={"name": "id", "type": dynamodb.AttributeType.STRING} ) func = _lambda.Function( self, "QueueWorker", runtime=_lambda.Runtime.PYTHON_3_9, handler="worker.handler", code=_lambda.Code.from_asset("lambda"), environment={"TABLE_NAME": table.table_name} ) func.add_event_source(sources.SqsEventSource(queue)) table.grant_write_data(func)
🗣️ Yukkuri Commentary
Reimu: Messages come in, Lambda writes to DB… magical pipeline!
Marisa: It’s a conveyor belt of events.
Reimu: Like a sushi belt, but JSON flavored.
Marisa: And DynamoDB eats everything.
6.4 Step Functions (optional advanced)
State Machine example
from aws_cdk import aws_stepfunctions as sfn from aws_cdk import aws_stepfunctions_tasks as tasks task = tasks.LambdaInvoke(self, "ProcessEvent", lambda_function=func) definition = task.next(sfn.Succeed(self, "Done")) sfn.StateMachine(self, "EventProcessor", definition=definition )
Optional: Kinesis / Firehose for streaming pipeline.
🗣️ Yukkuri Commentary
Reimu: So Step Functions orchestrate many Lambdas?
Marisa: Yes. It’s the puppet master.
Reimu: Cloud puppet theater!
Marisa: With JSON strings instead of strings.
6.5 Monitoring: CloudWatch Logs, Metrics, Alerts
Enable metrics & alarms:
from aws_cdk import aws_cloudwatch as cw cw.Alarm(self, "QueueDepthAlarm", metric=queue.metric_approximate_number_of_messages_visible(), threshold=100, evaluation_periods=1 )
View:
- Lambda logs in CloudWatch
- SQS queue length
- DynamoDB throttles
- Step Function execution history
🗣️ Yukkuri Commentary
Reimu: Monitor logs! Understand errors!
Marisa: Logs are truth. Metrics are destiny.
Reimu: Alert me only when critical.
Marisa: Or when lonely, like “Hey, I missed you. Queue is empty.”
6.6 Cost & Scaling Considerations
Key Factors
| Resource | Pricing Trigger |
|---|---|
| Lambda | Execution time & requests |
| SQS | API calls & data |
| SNS | Requests & fan-out traffic |
| DynamoDB | RCU/WCU or On-Demand |
| Step Functions | State transitions |
Tips
- Use on-demand DynamoDB until stable traffic
- Tune Lambda memory (affects speed)
- Dead Letter Queues (DLQ) for failure safety
- SQS batch size improves efficiency
sources.SqsEventSource(queue, batch_size=10)
🗣️ Yukkuri Commentary
Reimu: Serverless seems cost-effective.
Marisa: Yes… until you forget to turn off debug logs.
Reimu: CloudWatch bill trauma incoming.
Marisa: We cry, then optimize.
✅ Chapter Summary
You built:
- Event-driven queue + topic + event bus
- Lambda processing pipeline
- DynamoDB persistence
- Optional Step Functions workflow
- Monitoring alarms
- Cost strategies
You now wield cloud automation power.
Chapter 7: Testing, CI/CD and Quality of CDK Apps
Infrastructure deserves the same rigor as application code. In this chapter, we cover:
- Testing CDK constructs
- Snapshot tests & E2E flows
- CI/CD pipelines (GitHub Actions & CodePipeline)
- Linting & type checking
- Handling drift & stack lifecycle policies
7.1 Unit Testing CDK Constructs (pytest + CDK Assertions)
Install dependencies:
pip install pytest aws-cdk-lib constructs pip install aws-cdk.assertions
Example Stack
from aws_cdk import Stack, aws_s3 as s3 from constructs import Construct class DemoStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) s3.Bucket(self, "MyBucket", versioned=True, encryption=s3.BucketEncryption.S3_MANAGED )
Test with CDK Assertions
test_demo.py
import aws_cdk as cdk from aws_cdk import assertions from demo.demo_stack import DemoStack def test_bucket_created(): app = cdk.App() stack = DemoStack(app, "TestStack") template = assertions.Template.from_stack(stack) template.has_resource_properties("AWS::S3::Bucket", { "VersioningConfiguration": {"Status": "Enabled"} })
Run:
pytest
🗣️ Yukkuri Commentary
Reimu: Testing infrastructure feels… weird?
Marisa: But glorious. We prevent future cloud sadness.
Reimu: And AWS mistakes are expensive sadness.
Marisa: Unit tests = cost protection charms.
7.2 Snapshot Tests, Integration Tests, E2E Tests
Snapshot Test Example
def test_snapshot(): app = cdk.App() stack = DemoStack(app, "SnapshotStack") template = assertions.Template.from_stack(stack) template.to_json() # saved and compared automatically
Stores JSON snapshot in repo. Change detected? → CI fails = infra review time.
Integration Test Strategy
- Deploy to staging
- Validate resource endpoints (Lambda/API)
- Assert IAM roles exist
End-to-End Test Example (Concept)
curl https://my-api.example.com/hello | grep "Hello"
Combine with pytest + boto3 for automated checks.
🗣️ Yukkuri Commentary
Reimu: Snapshots catch “oops, I didn't mean to wipe production,” right?
Marisa: Exactly. A safety net against accidental chaos.
Reimu: So like a cloud parachute?
Marisa: More like airbag for your career.
7.3 CI/CD Pipelines
GitHub Actions Example: deploy.yml
name: CDK Deploy on: push: branches: [ "main" ] jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Setup Python uses: actions/setup-python@v4 with: python-version: "3.9" - name: Install CDK run: npm install -g aws-cdk - name: Install Python deps run: | python -m venv .venv source .venv/bin/activate pip install -r requirements.txt - name: CDK Deploy env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} run: cdk deploy --all --require-approval never
CDK CodePipeline Example
from aws_cdk import aws_codepipeline as pipeline from aws_cdk import aws_codepipeline_actions as actions
(Full pipeline in Appendix)
🗣️ Yukkuri Commentary
Reimu: Auto-deploy cloud changes when I push code? Heaven!
Marisa: Yes, but beware — automated explosions are also faster.
Reimu: Truly the power and terror of DevOps.
Marisa: Pipelines are anime transformation sequences for infrastructure.
7.4 Linting & Type Checking (mypy)
Install tools:
pip install mypy black flake8
Type Check Example
mypy src/
mypy-friendly CDK pattern
from typing import Optional bucket: Optional[s3.Bucket] = None
Lint & Format
flake8 black .
🗣️ Yukkuri Commentary
Reimu: Types in Python?
Marisa: Yes, we can pretend it’s TypeScript for a day.
Reimu: My code looks smarter already.
Marisa: Clean CDK code sparks joy.
7.5 Handling Drift, Stack Updates, Deletion Policies
Detect Drift
cdk diff
Or CloudFormation console → Drift Detection.
Prevent Data Loss
from aws_cdk import RemovalPolicy bucket = s3.Bucket(self, "DataBucket", removal_policy=RemovalPolicy.RETAIN )
Update Strategies
| Technique | Use case |
|---|---|
cdk diff |
Review changes before deploy |
| Change sets | Manual approvals |
| Phased stack replacement | Big infra upgrades |
🗣️ Yukkuri Commentary
Reimu: Drift sounds spooky.
Marisa: Yes. Cloud entropy. Infra chaos creeping in.
Reimu: And deletion policy stops accidental wipeouts?
Marisa: Yes. Buckets stay. Your sanity stays.
✅ Chapter Summary
You learned to:
- Unit-test CDK stacks with pytest & assertions
- Snapshot and E2E test infra
- Build CI/CD pipelines with GitHub Actions
- Use mypy + lint tools for quality
- Detect drift & enforce safe removals
You now wield both cloud power and discipline.
Chapter 8: Advanced Patterns & Best Practices
In this chapter, we elevate your CDK skills from builder to architect. We will focus on scalable, maintainable, secure CDK patterns.
8.1 Construct Library Design: Reusable Constructs
Custom constructs let you package infrastructure logic like reusable software modules.
Folder structure
infra/
constructs/
__init__.py
network_construct.py
stacks/
app_stack.py
Example: Custom Construct
constructs/network_construct.py
from constructs import Construct from aws_cdk import aws_ec2 as ec2 class NetworkConstruct(Construct): def __init__(self, scope: Construct, id: str): super().__init__(scope, id) self.vpc = ec2.Vpc( self, "Vpc", max_azs=2, subnet_configuration=[ ec2.SubnetConfiguration( name="Private", subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS ) ] )
Using the construct
class AppStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs): super().__init__(scope, id, **kwargs) network = NetworkConstruct(self, "Network")
🗣️ Yukkuri Commentary
Reimu: Constructs are like making Lego pieces yourself?
Marisa: Exactly. But these Legos deploy servers.
Reimu: And mistakes deploy invoices.
Marisa: Yes. Architect responsibly.
8.2 Architecture Patterns
Microservices
Each service = its own stack + shared services stack.
SharedInfraStack -> VPC, IAM, Monitoring UserServiceStack OrderServiceStack PaymentServiceStack
Domain-Driven Stacks
Group by business domain, not AWS service.
Shared Infra Stack
Example resources:
- VPC
- Database clusters
- Observability stack
- KMS keys, IAM roles
🗣️ Yukkuri Commentary
Reimu: Microservices can become micro-chaos.
Marisa: True. Microservices without strategy = maximum pain.
Reimu: So CDK helps organize the cloud dojo?
Marisa: Yes. Structure before scale.
8.3 Infra Modularization and Versioning
Requirements file pinned
requirements.txt
aws-cdk-lib==2.91.0 constructs>=10.0.0,<11.0.0
Version catalog for constructs
Define internal version constant:
MODULE_VERSION = "1.3.0"
Tag deployments:
git tag v1.3.0
Publish to internal artifact repo → optional.
🗣️ Yukkuri Commentary
Reimu: Versioning infra feels like managing spellbooks.
Marisa: Yes, infra magic evolves — version your power.
Reimu: No rogue upgrades allowed!
Marisa: Only responsible sorcery.
8.4 Security & Compliance
IAM Least Privilege
table.grant_read_write_data(lambda_fn)
# NOT lambda_fn.add_to_role_policy(...)
Prefer grant* helpers (safer, scoped policies).
Tagging
from aws_cdk import Tags Tags.of(self).add("Owner", "platform-team") Tags.of(self).add("Environment", "prod")
Monitoring
- CloudWatch dashboards
- Alarms for errors & latency
- Audit with AWS Config
- Security Hub / IAM Access Analyzer
🗣️ Yukkuri Commentary
Reimu: Cloud security is serious business.
Marisa: Yes. The cloud has ninjas — and auditors.
Reimu: Least privilege or your wallet cries?
Marisa: Yes. And compliance demons appear.
8.5 Cost Optimization & Cleanup
S3 Lifecycle rules
s3.Bucket(self, "Logs", lifecycle_rules=[s3.LifecycleRule( expiration=Duration.days(30) )] )
DynamoDB On-Demand
billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST
Turn on Lambda concurrency limits
reserved_concurrent_executions=10
🗣️ Yukkuri Commentary
Reimu: Optimize or perish?
Marisa: Cloud economics is battle strategy.
Reimu: Money saved = more ramen.
Marisa: Ramen-driven cloud design.
8.6 Anti-patterns & Pitfalls
| Anti-pattern | Better Way |
|---|---|
| Too many tiny stacks | Group by domain |
| Huge monolithic stack | Domain boundaries |
| Broad IAM policies | grant_read_write_data() |
| Hard-coding env | Use context, env vars |
| No lifecycle rules | S3 grows forever |
| Ignoring drift | cdk diff, config rules |
🗣️ Yukkuri Commentary
Reimu: What happens if we ignore these warnings?
Marisa: Your infra becomes a cursed spaghetti shrine.
Reimu: Horrors beyond human comprehension.
Marisa: And billing department cries blood.
✅ Chapter Summary
You learned:
- How to build reusable constructs
- Microservices / domain-driven infra patterns
- Infra versioning & modularity
- Security, IAM, tagging, monitoring
- Cost control strategies
- Dangerous anti-patterns to avoid
You now think like a Cloud Architect.
Chapter 9: Operating CDK in Production
At this stage, you are ready for real-world operations. This chapter focuses on running CDK apps in production environments:
- Environment management
- Multi-account setups
- Monitoring & observability
- Troubleshooting CloudFormation states
- Upgrading CDK
- Future CDK ecosystem
9.1 Managing Multiple Environments (dev, staging, prod)
Strategies
| Pattern | Description |
|---|---|
| Separate stacks per env | DevStack, StagingStack, ProdStack |
| Context parameters | cdk deploy -c env=prod |
| Config files | cdk.context.json, YAML env config |
| Parameter Store / Secrets Manager | External config |
Example using context
cdk deploy -c env=prod
env = self.node.try_get_context("env") bucket_name = f"my-app-{env}" s3.Bucket(self, "AppBucket", bucket_name=bucket_name)
Recommended: Per-env accounts
- dev / qa = sandbox
- staging = pre-production
- prod = protected account
🗣️ Yukkuri Commentary
Reimu: So each environment gets its own world?
Marisa: Yes. Multiverse cloud strategy.
Reimu: And prod is sacred ground?
Marisa: Touch prod only with clean commits and pure heart.
9.2 Multi-Account AWS + SSO
AWS Organizations & SSO
- Separate accounts for security boundaries
- AWS SSO (IAM Identity Center) for centralized login
- Deploy through IAM roles instead of static keys
CDK Environment Config
from aws_cdk import Environment prod_env = Environment( account="123456789012", region="us-east-1" )
Assume Role Deployment Example
GitHub Actions:
- name: Assume role uses: aws-actions/configure-aws-credentials@v2 with: role-to-assume: arn:aws:iam::123456789012:role/CDKDeployRole aws-region: us-east-1
🗣️ Yukkuri Commentary
Reimu: Multi-account sounds complex...
Marisa: It is. But so is rebuilding prod after an accident.
Reimu: So isolation = survival.
Marisa: Exactly — cloud Darwinism.
9.3 Monitoring & Observability
What to monitor
| Component | Metric |
|---|---|
| Lambda | Errors, duration, concurrency |
| API Gateway | 5xx, latency |
| DynamoDB | Throttles, capacity |
| SQS | Queue depth |
| CloudFront | Cache hit rate |
CDK CloudWatch Dashboard
from aws_cdk import aws_cloudwatch as cw cw.Dashboard(self, "AppDashboard")
Add metrics:
dashboard.add_widgets(
cw.GraphWidget(
title="Lambda Errors",
left=[fn.metric_errors()]
)
)
🗣️ Yukkuri Commentary
Reimu: If we don't watch it, it breaks?
Marisa: It breaks even if you watch it — but you notice faster.
Reimu: Observability is pain awareness.
Marisa: Wisdom comes from logs.
9.4 Troubleshooting CDK Deployments
CloudFormation Error Checklist
| Issue | Fix |
|---|---|
| Failed create/update | Check events tab |
| Insufficient permissions | IAM role/assume role policies |
| Stuck rollback | Delete stack resources manually |
| Resource already exists | Import or rename |
| Dependency loops | Consolidate or split resources |
How to debug
Terminal
cdk deploy -v
CloudFormation Console
- Events tab
- Nested stack failures
- IAM role trust issues
🗣️ Yukkuri Commentary
Reimu: CloudFormation failed! Panic?
Marisa: No. Panic after reading logs.
Reimu: Why does rollback feel like judgement day?
Marisa: Because it is. AWS gods are cruel and just.
9.5 Upgrading CDK versions safely
Strategy
- Pin version in
requirements.txt - Upgrade incrementally
cdk diffbefore deploying- Test in dev/staging first
Upgrade example
aws-cdk-lib==2.92.0 → aws-cdk-lib==2.100.0
Use release notes → https://github.com/aws/aws-cdk/releases
🗣️ Yukkuri Commentary
Reimu: Upgrades bring new powers!
Marisa: And new bugs. Read release notes like sacred scrolls.
Reimu: Fearful respect for version numbers.
Marisa: A true cloud monk.
9.6 Future of CDK
| Tech | Concept |
|---|---|
| CDK for Terraform (CDKTF) | CDK syntax → Terraform engine |
| CDK8s | Kubernetes manifests in code |
| Projen | Project config as code |
| Serverless Cloud (future tools) | Higher level abstractions |
Example CDK8s
from cdk8s import Chart from constructs import Construct from imports.k8s import KubeDeployment class AppChart(Chart): def __init__(self, scope: Construct, id: str): super().__init__(scope, id) KubeDeployment(self, "app", spec={"replicas": 2, "template": {...}} )
🗣️ Yukkuri Commentary
Reimu: So CDK is not just for AWS?
Marisa: Correct. CDK is spreading like cloud bamboo.
Reimu: Infrastructure everywhere.
Marisa: Code conquers configuration.
✅ Chapter Summary
You can now:
- Manage dev → staging → prod safely
- Run CDK with multi-account + SSO
- Monitor real workloads
- Debug CloudFormation issues
- Upgrade CDK versions safely
- Understand the future landscape (CDKTF, CDK8s)
You are now ready for production-grade AWS CDK.
Appendix A — CDK CLI Commands Cheat Sheet
Essential Commands
cdk init app --language python # create a new CDK project cdk synth # generate CloudFormation template cdk diff # compare local vs deployed stack cdk deploy # deploy a stack cdk deploy --all # deploy all stacks cdk destroy # tear down stack cdk list # list stacks in app cdk context # display cached context cdk doctor # diagnose environment cdk bootstrap # prepare env for CDK
Useful flags
cdk deploy --require-approval never cdk deploy -c env=prod cdk diff --verbose
🗣️ Yukkuri Commentary
Reimu: So cdk synth is the “see the future” command?
Marisa: Yes. And cdk diff is “spot disaster before it happens.”
Reimu: And cdk destroy is…
Marisa: Order 66 for cloud resources. Use wisely.
Appendix B — Python & AWS Construct Library Reference
Common Imports
from aws_cdk import ( App, Stack, Duration, RemovalPolicy, aws_s3 as s3, aws_lambda as _lambda, aws_dynamodb as dynamodb, aws_ec2 as ec2, aws_apigateway as apigw, aws_sqs as sqs, aws_sns as sns, aws_events as events, aws_events_targets as targets, ) from constructs import Construct
CDK Patterns
Bucket w/ lifecycle + encryption
s3.Bucket(self, "Logs", encryption=s3.BucketEncryption.S3_MANAGED, lifecycle_rules=[s3.LifecycleRule( expiration=Duration.days(30) )] )
Lambda + env vars
_lambda.Function(
self, "Handler",
runtime=_lambda.Runtime.PYTHON_3_9,
handler="app.handler",
code=_lambda.Code.from_asset("lambda"),
environment={"STAGE": "prod"}
)
VPC + SG
vpc = ec2.Vpc(self, "AppVpc", max_azs=2) sg = ec2.SecurityGroup(self, "AppSG", vpc=vpc)
🗣️ Yukkuri Commentary
Reimu: This is like Pokémon stats for AWS resources.
Marisa: Yes — collect them all, but only deploy with intention.
Reimu: No random Lambda spamming?
Marisa: Unless you enjoy mystery bills.
Appendix C — Migration Guide: CDK v1 → v2
Key Differences
| CDK v1 | CDK v2 |
|---|---|
| Many packages | aws-cdk-lib only |
@aws-cdk/core |
constructs pkg |
| Mixed stability | Stable API by default |
Migration Steps
- Upgrade CLI
npm install -g aws-cdk@latest
- Update dependencies
aws-cdk-lib>=2.0.0 constructs>=10.0.0,<11.0.0
- Replace imports
# old from aws_cdk import core # new from aws_cdk import App, Stack from constructs import Construct
- Remove deprecated APIs
- Test with
cdk diff - Deploy to dev → staging → prod
🗣️ Yukkuri Commentary
Reimu: Migrating is scary!
Marisa: Yes, like updating magical spell formulas.
Reimu: What if something explodes?
Marisa: That's why we use test environments and snacks. Snacks help.
Appendix D — Resources & Links
Official Docs
Examples
Community
- AWS CDK Slack
- Reddit r/aws
- Stack Overflow tag
aws-cdk - AWS Builders Discord
Learning
- AWS Well-Architected Labs
- CDK Workshops — https://cdkworkshop.com/
🗣️ Yukkuri Commentary
Reimu: So many resources!
Marisa: Yes, knowledge is infinite. Time is not.
Reimu: So copy-paste wisely.
Marisa: Copy-paste, then understand — the cloud way.
Appendix E — Glossary of Terms
| Term | Meaning |
|---|---|
| CDK | Cloud Development Kit |
| Construct | Reusable cloud component |
| Stack | CloudFormation stack |
| App | CDK program entry |
| Synthesis | Convert CDK → CloudFormation template |
| Drift | Deployed infra differs from code |
| Least privilege | Minimal IAM permissions |
| Bootstrap | Prepare AWS env for CDK |
| IaC | Infrastructure as Code |
| Decoupling | Design components independently |
| On-demand | Pay-per-use pricing mode |
| Observability | Logs + metrics + traces |
🗣️ Yukkuri Commentary
Reimu: Glossary unlocked! Final boss defeated!
Marisa: Yes — you now speak the sacred language of the cloud.
Reimu: Time to ascend as Cloud Priestess?
Marisa: Go forth and deploy — and try not to awaken Billing-kun.
🎉 Book Complete!
You now understand:
- CDK from basics → production
- Multi-stack patterns
- Serverless workflows
- CI/CD practices
- Cost + security strategies
- Migration and future CDK roadmap
