Skip to content

Commit 5c29a35

Browse files
committed
MAJOR: add initial structure
1 parent 998597b commit 5c29a35

24 files changed

+2332
-0
lines changed

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
all:
2+
cd lambda-layers && $(MAKE)
3+
4+
clean:
5+
cd lambda-layers && $(MAKE) clean

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# AWS-CDK-FASTAPI-LAMBDA
2+
3+
Custom AWS-CDK solution with the infrastructure and code for running a FastAPI Server with Lambda Functions.
4+
5+
<!-- TODO: CREATE DETAILED README FILE! -->
6+
7+
## License
8+
9+
Copyright 2023 Santiago Garcia Arango.

cdk.context.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"main_resources_name": "fastapi-lambda",
3+
"tags": {
4+
"Owner": "Santiago Garcia Arango",
5+
"Source": "https://github.com/san99tiago/aws-cdk-fastapi-lambda",
6+
"Usage": "Sample project to illustrate a quick easy FastAPI deployment on Lambda Functions"
7+
}
8+
}

cdk.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"app": "make && python3 cdk/app.py"
3+
}

cdk/add_tags.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import aws_cdk as cdk
2+
3+
4+
def add_tags_to_app(
5+
app: cdk.App, main_resources_name: str, deployment_environment: str
6+
) -> None:
7+
"""
8+
Function to add custom tags to app in a centralized fashion.
9+
10+
:param app: (aws_cdk.App) to apply tags to.
11+
:param main_resources_name: (str) the main solution name being deployed.
12+
:param deployment_environment: (str) value of the tag "environment".
13+
"""
14+
15+
app_tags = cdk.Tags.of(app)
16+
app_tags.add("MainResourcesName", main_resources_name)
17+
app_tags.add("Environment", deployment_environment)
18+
19+
# Add tags from CDK context
20+
context_tags = app.node.try_get_context("tags")
21+
for key in context_tags:
22+
app_tags.add(key, context_tags[key])

cdk/app.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env python3
2+
3+
################################################################################
4+
# CDK SOLUTION FOR: APIGATEWAY-SQS-LAMBDA (TEMPLATE)
5+
################################################################################
6+
7+
# Built-in imports
8+
import os
9+
10+
# External imports
11+
import aws_cdk as cdk
12+
13+
# Own imports
14+
import add_tags
15+
from stacks.cdk_lambda_fastapi_stack import LambdaFunctionFastAPIStack
16+
17+
18+
print("--> Deployment AWS configuration (safety first):")
19+
print("CDK_DEFAULT_ACCOUNT", os.environ.get("CDK_DEFAULT_ACCOUNT"))
20+
print("CDK_DEFAULT_REGION", os.environ.get("CDK_DEFAULT_REGION"))
21+
22+
23+
app: cdk.App = cdk.App()
24+
25+
26+
# Configurations for the deployment (obtained from env vars and CDK context)
27+
DEPLOYMENT_ENVIRONMENT = os.environ.get("DEPLOYMENT_ENVIRONMENT", "dev")
28+
NAME_PREFIX = os.environ.get("NAME_PREFIX", "")
29+
MAIN_RESOURCES_NAME = app.node.try_get_context("main_resources_name")
30+
31+
32+
stack = LambdaFunctionFastAPIStack(
33+
app,
34+
"{}-{}".format(MAIN_RESOURCES_NAME, DEPLOYMENT_ENVIRONMENT),
35+
NAME_PREFIX,
36+
MAIN_RESOURCES_NAME,
37+
DEPLOYMENT_ENVIRONMENT,
38+
env={
39+
"account": os.environ.get("CDK_DEFAULT_ACCOUNT"),
40+
"region": os.environ.get("CDK_DEFAULT_REGION"),
41+
},
42+
description="Stack for {} infrastructure in {} environment".format(
43+
MAIN_RESOURCES_NAME, DEPLOYMENT_ENVIRONMENT
44+
),
45+
)
46+
47+
add_tags.add_tags_to_app(
48+
stack,
49+
MAIN_RESOURCES_NAME,
50+
DEPLOYMENT_ENVIRONMENT,
51+
)
52+
53+
app.synth()

cdk/stacks/__init__.py

Whitespace-only changes.
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Built-in imports
2+
import os
3+
4+
# External imports
5+
from aws_cdk import (
6+
Stack,
7+
Duration,
8+
CfnOutput,
9+
aws_lambda,
10+
RemovalPolicy,
11+
)
12+
from constructs import Construct
13+
14+
15+
class LambdaFunctionFastAPIStack(Stack):
16+
"""
17+
Class to create the infrastructure on AWS.
18+
"""
19+
20+
def __init__(
21+
self,
22+
scope: Construct,
23+
construct_id: str,
24+
name_prefix: str,
25+
main_resources_name: str,
26+
deployment_environment: str,
27+
**kwargs,
28+
) -> None:
29+
super().__init__(scope, construct_id, **kwargs)
30+
31+
# Input parameters
32+
self.construct_id = construct_id
33+
self.name_prefix = name_prefix
34+
self.main_resources_name = main_resources_name
35+
self.deployment_environment = deployment_environment
36+
37+
# Main methods for the deployment
38+
self.create_lambda_layers()
39+
self.create_lambda_functions()
40+
41+
# Create CloudFormation outputs
42+
self.generate_cloudformation_outputs()
43+
44+
def create_lambda_layers(self):
45+
"""
46+
Create the Lambda layers that are necessary for the additional runtime
47+
dependencies of the Lambda Functions.
48+
"""
49+
50+
# Layer for "LambdaPowerTools" (for logging, traces, observability, etc)
51+
self.lambda_layer_powertools = aws_lambda.LayerVersion.from_layer_version_arn(
52+
self,
53+
id="LambdaLayer-Powertools",
54+
layer_version_arn=f"arn:aws:lambda:{self.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:35",
55+
)
56+
57+
# Layer for "FastAPI" and "Mangum" Adapter libraries
58+
self.lambda_layer_fastapi = aws_lambda.LayerVersion(
59+
self,
60+
id="LambdaLayer-FastAPI",
61+
code=aws_lambda.Code.from_asset("lambda-layers/fastapi/modules"),
62+
compatible_runtimes=[
63+
aws_lambda.Runtime.PYTHON_3_9,
64+
aws_lambda.Runtime.PYTHON_3_10,
65+
],
66+
description="Lambda Layer for Python with <fastapi> library",
67+
removal_policy=RemovalPolicy.DESTROY,
68+
)
69+
70+
def create_lambda_functions(self):
71+
"""
72+
Create the Lambda Functions for the FastAPI server.
73+
"""
74+
# Get relative path for folder that contains Lambda function source
75+
# ! Note--> we must obtain parent dirs to create path (that"s why there is "os.path.dirname()")
76+
PATH_TO_LAMBDA_FUNCTION_FOLDER = os.path.join(
77+
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
78+
"src",
79+
"lambdas",
80+
)
81+
self.lambda_fastapi: aws_lambda.Function = aws_lambda.Function(
82+
self,
83+
id="Lambda-FastAPI",
84+
runtime=aws_lambda.Runtime.PYTHON_3_9,
85+
handler="api/main.handler",
86+
code=aws_lambda.Code.from_asset(PATH_TO_LAMBDA_FUNCTION_FOLDER),
87+
timeout=Duration.seconds(30),
88+
memory_size=128,
89+
environment={
90+
"ENVIRONMENT": self.deployment_environment,
91+
"LOG_LEVEL": "DEBUG",
92+
"STATE_MACHINE_ENABLED": "true",
93+
},
94+
layers=[
95+
self.lambda_layer_powertools,
96+
self.lambda_layer_fastapi,
97+
],
98+
)
99+
100+
self.lambda_function_url = self.lambda_fastapi.add_function_url(
101+
auth_type=aws_lambda.FunctionUrlAuthType.NONE,
102+
)
103+
104+
def generate_cloudformation_outputs(self):
105+
"""
106+
Method to add the relevant CloudFormation outputs.
107+
"""
108+
109+
CfnOutput(
110+
self,
111+
"DeploymentEnvironment",
112+
value=self.deployment_environment,
113+
description="Deployment environment",
114+
)
115+
116+
CfnOutput(
117+
self,
118+
"LambdaFunctionUrl",
119+
value=self.lambda_function_url.url,
120+
description="URL to invoke Lambda Function",
121+
)

important_commands.sh

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/bin/bash
2+
3+
################################################################################
4+
# PART 1: Configure NodeJs, Python and CDK libraries
5+
################################################################################
6+
7+
# Install NodeJs and Python
8+
# --> https://nodejs.org/en/download/
9+
# --> https://www.python.org/downloads/
10+
11+
# Verify that NodeJs/npm is installed correctly
12+
node --version
13+
npm --version
14+
15+
# Verify that Python/pip is installed correctly
16+
python --version || python3 --version
17+
pip --version || pip3 --version
18+
19+
# Install AWS-CDK (on NodeJs)
20+
sudo npm install -g aws-cdk
21+
22+
# Verify correct install of AWS-CDK
23+
npm list --global | grep aws-cdk
24+
25+
26+
################################################################################
27+
# PART 2: Initial Project Setup (Only run these at the beginning)
28+
################################################################################
29+
30+
# Configure AWS credentials (follow steps)
31+
aws configure
32+
# --> Alternative 1: Environment variables added to terminal session
33+
# --> Alternative 2: AWS Cloud9 with the right permissions
34+
35+
# Bootstrap CDK (provision initial resources to work with CDK.. S3, roles, etc)
36+
#! Change "ACCOUNT-NUMBER" and "REGION" to your needed values
37+
cdk bootstrap aws://ACCOUNT-NUMBER/REGION
38+
39+
# Install poetry (for managing Python dependencies)
40+
pip install poetry
41+
42+
# Install poetry dependencies for the virtual environment
43+
poetry install
44+
45+
46+
################################################################################
47+
# PART 3: Main CDK and Python commands (most used)
48+
################################################################################
49+
50+
# Activate Python virtual environment with Poetry tool
51+
poetry shell
52+
53+
# Run unit tests
54+
poe test-unit
55+
56+
# Deploy commands
57+
export DEPLOYMENT_ENVIRONMENT=dev
58+
cdk synth
59+
cdk deploy
60+
61+
62+
################################################################################
63+
# PART 4: Other CDK usefull commands
64+
################################################################################
65+
66+
# Help
67+
cdk --help
68+
cdk deploy --help
69+
70+
# Lists the stacks in the app
71+
cdk list
72+
73+
# Synthesizes and prints the CloudFormation template for the specified stack(s)
74+
cdk synthesize
75+
76+
# Deploys the CDK Toolkit staging stack (necessary resources in AWS account)
77+
cdk bootstrap
78+
79+
# Deploys the specified stack(s)
80+
cdk deploy
81+
82+
# Destroys the specified stack(s)
83+
cdk destroy
84+
85+
# Compares the specified stack with the deployed stack or a local CloudFormation template
86+
cdk diff
87+
88+
# Displays metadata about the specified stack
89+
cdk metadata
90+
91+
# Creates a new CDK project in the current directory from a specified template
92+
cdk init
93+
94+
# Manages cached context values
95+
cdk context
96+
97+
# Opens the CDK API reference in your browser
98+
cdk docs
99+
100+
# Checks your CDK project for potential problems
101+
cdk doctor

lambda-layers/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
all:
2+
cd fastapi && $(MAKE)
3+
4+
clean:
5+
cd fastapi && $(MAKE) clean

lambda-layers/fastapi/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
all:
2+
[ -d "modules/python" ] || pip install -r requirements.txt -t modules/python/
3+
4+
clean:
5+
rm -rf modules
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fastapi==0.98.0
2+
mangum==0.17.0

0 commit comments

Comments
 (0)