Skip to content

Commit

Permalink
MAJOR: add initial structure
Browse files Browse the repository at this point in the history
  • Loading branch information
san99tiago committed Jun 26, 2023
1 parent 998597b commit 5c29a35
Show file tree
Hide file tree
Showing 24 changed files with 2,332 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all:
cd lambda-layers && $(MAKE)

clean:
cd lambda-layers && $(MAKE) clean
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# AWS-CDK-FASTAPI-LAMBDA

Custom AWS-CDK solution with the infrastructure and code for running a FastAPI Server with Lambda Functions.

<!-- TODO: CREATE DETAILED README FILE! -->

## License

Copyright 2023 Santiago Garcia Arango.
8 changes: 8 additions & 0 deletions cdk.context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"main_resources_name": "fastapi-lambda",
"tags": {
"Owner": "Santiago Garcia Arango",
"Source": "https://github.com/san99tiago/aws-cdk-fastapi-lambda",
"Usage": "Sample project to illustrate a quick easy FastAPI deployment on Lambda Functions"
}
}
3 changes: 3 additions & 0 deletions cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "make && python3 cdk/app.py"
}
22 changes: 22 additions & 0 deletions cdk/add_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import aws_cdk as cdk


def add_tags_to_app(
app: cdk.App, main_resources_name: str, deployment_environment: str
) -> None:
"""
Function to add custom tags to app in a centralized fashion.
:param app: (aws_cdk.App) to apply tags to.
:param main_resources_name: (str) the main solution name being deployed.
:param deployment_environment: (str) value of the tag "environment".
"""

app_tags = cdk.Tags.of(app)
app_tags.add("MainResourcesName", main_resources_name)
app_tags.add("Environment", deployment_environment)

# Add tags from CDK context
context_tags = app.node.try_get_context("tags")
for key in context_tags:
app_tags.add(key, context_tags[key])
53 changes: 53 additions & 0 deletions cdk/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python3

################################################################################
# CDK SOLUTION FOR: APIGATEWAY-SQS-LAMBDA (TEMPLATE)
################################################################################

# Built-in imports
import os

# External imports
import aws_cdk as cdk

# Own imports
import add_tags
from stacks.cdk_lambda_fastapi_stack import LambdaFunctionFastAPIStack


print("--> Deployment AWS configuration (safety first):")
print("CDK_DEFAULT_ACCOUNT", os.environ.get("CDK_DEFAULT_ACCOUNT"))
print("CDK_DEFAULT_REGION", os.environ.get("CDK_DEFAULT_REGION"))


app: cdk.App = cdk.App()


# Configurations for the deployment (obtained from env vars and CDK context)
DEPLOYMENT_ENVIRONMENT = os.environ.get("DEPLOYMENT_ENVIRONMENT", "dev")
NAME_PREFIX = os.environ.get("NAME_PREFIX", "")
MAIN_RESOURCES_NAME = app.node.try_get_context("main_resources_name")


stack = LambdaFunctionFastAPIStack(
app,
"{}-{}".format(MAIN_RESOURCES_NAME, DEPLOYMENT_ENVIRONMENT),
NAME_PREFIX,
MAIN_RESOURCES_NAME,
DEPLOYMENT_ENVIRONMENT,
env={
"account": os.environ.get("CDK_DEFAULT_ACCOUNT"),
"region": os.environ.get("CDK_DEFAULT_REGION"),
},
description="Stack for {} infrastructure in {} environment".format(
MAIN_RESOURCES_NAME, DEPLOYMENT_ENVIRONMENT
),
)

add_tags.add_tags_to_app(
stack,
MAIN_RESOURCES_NAME,
DEPLOYMENT_ENVIRONMENT,
)

app.synth()
Empty file added cdk/stacks/__init__.py
Empty file.
121 changes: 121 additions & 0 deletions cdk/stacks/cdk_lambda_fastapi_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Built-in imports
import os

# External imports
from aws_cdk import (
Stack,
Duration,
CfnOutput,
aws_lambda,
RemovalPolicy,
)
from constructs import Construct


class LambdaFunctionFastAPIStack(Stack):
"""
Class to create the infrastructure on AWS.
"""

def __init__(
self,
scope: Construct,
construct_id: str,
name_prefix: str,
main_resources_name: str,
deployment_environment: str,
**kwargs,
) -> None:
super().__init__(scope, construct_id, **kwargs)

# Input parameters
self.construct_id = construct_id
self.name_prefix = name_prefix
self.main_resources_name = main_resources_name
self.deployment_environment = deployment_environment

# Main methods for the deployment
self.create_lambda_layers()
self.create_lambda_functions()

# Create CloudFormation outputs
self.generate_cloudformation_outputs()

def create_lambda_layers(self):
"""
Create the Lambda layers that are necessary for the additional runtime
dependencies of the Lambda Functions.
"""

# Layer for "LambdaPowerTools" (for logging, traces, observability, etc)
self.lambda_layer_powertools = aws_lambda.LayerVersion.from_layer_version_arn(
self,
id="LambdaLayer-Powertools",
layer_version_arn=f"arn:aws:lambda:{self.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:35",
)

# Layer for "FastAPI" and "Mangum" Adapter libraries
self.lambda_layer_fastapi = aws_lambda.LayerVersion(
self,
id="LambdaLayer-FastAPI",
code=aws_lambda.Code.from_asset("lambda-layers/fastapi/modules"),
compatible_runtimes=[
aws_lambda.Runtime.PYTHON_3_9,
aws_lambda.Runtime.PYTHON_3_10,
],
description="Lambda Layer for Python with <fastapi> library",
removal_policy=RemovalPolicy.DESTROY,
)

def create_lambda_functions(self):
"""
Create the Lambda Functions for the FastAPI server.
"""
# Get relative path for folder that contains Lambda function source
# ! Note--> we must obtain parent dirs to create path (that"s why there is "os.path.dirname()")
PATH_TO_LAMBDA_FUNCTION_FOLDER = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
"src",
"lambdas",
)
self.lambda_fastapi: aws_lambda.Function = aws_lambda.Function(
self,
id="Lambda-FastAPI",
runtime=aws_lambda.Runtime.PYTHON_3_9,
handler="api/main.handler",
code=aws_lambda.Code.from_asset(PATH_TO_LAMBDA_FUNCTION_FOLDER),
timeout=Duration.seconds(30),
memory_size=128,
environment={
"ENVIRONMENT": self.deployment_environment,
"LOG_LEVEL": "DEBUG",
"STATE_MACHINE_ENABLED": "true",
},
layers=[
self.lambda_layer_powertools,
self.lambda_layer_fastapi,
],
)

self.lambda_function_url = self.lambda_fastapi.add_function_url(
auth_type=aws_lambda.FunctionUrlAuthType.NONE,
)

def generate_cloudformation_outputs(self):
"""
Method to add the relevant CloudFormation outputs.
"""

CfnOutput(
self,
"DeploymentEnvironment",
value=self.deployment_environment,
description="Deployment environment",
)

CfnOutput(
self,
"LambdaFunctionUrl",
value=self.lambda_function_url.url,
description="URL to invoke Lambda Function",
)
101 changes: 101 additions & 0 deletions important_commands.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/bin/bash

################################################################################
# PART 1: Configure NodeJs, Python and CDK libraries
################################################################################

# Install NodeJs and Python
# --> https://nodejs.org/en/download/
# --> https://www.python.org/downloads/

# Verify that NodeJs/npm is installed correctly
node --version
npm --version

# Verify that Python/pip is installed correctly
python --version || python3 --version
pip --version || pip3 --version

# Install AWS-CDK (on NodeJs)
sudo npm install -g aws-cdk

# Verify correct install of AWS-CDK
npm list --global | grep aws-cdk


################################################################################
# PART 2: Initial Project Setup (Only run these at the beginning)
################################################################################

# Configure AWS credentials (follow steps)
aws configure
# --> Alternative 1: Environment variables added to terminal session
# --> Alternative 2: AWS Cloud9 with the right permissions

# Bootstrap CDK (provision initial resources to work with CDK.. S3, roles, etc)
#! Change "ACCOUNT-NUMBER" and "REGION" to your needed values
cdk bootstrap aws://ACCOUNT-NUMBER/REGION

# Install poetry (for managing Python dependencies)
pip install poetry

# Install poetry dependencies for the virtual environment
poetry install


################################################################################
# PART 3: Main CDK and Python commands (most used)
################################################################################

# Activate Python virtual environment with Poetry tool
poetry shell

# Run unit tests
poe test-unit

# Deploy commands
export DEPLOYMENT_ENVIRONMENT=dev
cdk synth
cdk deploy


################################################################################
# PART 4: Other CDK usefull commands
################################################################################

# Help
cdk --help
cdk deploy --help

# Lists the stacks in the app
cdk list

# Synthesizes and prints the CloudFormation template for the specified stack(s)
cdk synthesize

# Deploys the CDK Toolkit staging stack (necessary resources in AWS account)
cdk bootstrap

# Deploys the specified stack(s)
cdk deploy

# Destroys the specified stack(s)
cdk destroy

# Compares the specified stack with the deployed stack or a local CloudFormation template
cdk diff

# Displays metadata about the specified stack
cdk metadata

# Creates a new CDK project in the current directory from a specified template
cdk init

# Manages cached context values
cdk context

# Opens the CDK API reference in your browser
cdk docs

# Checks your CDK project for potential problems
cdk doctor
5 changes: 5 additions & 0 deletions lambda-layers/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all:
cd fastapi && $(MAKE)

clean:
cd fastapi && $(MAKE) clean
5 changes: 5 additions & 0 deletions lambda-layers/fastapi/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all:
[ -d "modules/python" ] || pip install -r requirements.txt -t modules/python/

clean:
rm -rf modules
2 changes: 2 additions & 0 deletions lambda-layers/fastapi/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fastapi==0.98.0
mangum==0.17.0
Loading

0 comments on commit 5c29a35

Please sign in to comment.