Servicefull


June 30, 2019 / 8 minutes / #AWS #CDK #Terraform #Cloud

Comparison of AWS Cloud Development Kit with Terraform by building 2-tier Web App

As AWS Architect my day-to-day job includes writing a lot of Terraform code in HCL.

While I really like TF, in few places it's really verbose and some quirks of HCL are frustrating. So, I decided to take AWS Cloud Development Kit for a spin and get my hands dirty by building a simple 2-tier AWS infra like this:

Schema

Key points

    VPC with two subnets (public and private) in each AZ, IPGW as 0.0.0.0/0 route in public subnet, NAT Gateway as 0.0.0.0/0 route in private subnet

    ECS Cluster running Fargate cluster with Node.js service and task

    Application Load Balancer exposed to the public connected to the Fargate service

    Public S3 bucket with assets

    IAM Role for task to manipulate S3 Bucket

    Postgres DB instance in private subnet, accessible only from ECS tasks

Before getting into actions I've listed a couple of obvious differences which didn't require any practice from me:

Terraform

Written in HCL

Declarative

Supports multiple providers

SDK calls under the hood

Modules

CDK

Written in TS, Java or Python

Imperative

AWS Only

Cloudformation under the hood

Constructs

After result of few hours fight with both tools, I present you...

My Outcomes

Imperative nature of the language used in CDK might be counterintuitive for declaring things like infrastructure where the end state is the most important thing. This might be even tricky due to async nature of JS (e.g. for loop with async) but when used correctly pays off in better possibilities to express collection operations. This has been improved greatly in Terraform 0.12, however, it's still far from flexibility and easy of use that we're used from ES6 spec like Array.filter(...).map(...).reduce(...) etc.

CDK API changes pretty quickly, some of the examples are outdated and require some adjustments like loadBalancer.loadBalancerDnsName vs loadBalancer.dnsName.

When bootstrapping a project make sure you're running the same version of CLI and all the modules. Otherwise you might face some cryptic errors and lose unnecesary amount of time debugging them.

In CDK nomenclature "Modules" are called "Constructs". Unlike Terraform, CDK comes with a bunch of really robust constructs like ecs.LoadBalancedFargateService which encapsulate hundreds of CloudFormation or Terraform code in just 10 or even less. While this is really useful this tradeoff is not without any compromises. Some of these modules are really implicit and you end up digging in the source code wondering what are the required params, what's included and how it should plug to the rest of your infra.

Using the same language for both code, configuration and infrastructure makes whole process of development really seamless. Also, when writing in a language with type completion and properly configurated IDE, it just feels super nice, all the parts "fit" like lego.



Really refreshing comparing to writing huge YAML or JSON files. However, going with Python where there is no static typing I couldn't see big benefit. Plus, Troposphere is with us already for a moment.


Also the amount of code is much less in CDK:

➜ find ./cdk/lib -name "*.ts" | xargs cat | wc -l 105 ➜ find ./terraform -name "*.tf" | xargs cat | wc -l 516


If you're interested in final result, you can find the repo with code here!. After pulling it, simply execute ./build-and-push.sh to create an AWS Elastic Container Registry, build the Docker image and push it to the cloud. It will be used by both infras.

Agree? Disa̶g̶r̶e̶e̶? Discuss it on Twitter

Rafal Wilinski

Written by Rafal Wilinski, certified AWS Architect, Serverless enthusiast and consultant. You may find me on Twitter