A quick intro to the AWS CDK for Go

AWS has released a developer preview version of the CDK for Go. Considering I haven’t had the chance to use CDK yet, and I spend chunks of my time wrestling CloudFormation, I thought I’d install it in a new project and see why people are singing its praises.

What is AWS CDK?

AWS Cloud Development Kit (or CDK) is a framework that allows you to define your AWS infrastructure as code. It comes in several languages: TypeScript, JavaScript, Python, Java, C#/.Net and now a Go beta. Under the hood, regardless of which language implementation you use, it’s essentially a wrapper for CloudFormation. Everybody loves CloudFormation, right?

Why use CDK over CloudFormation?

1. It’s not CloudFormation

The main reason I can think of is that it’s not YAML or JSON. I’ve always preferred YAML to JSON for AWS configuration as it allows you to write comments and is somewhat easier to read. JSON has the benefit of being structurally correct, and you’re not going to get bitten by a lousy tab or array. Still, both are horrible as configuration languages. Combined with AWS’s inconsistent and often hard to use documentation, it can feel like a very laborious task to spin up new stacks.

By moving the configuration reference into a Go import, you can take advantage of code search and largely avoid the documentation altogether. Even if this is all that CDK does, I’m a convert already.

How nice is this?

VSCode autocomplete

2. It’s testable

Another benefit is that you can write unit tests for your configurations.

In this example, we will declare a simple Route53 record to create a new Hosted Zone.

stack := awscdk.NewStack(scope, &id, &sprops)

// Define the Public Hosted Zone
awsroute53.NewPublicHostedZone(stack, jsii.String("website.com"), &awsroute53.PublicHostedZoneProps{
    ZoneName: jsii.String("website.com"),
})

Now let’s write a test for the Hosted Zone.

func TestDNSStack(t *testing.T) {
    app := awscdk.NewApp(nil)
    stack := NewDNSStack(app, "DNSStack", nil)

    bytes, err := json.Marshal(app.Synth(nil).GetStackArtifact(stack.ArtifactId()).Template())
    if err != nil {
        t.Error(err)
    }

    template := gjson.ParseBytes(bytes)
    name := template.Get("Resources.websitecom865442B6.Properties.Name").String()
    assert.Equal(t, "website.com.", name)
}

One thing you might notice here is the JSON marshalling. That’s because the CDK will build a CloudFormation-friendly JSON artefact from your code using the cdk synth command.

Testing CloudFormation has always been a pain, to the extent that I’ve never really bothered. In true Go style, they’ve made testing easy, so I will probably make an effort from now on.

3. It’s code

In my simple test, I put together a DNS stack for Route53, so I didn’t have to write much code. It’s all still in a very declarative style, but having the flexibility to write logic will be a big plus. If you’ve ever had the misfortune to use Fn::Transform and macros to do any template processing, you’ll understand how easy a code-based configuration will make things.

Still, there’s always the potential to write an infinite loop and boot up a couple of thousand EC2 instances. I almost want to try it to see if they’ve built in any safeguard warnings.

$ cd deploy
Stack EC2Stack
Resources
[+] AWS::EC2::Instance x 32000
[+] Wait, what on earth are you doing?
[+] You maxed out your credit card last month on a single RDS instance
[+] Fix your code

Conclusion

Due to the reasons above, I’m already a fan, even with this straightforward piece of work. Over the next couple of months, I’ll be doing some more complex work like networking, data pipelines and building serverless stacks. It will be interesting to see how CDK plays with SAM. SAM is a pretty integral part of my toolchain for development and deployment, so I need it to work with CDK or adjust how I write serverless code. If you’ve had any experience with Lambda in a CDK environment, then let me know. I’d love to see how you got on.