How-to-use-AWS-CDK-to-deploy-Python-Lambda-function

AWS CDK Python Lambda Deployment Example

The AWS Cloud Development Kit (AWS CDK) is an open-source development framework to model and provision your cloud application resources using popular programming languages like Typescript, Javascript, Python, Java, and C#. This AWS CDK Python Lambda deployment example demonstrates how to deploy the Python Lambda function using AWS CDK.

Every AWS resource in AWS CDK is implemented in a module called the “construct.” Constructs are the basic building blocks of AWS CDK applications. In AWS CDK apps, you define your infrastructure as code using constructors for each type of AWS resource you want to include. Each construct has an ID and a logical name, which you can use to reference the construct in your code. For example, you might use constructors to create an Amazon S3 bucket, an Amazon DynamoDB table, or an Amazon SQS queue.

By calling these constructors from within your app, you can easily add new resources to your infrastructure without manually editing template files or JSON configurations. In addition, constructors can be used to declare dependencies in line with your resources so that you can ensure that resources are created in the correct order. For example, you might want to ensure that an Amazon S3 bucket is created before an Amazon DynamoDB table.

Using constructors, you can easily express these relationships in your code. As a result, constructors provide a powerful way to organize and manage AWS CDK applications.

Here’s a great bit more in-depth explanation of What is the AWS CDK.

I personally like AWS CDK because:

  • AWS CDK constructs defaulted to AWS best practices – for example, if you declare a VPC without any parameters, AWS CDK will use the latest AWS best practices recommendations to build the VPC and all related infrastructure.
  • I can prototype any infrastructure in minutes.
  • Ultimately, I can get a CloudFormation template that may be used independently without AWS CDK.

I’m a big fan of Python, so we’ll concentrate on this beautiful programming language.

Before we begin, several must-know resources:

  • AWS Cloud Development Kit – here, you’ll find documentation on all available Python modules.
  • AWS CDK Intro Workshop for Python – you need to spend ~20 mins here to get a taste of AWS CDK.
  • AWS CDK GitHub repository with lots of examples – an excellent starting point if you’re looking for an example of boilerplate code.
  • AWS Toolkit for Visual Studio Code – an open-source plug-in for Visual Studio Code makes it easier to create, debug, and deploy applications on Amazon Web Services.

AWS SAM vS. AWS CDK

AWS SAM and CDK are AWS infrastructure as code (IAC) tools. AWS SAM is an open-source framework that allows you to define and manage AWS resources using AWS CloudFormation templates. AWS CDK is a new IAC tool that allows you to define AWS resources using familiar programming languages such as TypeScript, JavaScript, Python, and Java.

AWS SAM and AWS CDK allow you to define AWS resources such as Amazon S3 buckets, Amazon DynamoDB tables, Amazon SQS queues, etc. However, AWS CDK has a few advantages over AWS SAM:

  • First, AWS CDK allows you to use a familiar programming language instead of YAML or JSON. This can be a big advantage if you’re more comfortable coding in Python than writing CloudFormation templates.
  • Second, AWS CDK has a library of pre-built “constructs” that make creating common AWS resources such as VPCs, IAM roles, and AWS Lambda functions easy.
  • Lastly, AWS CDK integrates natively with the rest of the AWS ecosystem, making it easy to deploy your infrastructure changes and application code.

Example of AWS CDK Python project (Cron Lambda Job)

Serverless CRON Jobs

The AWS CRON Using Lambda Functions And Terraform article covered how to create a Serverless Cron job using CloudFormation and Terraform. Let’s build the same functionality (the Cron job to delete outdated AMIs) but with the help of AWS CDK.

AWS CDK Python Lambda Project structure

I’m assuming that you already installed AWS CDK. If not, here’s how to install AWS CDK.

Here’s our AWS CDK project structure:

tree
.
├── app.py
├── cdk.json
├── lambda-handler.py
└── requirements.txt
0 directories, 4 files
  • lambda-handler.py – our new Lambda function code from the previous example.
  • requirements.txt – required constructs, which we need to build an example.
  • cdk.json – AWS CDK runtime context configuration.
  • app.py – AWS CDK application module where we’re describing infrastructure.

Now, let’s look at the files.

AWS CDK application requirements

The requirements.txt file contains the following content:

aws-cdk.aws-events
aws-cdk.aws-events-targets
aws-cdk.aws-lambda
aws-cdk.core

AWS CDK Python Lambda application code

Those contents which install dependencies allow you to use AWS CloudWatch Events and AWS Lambda constructs in your app.py AWS CDK application code. Let’s code the AWS CDK Lambda Python example by importing the following python bundles and block of code below:

from aws_cdk import (
    aws_events as events,
    aws_lambda as lambda_,
    aws_events_targets as targets,
    core,
)

class LambdaCronStack(core.Stack):
    def __init__(self, app: core.App, id: str) -> None:
        super().__init__(app, id)
        with open("lambda-handler.py", encoding="utf8") as fp:
            handler_code = fp.read()
        lambdaFn = lambda_.Function(
            self, "ami-cleanup-lambda",
            code=lambda_.InlineCode(handler_code),
            handler="index.handler",
            timeout=core.Duration.seconds(900),
            runtime=lambda_.Runtime.PYTHON_3_9,
        )
        rule = events.Rule(
            self, "Rule",
            schedule=events.Schedule.rate(core.Duration.days(1)),
        )
        rule.add_target(targets.LambdaFunction(lambdaFn))

app = core.App()
LambdaCronStack(app, "Lambda-Cron-Delete-AMIs")
app.synth()

The code itself is pretty straightforward. We’re importing the required modules and declaring the Python class, which contains the description of the AWS Lambda function and CloudWatch Events. The aws_lambda.Function constructor accepts many arguments to configure the AWS Lambda function, such as function name, handler method, execution timeout, required runtime, environment variables, etc.

AWS CDK Python Lambda handler code

Our simple Lambda function code is located in the lambda-handler.py file, which we’re reading into the handler_code Python variable and use in the aws_lambda.Function constructor:

"""
AWS Lambda function to remove outdated AMIs
All credits: https://gist.github.com/luhn/802f33ce763452b7c3b32bb594e0d54d
"""
import logging
import os
import re
import sys
from datetime import datetime, timedelta
import boto3
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)
ACCOUNT_ID = os.environ.get('ACCOUNT_ID')
AMI_MAX_AGE = int(os.environ.get('AMI_MAX_AGE', 14))
EC2 = boto3.resource("ec2")
EC2_CLIENT = boto3.client("ec2")
def handler(event, context):
    """handler function"""
    # pylint: disable=R0914,C0103,W0613
    my_amis = EC2_CLIENT.describe_images(Owners=[ACCOUNT_ID])['Images']
    used_amis = {
        instance.image_id for instance in EC2.instances.all()
    }
    LOGGER.info('used_amis: %s', used_amis)
    fresh_amis = set()
    for ami in my_amis:
        created_at = datetime.strptime(
            ami['CreationDate'],
            "%Y-%m-%dT%H:%M:%S.000Z",
        )
        if created_at > datetime.now() - timedelta(AMI_MAX_AGE):
            fresh_amis.add(ami['ImageId'])
    LOGGER.info('fresh_amis: %s', fresh_amis)
    latest = dict()
    for ami in my_amis:
        created_at = datetime.strptime(
            ami['CreationDate'],
            "%Y-%m-%dT%H:%M:%S.000Z",
        )
        name = ami['Name']
        if(
                name not in latest
                or created_at > latest[name][0]
        ):
            latest[name] = (created_at, ami)
    latest_amis = {ami['ImageId'] for (_, ami) in latest.values()}
    LOGGER.info('latest_amis: %s', latest_amis)
    safe = used_amis | fresh_amis | latest_amis
    for image in (
            image for image in my_amis if image['ImageId'] not in safe
    ):
        LOGGER.info('Deregistering %s (%s)', image['Name'], image['ImageId'])
        EC2_CLIENT.deregister_image(ImageId=image['ImageId'])
    LOGGER.info('Deleting snapshots.')
    images = [image['ImageId'] for image in my_amis]
    for snapshot in EC2_CLIENT.describe_snapshots(OwnerIds=[ACCOUNT_ID])['Snapshots']:
        LOGGER.info('Checking %s', snapshot['SnapshotId'])
        r = re.match(r".*for (ami-.*) from.*", snapshot['Description'])
        if r:
            if r.groups()[0] not in images:
                LOGGER.info('Deleting %s', snapshot['SnapshotId'])
                EC2_CLIENT.delete_snapshot(SnapshotId=snapshot['SnapshotId'])
if __name__ == "__main__":
    handler(None, None)

The defined above AWS Lambda function is responsible for deleting old EC2 instances AMIs and volume snapshots. To create the vital Python function, define the handler function. The handler Python function is the Lambda function “main” method and the wintry point. We’re using the Boto3 EC2 client and resource to query the required information and delete AWS resources. For more information about the topic, check out our Python Boto3 Tutorials and Boto3 Snapshots and AMIs – Complete Tutorial.

Note: we strongly encourage you to unit test the Lambda function code before deploying it to the cloud environment.

If you’d like to define several Python Lambda functions, you need to create separate files for storing their source code and define several aws_lambda.Function constructors. For example, building the AWS CDK application containing several Python Lambda functions is common when building an orchestrated Step Functions workflow.

The Step Functions allow you to tie several AWS Lambda functions in a single workflow where every AWS Lambda function might be executed in a specific order and under certain conditions. Сheck out the AWS Step Functions Long Running Task Example article for more information about handling AWS Step Functions long-running tasks.

The cdk.json contains the default context for Python AWS CDK applications:

{
    "app": "python3 app.py"
}

This default context is required by AWS CDK Cloud assemblies or templates that define the AWS resources that make up a cloud application. They are used to provision and manage cloud resources and interact with AWS services, which requires AWS CLI to be accessed. Cloud assemblies can define both simple and complex applications and can be deployed to multiple AWS Regions.

Assemblies can be created using the AWS CDK Command Line Interface (AWS CLI) or the AWS CDK suite of tools. Once an assembly is defined, it can be deployed to an AWS account using the AWS CDK deploy command. Before deployment, AWS CDK creates a Lambda package (a zip file with the Lambda function) with the Python-based Lambda Layer and uploads it to the S3 bucket, where it will be consumed by the CloudFormation stack responsible for CDK application deployment.

AWS CDK application deployment

The CDK deploys defined resources into your AWS account through safe and idempotent operations. This means you can deploy your CDK apps repeatedly without creating duplicate resources or modifying existing ones. The CDK CLI interacts with your AWS account and deploys the resources defined in your code. The CLI uses the AWS SDK under the hood, supporting all of the same features and functionality.

However, the CLI also provides several helpful commands and features that make it easier to work with your resources. For example, you can use the CLI to generate sample code for your resources, view diffs between your local code and the deployed resources, and invoke Lambda functions defined in your code.

To deploy the AWS CDK application, you need to install only the environment variable, which will require Python modules, to be more specific, which is the requirements.txt for accessing private Python repositories with their exact versions first:

python3 -m venv .env
source .env/bin/activate
pip install -r requirements.txt

Now you’re ready to deploy the application:

cdk deploy

As soon as you change something in your application, you may deploy your changes again using the same command.

That’s it! So simple. Maybe you do not see all the benefits of using AWS CDK from this simple example, but the amount of code you’re writing is significantly less for larger projects.

To destroy your changes, run:

cdk destroy

Additional AWS CDK Python examples

AWS CDK examples for Python can be found at the following resources:

Summary

In this article, we’ve covered how to use AWS CDK to deploy the AWS Lambda function. There are other ways to deploy Lambda functions, such as using the Lambda Layers along with the Docker platform, with its entirely custom docker images, and the Code Artifact PyPi repo, which you can call within the Lambda function. So make sure to check them all out! We hope this article will save you some amount of time.

If you find this article useful, please help spread it to the world!

Similar Posts