DEV Community

Cover image for How to prototype cloud solutions with AWS CDK?
Jakub Gaj for Chmoora

Posted on • Updated on • Originally published at chmoora.io

How to prototype cloud solutions with AWS CDK?

Prerequisites

This article assumes that you are somehow familiar with the AWS Cloud Development Kit framework and its concepts. Otherwise, I'd highly recommend you to check the following resources before continuing:

AWS CDK v2 Developer Guide
https://docs.aws.amazon.com/cdk/v2/guide
AWS CDK Workshop
https://cdkworkshop.com/

Infrastructure as Code

As a cloud architect, I have to design different cloud-based solutions almost on a daily basis. Depending on the requirements, the size & complexity of each solution might differ, of course. What I usually need is a proof of concept, a proof that the overall idea will eventually work as designed. Also, if selected AWS services can interact with each other out-of-the-box, or will I have to glue some of the bits together in low-code or some-code fashion, for example with custom Lambda functions.

Clicking things out straight on the AWS Management Console is probably the most common way of prototyping in a sandbox environment. I'm sure we've all been there. AWS just makes it super easy to connect different services, in most cases at least.

One of the pros of this approach is that the AWS console wizards can automatically create any necessary IAM roles and related permissions embedded in IAM policies. Downside is that at some point I might need to write it all down as Infrastructure as Code, for obvious reasons. CloudFormation is a native choice for any AWS developer, but building more complex solutions requires very fast fingers to generate that beautiful YAML code (or the ugly JSON, if you're hardcore enough).

I still have a repository of own CloudFormation templates and snippets, which I can reuse anytime in a modular way in combination with CF features like macros, nested stacks, stack sets, etc. The problem is that any larger solution generates tons of YAML code, which is quite hard to maintain and refactor.

By entering the world of AWS CDK, I could easily avoid some of the CF templates horror stories. In the beginning I didn't like the framework at all, mostly because it was a bit too overwhelming to work with. I've decided to give it another try when Python became one of the supported languages. I must admit, it took me few tries to get used to CDK's concept and to discovered the true potential of this framework.

Today I can say honestly that I do enjoy developing my AWS solutions in CDK. They usually end up as multiple CDK apps with multiple CDK stacks and deployed to multiple AWS accounts and/or regions. My CDK apps get deployed automatically from different CI/CD pipelines, as CDK can handle deployments of CloudFormation stacks pretty well in very automated fashion.

Constructs and patterns

For me the true power of the AWS CDK framework lays in so called CDK Constructs. My current solutions portfolio consists of CDK constructs for commonly used architectural patterns, which I often use as a skeleton for any AWS-based infrastructures. A perfect example would be 3-tier VPC networking with all the bells and whistles, conditionally deployed or not depending on the target environment (dev, prod, etc). Sounds familiar?

In this post I wanted to show you some of the publicly available repositories of architectural patterns and solution constructs, which I find very useful, especially for some quick & dirty developments. The constructs basically allow for very rapid prototyping, as most of them deploy all the necessary infrastructure resources, or allow me to specify existing ones instead (for example, the VPC).

AWS Construct Library

This is basically a list of L3 Constructs, also just called patterns. They are part of AWS CDK API Reference and can be found under aws-cdk-lib.aws_{service}_patterns.

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html

Application Load Balanced Fargate Service

This is one of my favourite construct, as it deploys quite common pattern: Application Load Balancer with ECS service running in ECS Fargate cluster.

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns.ApplicationLoadBalancedFargateService.html

const domainName = 'aws.chmoora.io';

const hostedZone: r53.IHostedZone = r53.HostedZone.fromLookup(this, 'Zone', {
  domainName: domainName,
  privateZone: false
});

const vpc: ec2.IVpc = ec2.vpc.fromLookup(this, 'Vpc', {
  vpcName: 'myapp-vpc',
  isDefault: false,
});

new ecs.ApplicationLoadBalancedFargateService(this, 'Fargate', {
  vpc: vpc,
  desiredCount: 1,
  memoryLimitMiB: 1024,
  cpu: 512,
  assignPublicIp: false,
  protocol: elbv2.ApplicationProtocol.HTTPS,
  domainName: `myapp.${domainName}`,
  domainZone: hostedZone,
  taskImageOptions: {
    image: ecs.ContainerImage.fromRegistry("nginx:latest"),
  },
  taskSubnets: {
    subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS
  },
});
Enter fullscreen mode Exit fullscreen mode

With default values CDK will generate CF resources for a new VPC, ECS cluster, ECS service, Application Load Balancer, etc. I can enforce HTTPS protocol to generate a TLS certificate stored in Certificate Manager, based on custom domain name defined in Route 53 public Hosted Zone. And that's it! Here's my containerised Nginx server running on ECS cluster behind ALB with HTTPS listener.

In the above example I'm relying on existing VPC and Route 53 Hosted Zone, which I'm importing inside my CDK stack. How does it work exactly? Well, CDK will lookup in my target AWS account(s) for specific AWS resources, then will cache their ARNs in cdk.context.json file, which is part of the CDK app. Pretty cool, huh? :)

Also, I can make my solution a bit more production ready, for example by adding some CloudFront distribution and WAF WebACLs for extra layer of protection.

AWS Solutions Constructs

This AWS CDK extension provides some multi-service, well-architected patterns for quickly defining whole solutions in code. It's nothing more but a browsable and searchable library of open-source patterns, which you can use in your CDK projects.

https://aws.amazon.com/solutions/constructs/patterns/
https://docs.aws.amazon.com/solutions/latest/constructs

The library contains some of the commonly used patterns, for example:

API Gateway to Lambda
https://docs.aws.amazon.com/solutions/latest/constructs/aws-apigateway-lambda.html

EventBridge to Lambda
https://docs.aws.amazon.com/solutions/latest/constructs/aws-eventbridge-lambda.html

EventBridge to Step Functions
https://docs.aws.amazon.com/solutions/latest/constructs/aws-eventbridge-stepfunctions.html

CloudFront to S3
https://docs.aws.amazon.com/solutions/latest/constructs/aws-cloudfront-s3.html

Constructs Hub

Another great source of CDK constructs is the Constructs Hub. This extensive library contains CDK patterns from different publishers, for different programming languages and also patterns for CDK extensions, like CDKCF (CDK for Terraform) or CDK8s (CDK for Kubernetes).

https://constructs.dev/

Temporary Stack

Have you ever forgot to destroy your playground CF stacks on friday afternoon and the AWS resources kept running over weekend, incuring some costs connected to your credit card? We've all been there, trust me :) Wouldn't be nice to be able to automatically destroy your AWS resources deployed with CF stack(s) after specific period of time, let's say after X number of hours or days?

This community provided CDK construct called TempStack by CloudComponents does exactly that. Simply add TimeToLive resource to your CDK stack, which will deploy couple of resources handling the lifecycle of the CF stack, namely Lambda function and EventBridge rule to trigger it on schedule. The absolute coolness!

https://constructs.dev/packages/@cloudcomponents/cdk-temp-stack/

import { Construct } from 'constructs';
import { Stack, StackProps, Duration } from 'aws-cdk-lib';
import { TimeToLive } from '@cloudcomponents/cdk-temp-stack';
import { Vpc, IpAddresses, IpAddresses } from 'aws-cdk-lib/aws-ec2';

export class MyPlaygroundVpcStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    new TimeToLive(this, 'Ttl', {
      ttl: Duration.days(1),
    });

    new Vpc(this, 'Vpc', {
      vpcName: 'my-playground-vpc',
      ipAddresses: IpAddresses.cidr('10.10.100.0/24'),
      maxAzs: 2,
      natGateways: 1,
      enableDnsHostnames: true,
      enableDnsSupport: true,
      subnetConfiguration: [
        {
          cidrMask: 26,
          name: 'entry',
          subnetType: SubnetType.PUBLIC,
        },
        {
          cidrMask: 26,
          name: 'app',
          subnetType: SubnetType.PRIVATE_WITH_EGRESS,
        }
      ]
    });

  }
}
Enter fullscreen mode Exit fullscreen mode

Summary

I hope this post will inspire you a bit to play around with CDK constructs in your current or future projects. It would be great if you'd share in the comments any constructs from provided resources, which you've found particularly useful or worth checking out. Also, feel free to share any repositories with your own CDK constructs you've developed & published in the past, I'd love to have a look!

Have fun! :)

Top comments (0)