To create a maintainable, reusable and readable codebase of CDK, we can split the definition of stack in cdk_workshop_02_stack.py
into multiple file and include in a main file to deploy stack.
cdk_workshop_02/main_stack.py
files for the root stack.touch cdk_workshop_02/main_stack.py
touch cdk_workshop_02/lb_fargate_stack.py
touch cdk_workshop_02/lambda_stack.py.py
touch cdk_workshop_02/api_gateway_stack.py.py
cdk_workshop_02/lb_fargate_stack.py
from aws_cdk import (
NestedStack,
aws_ecs as ecs,
aws_ecs_patterns as ecsp,
)
from constructs import Construct
class LBFargateStack(NestedStack):
def __init__(self, scope: Construct, **kwargs) -> None:
super().__init__(scope, "LB Fargate Stack", **kwargs)
# Declare a Load Balancer Fargate
lb_fargate_service = ecsp.ApplicationLoadBalancedFargateService(
self,
"MyWebServer",
task_image_options=ecsp.ApplicationLoadBalancedTaskImageOptions(
image=ecs.ContainerImage.from_registry("nginxdemos/hello")),
public_load_balancer=True,
desired_count=3
)
self.lb = lb_fargate_service.load_balancer
cdk_workshop_02/lambda_stack.py
.from aws_cdk import (
NestedStack,
aws_s3 as s3,
aws_lambda as lambda_
)
from constructs import Construct
class LambdaStack(NestedStack):
def __init__(self, scope: Construct, **kwargs) -> None:
super().__init__(scope, "Lambda Stack", **kwargs)
# Add S3 bucket
bucket = s3.Bucket(self, "WidgetStore")
# Add Lambda function
handler = lambda_.Function(self, "WidgetHandler",
runtime=lambda_.Runtime.NODEJS_18_X,
code=lambda_.Code.from_asset("resources"),
handler="widget.main",
environment=dict(
BUCKET=bucket.bucket_name)
)
# Grant bucket permission to lambda function
bucket.grant_read_write(handler)
self.handler = handler
cdk_workshop_02/api_gateway_stack.py
.from aws_cdk import (
NestedStack,
aws_apigateway as apigateway,
aws_ecs_patterns as ecsp,
aws_lambda as lambda_
)
from constructs import Construct
class APIGatewayStack(NestedStack):
def __init__(self, scope: Construct, lb_dns: str, lambda_handler: lambda_.Function, **kwargs) -> None:
super().__init__(scope, "API Gateway Stack", **kwargs)
# Define API Gateway
api = apigateway.RestApi(self, "ProxyToLBECS")
# Add resource and method for ECS proxy request
ecs_proxy = api.root.add_resource("ecs")
ecs_proxy.add_method("GET", apigateway.HttpIntegration(f"http://{lb_dns}"))
# Create Lambda intergration
get_widgets_integration = apigateway.LambdaIntegration(lambda_handler,
request_templates={"application/json": '{ "statusCode": "200" }'})
# Add resource and method for Lambda proxy request
lambda_proxy = api.root.add_resource("lambda")
lambda_proxy.add_method("GET", get_widgets_integration)
self.url = api.url
cdk_workshop_02/main_stack.py
.from aws_cdk import (
Stack,
aws_apigateway as apigateway,
aws_s3 as s3,
aws_lambda as lambda_,
CfnOutput
)
from constructs import Construct
from .lambda_stack import LambdaStack
from .lb_fargate_stack import LBFargateStack
from .api_gateway_stack import APIGatewayStack
class MainStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
lb_fargate_stack = LBFargateStack(self)
lambda_stack = LambdaStack(self)
# Get the DNS value of the Application Load Balancer
lb_dns = lb_fargate_stack.lb.load_balancer_dns_name
api_gateway_stack = APIGatewayStack(self, lb_dns, lambda_stack.handler)
# Define stack output
CfnOutput(self, "API Gateway URL", value=api_gateway_stack.url)
app.py
to use our new template.#!/usr/bin/env python3
import os
import aws_cdk as cdk
from cdk_workshop_02.main_stack import MainStack
app = cdk.App()
# CdkWorkshop02Stack(app, "CdkWorkshop02Stack")
MainStack(app, "MainStack")
app.synth()
cdk deploy
After deploying successfully, you can see the newly created stacks in the AWS CloudFormation Console.
You can try the API Gateway endpoint for Lambda and ECS like in the previous section.
Upload files to S3 for testing
Changing the code inside the app.py
file will create a new CloudFormation template. In this workshop, each Cloudformation stack needs 2 elastic IPs to function properly. When deploying a stack, if the number of Elastic IPs exceeds the limitation of your account (default is 5), the CloudFormation stack may not initiate and get stuck at the IN_PROGRESS state. Make sure that you release all the unneeded Elastic IPs when performing this workshop.