The AWS CDK for software-defined deployments
Dreaming of Clouds
The financial benefits of the cloud seem quite obvious on the surface. One powerful point that deserves not only emphasis but in-depth analysis is software-defined deployments. With the advent of cloud platforms, API-driven services and infrastructure are now the norm, not the exception, making it possible not only to automate the packaging and deployment of the software, but to provision the infrastructure that hosts the applications deployed. Although tools like Amazon Web Services (AWS) CloudFormation and HashiCorp's Terraform are heavyweights, I really think the AWS Cloud Development Kit (CDK) deserves a serious look as a strong contender in this arena.
Bring on the Clouds!
With every major cloud provider come additional benefits – in addition to the immediately obvious financial benefits – like the as-a-service offerings. For example, the Kubernetes-as-a-service offerings, such as Google Kubernetes Engine [1], Amazon Elastic Container Service for Kubernetes (EKS) [2], and Microsoft Azure Kubernetes Service (AKS) [3], make it possible to provision immensely complex orchestration platforms and tools with point-and-click web interfaces or a simple command-line invocation. In this dimension, many additional benefits that might not be immediately obvious are worth mentioning:
- Cost optimization and savings through reduction of labor. Working from the Kubernetes-as-a-service example, the time saved in not having to learn how to architect and deploy a multimaster, resilient, high-availability cluster is immense and is but one of many such services available in an easy-to-consume offering.
- Exposure and access to new technologies. It's probably fair to say that many developers would never experiment with a function-as-a-service (serverless) platform or a non-relational database if it were not offered in a form as simple to use as Amazon DynamoDB.
- Software-defined deployments. As the point that forms the crux of this article, the importance of software-defined deployments cannot be underscored strongly enough in the cloud revolution.
Pareidolia
Seeing shapes in clouds isn't just a youthful pastime anymore. These days, API-driven cloud platforms give you the power to define the form and shape of your deployments in the cloud. All major cloud providers have command-line-based toolkits to script deployments in scripting languages like Bash or PowerShell. Although these languages and the products built with them are extremely powerful, they do leave room for improvement.
For example, when modifying aspects of previously defined deployments and infrastructure, you are typically left to different APIs and, hence, the command line (CLI) to make changes to your deployments. For sufficiently complex deployments, it becomes an increasingly complex task to maintain separate scripts (or, alternatively, a single monstrosity that accepts an ever-increasing number of flags and arguments) to handle any type of modification to a deployment, create new deployments, and destroy deployments that are no longer needed.
Further improvements in this space yielded a newer generation of tools that make use of declarative state machines to create (and further modify) deployments. In 2011, AWS introduced CloudFormation [4]. In its initial incarnation, CloudFormation allowed you to define a deployment through the use of JSON-based templates, which were then POSTed to an API endpoint.
Then, as now, services internal to AWS parse the template, both to evaluate logic embedded [5] in the templates and to figure out the order in which resources should be provisioned according to dependencies; provision services to match the template's specifications; handle success and failure scenarios; and maintain a state of the defined resources. In stark contrast to the aforementioned shell scripts of increasingly complex logic to handle create/modify/delete scenarios, the JSON (and subsequently YAML) templates of CloudFormation-defined deployments are static and declarative, allowing you to define your initial set of templates and provision your services.
When it is time to update (or destroy) your services, you update your template to your new specifications and once again POST it to the API. The services behind the API figure out the delta between your specified template and the state currently known to the service of your existing resource set; from there, the service creates, modifies, and deletes services and resources as necessary to bring your deployment in line with the specifications of your template.
Although CloudFormation gave AWS users exclusively a powerful tool, 2014 gave a wider infrastructure API consumer audience a powerful new tool in their tool belt with the arrival of Terraform [6]. Terraform brought a similar set of concepts: a declarative template definition language interpreted by a run time capable of understanding the differences between a current and desired state that leverages an abstracted set of provider APIs to make the current state match the desired state. The benefits of Terraform are numerous, and although the extent of some of those benefits relative to other tools might be a matter of opinion or circumstance, I find these benefits almost universally agreed upon:
- Open source. It is available under the Mozilla Public License (MPL) v2.0 [7].
- Visibility into the deployment state. It exposes its state to inspection (CloudFormation does not expose its state in any way, although it recently began to offer drift detection [8]). The executable also provides a robust set of commands and tools to inspect and (if necessary) manipulate the state of a deployment directly.
- Flexible. Terraform offers a great deal of flexibility and power in its implementation (i.e., its null resources [9] and external data sources [10]), although, in my opinion, this comes with a somewhat steeper learning curve than something like CloudFormation. CloudFormation's somewhat analogous custom resources are relegated to running on the AWS platform.
- Portable. The run time is portable and basically can be run anywhere, assuming the executable has the ability to communicate with whatever APIs it's leveraging.
- Interoperable. It can be made to interoperate with any service that exposes an API that implements create, read, update, and delete (CRUD) operations (through custom plugin or "provider" development) [11].
Tool Fatigue
Is another tool really necessary in this space? Although I mostly use CloudFormation and Terraform in this article as points of comparison, the list of other tools that can provision infrastructure is long: Troposphere [12], Sceptre [13], Bash scripts, custom apps leveraging SDKs, Ansible [14], Selenium scripts automating the AWS console (OK, I've never done that, and it's probably a terrible idea – but it would work!), and the list goes on. Honestly, I blew off the AWS CDK [15] the first time I heard about it, because it seemed like yet another tool vying for my attention in an already crowded field that already has some very strong contenders. After some time, though, my curiosity won out over my skepticism, and I decided to take the CDK for a spin.
Buy this article as PDF
(incl. VAT)