Cover image

Levels of Infrastructure Deployment

January 24, 2023

6 min read

Introduction

Copy heading link

Early last year I worked on a personal full-stack project using AWS Amplify. I had abandoned the project since, and only recently decided to revive it. The issue that I ran into was that I had already deleted the existing resources off AWS and the Amplify codebase was still referencing those references. After jumping through many hoops and a lot of googling, I could not successfully spin up the project again and re-deploy it on AWS Amplify. My only choice was to use the Amplify CLI to create each resource 1 by 1 (DynamoDB, Lambdas, Cognito Pool, Federated Signin configurations etc.).

Through my full-time job, we were in the process of moving one of our projects from Serverless to AWS CDK and boy was that a game changer. To fully appreciate the evolution of infrastructure as code we must take it back to the beginning.

Level 1 - AWS console

Copy heading link

The classic AWS web interface. Besides having one of the most hideous UI designs on the internet, it's super easy to quickly search for an AWS service and quickly create a resource. This is of course a very manual method of creating resources and is not feasible for large projects that require hundreds of resources. Imagine creating and uploading Lambdas one by one for each of your environments.

Level 2 - Cloud formation templates

Copy heading link

The Cloud Formation template is the purest form of infrastructure as code for AWS. It is in JSON format and can easily be moved from one environment to another to replicate resources. Unfortunately the JSON file is not very easy to write without memorising all the valid keys and value options beforehand.

Level 3 - Amplify

Copy heading link

The Amplify CLI I used to spin up a full stack environment as an alternative to something like Firebase. It extracts away the need to know how to write a CloudFormation template and generates the template for you as you use the CLI to create resources, one by one. This method works well for small-scale applications, but if you have a larger application that has over 30 lambdas, multiple S3 triggers etc, the creation of resources could get really tedious via the CLI prompts. Not to mention that Amplify is a large abstraction over many other AWS services which gives you less flexibility on how you want to configure the resources.

Level 4 - Serverless

Copy heading link

Serverless is a framework designed to implement a common language that can spin up resources for cloud providers. It supports AWS, GCP, Azure and many more. Serverless for the most part does well in AWS resource creation and handling multiple environments (dev, staging, uat, prod etc). It has a large plugin ecosystem (this can be seen as a pro or a con) that helps with additional functionality such as packaging (e.g. serverless-webpack) or handling of environment variables (e.g. serverless-dotenv-plugin). The plugins are written by the Serverless community which sometimes has bugs or very limited support. My main criticisms on using Serverless are the .yml file feels clumsy and is prone to mistakes (much like writing your own CloudFormation template), lacks type safety or IDE autocomplete and that does not handle CloudFormation stack limitations of 500 resources well. For small to mid projects, Serverless is a fine option.

Level 5 - AWS CDK

Copy heading link

My newest favourite kid on the block. From the official docs:

The AWS CDK lets you build reliable, scalable, cost-effective applications in the cloud with the considerable expressive power of a programming language.

The fact that you can describe your infrastructure using your language of choice, whether it's TypeScript, JavaScript, Java, Go, Python or C#, it means that your dev team does not need to learn a new language to add resources.

As a TypeScript developer, I can take full advantage of type safety, IDE autocomplete support, use of enums to restrict invalid values, utilize object-oriented paradigms, re-use variables and functions and use any external library from the node ecosystem. Here is an example of how a Lambda could be described:

TypeScript
  • Line 8 uses the native NodeJS path package to form a path to the lambda.
  • Line 9 extracts the table name from a DynamoDB instance, instead of manually typing the table name in multiple places and possibly mis-spelling it.
  • Line 11 takes advantage of a class instance that describeds an AWS policy statement.
  • Line 14 dynamically interpolates the DynamoDB ARN as this ARN does not exist yet.
  • Lines 17, 18 and 20 take advantage of enums from the aws-cdk-lib package to restrict allowed values for those keys.

I can even go one step further and create a custom Lambda construct class to promote re-usability and consistency:

TypeScript

Now every time I need to spin up a lambda, I just create a new instance LambdaConstruct and I know the parameters will be consistent with every other Lambda created previously.

Another bonus of using CDK is that my Lambdas are written in TypeScript and CDK automatically compiles them, bundles them using esbuild and uploads them for me. No plugins like serverless-webpack required.

In the end, when running cdk synth in the CDK CLI, it creates a Cloud Formation template and running cdk deploy will push the resources to the cloud. A simple cdk destroy command can quickly tear down resources if they are no longer required.

Newsletter