DEV Community

Cover image for Go fast and reduce risk: using CDK to deploy your serverless applications on AWS
Joe Stech for AWS Community Builders

Posted on

Go fast and reduce risk: using CDK to deploy your serverless applications on AWS

There are a truly absurd number of ways to deploy applications on AWS. Corey Quinn wrote two separate articles wherein he described 17 ways to deploy containers on AWS -- that's 34 different ways just to deploy containers (granted, some of the listed ways to deploy are farcical).

All of these options inevitably spawn fights about the "right" way to deploy on AWS. I'm now going to explain my preferred way to deploy a serverless API, and then you can fight me.

The best way to deploy your serverless API on AWS:

  1. Write your API business logic code in a way that can be run on AWS Lambda.
  2. Write a CDK template in the same language as your Lambda function code and store along with your Lambda function code in source control (I'm going to assume you're using git here, but use whatever source control you want).
  3. Deploy your serverless API from your git commit as a self-contained unit.

There's a lot to unpack here, but the main thing I want convey here is that it is awesome to write your executable code and your IaC templates in the same language.

Your CDK template

So what is CDK? It's the AWS 'Cloud Development Kit', and it basically lets you transpile your language of choice (as long as that language is either JavaScript, TypeScript, Python, Java, C#, or Go) into CloudFormation. This is awesome, because you don't have to deal with a weird domain specific language for your IaC or manage state files for your IaC (looking at you, Terraform).

In the case of a serverless API, these are the main things you'll want in your CDK code:

  1. IAM policies that limit your lambda permissions using the principle of least privilege.
  2. A Lambda resource that you'll deploy your code to.
  3. An API Gateway resource (RestApi) that you'll point at your Lambda.

There are a bunch of other services you could include here (RDS database, dynamoDB, etc etc) if you need them, but that's the beauty of this system -- you're not limited by a specific serverless framework, you can just add arbitrary services to your CDK code as you need them.

Here's a bare-bones version of a serverless CDK stack file in Python (you can also write these files in JavaScript, TypeScript, Java, C#, or Go), so you can see what I mean (everything has the generic name "somestack", which you can replace with a more meaningful name):

from aws_cdk import (
aws_lambda as lambda_,
aws_apigateway as apigw,
aws_iam as iam,
aws_ecr as ecr,
Stack)
from constructs import Construct
import os

class SomeStackName(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Create the Lambda execution role
        lambda_role = iam.Role(self, id="somestack-lambda",
            role_name='SomestackManagementRole',
            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
            managed_policies= [
                        iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaVPCAccessExecutionRole"),
                        iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaBasicExecutionRole")
                    ]
        )
        # Get an existing ECR repo that has a docker image you want to deploy to Lambda
        repo = ecr.Repository.from_repository_name(self, "SomestackRepo", "somestack_ecr_repo")
        # Create the Lambda function
        somestack_lambda = lambda_.DockerImageFunction(self,
            "SomestackLambda",
            code=lambda_.DockerImageCode.from_ecr(
                repository=repo,
                tag=some_image_tag_name
                ),
            role=lambda_role
        )

        # Create the API Gateway
        api = apigw.LambdaRestApi(self,
            "somestack-endpoint",
            handler=somestack_lambda,
            default_cors_preflight_options=apigw.CorsOptions(allow_origins=["*"])
        )
Enter fullscreen mode Exit fullscreen mode

That's all the Infrastructure as Code that you need to create a serverless API! You can learn more from the official CDK developer guide.

The actual development workflow

So now you have your CDK IaC written and you're ready to start incorporating it into a real devops pipeline. What does the day-to-day development process look like?

  1. Make a branch.
  2. Make some Lambda code changes, some CDK changes, whatever, and push your branch.
  3. A git server webhook should trigger a CDK build to test your Infrastructure as Code (IaC). This webhook also runs some tests on your temporarily built environment to make sure you have no regressions.
  4. Merge your branch into main (master, whatever you call it).
  5. Another git server webhook that only triggers on main branch commits deploys your code to your dev environment (which can then be promoted to stage/prod as necessary)

Now you're ready to build serverless, production-grade APIs with incredible speed and very little risk! You don't have to have a team of engineers doing server maintenance, and you can spin up as many independent microservices as you need to without worrying about autoscaling policies or cluster management. It's an incredibly powerful pattern for certain types of software.

Oldest comments (3)

Collapse
 
vince_bighire_tools profile image
Vince Fulco (It / It's)

One of the biggest problems for noob / beginner-intermediate developers is the paradox of choice in the AWS universe. Slows down learning tremendously getting a 10K view of the landscape

Collapse
 
joestech profile image
Joe Stech

100% true. That's one reason I present things in an opinionated way -- I've evaluated dozens of deployment options, and this is the one that balances short-term and long-term developer friction the best for cloud-based APIs that don't require highly optimized response times. There are lots of options that are quicker to initially deploy with (including just clicking around in the AWS console!), but they immediately become productivity destroyers when multiple developers start adding features to a production product. This pattern accounts for that.

Collapse
 
vince_bighire_tools profile image
Vince Fulco (It / It's)

Very well done. Thanks.