What is AWS Cloud Development Kit?
If you've been in the world of AWS long enough, you've probably heard of CloudFormation (duh!) and AWS CDK (Cloud Development Kit). If you haven't - you should! Trust me, it's awesome!!! AWS CDK gives you the best of Imperative and Declarative when it comes to IAC (Infrastructure as Code). It allows you to:
- Keep the entire code of your app on Git as a "single source of truth", making the best use of SCM tools such as version control and CI.
- Use your favourite programming language (read: python!... and yes, I know AWS recommends TypeScript and the documentation is much better, but I'd still go with Python). In the end of the day, CDK is just a way for you to create and deploy CloudFormation Stacks.
How do I get started with CDK?
I'd highly recommend you to get familiar with CDK, and I'll leave 3 links you need to bookmark:- Official AWS documentation: https://docs.aws.amazon.com/cdk/latest/guide/work-with-cdk-python.html
- An awesome CDK Workshop that you MUST do: https://cdkworkshop.com/ . You'll see that most of blogs and youtube videos called "Intro to CDK", are simply a rip off of this workshop.
- Official AWS CDK API Reference: https://docs.aws.amazon.com/cdk/api/latest/docs/aws-construct-library.html
Piece of advice: use all these docs to create your own "how to", because... you'll see, the documentation still needs some work.
CDK Building Blocks
Constructs are the basic building block of CDK apps. They represent abstract “cloud components” which can be composed together into higher level abstractions via scopes. Scopes can include constructs, which in turn can include other constructs, etc. Constructors must always have:
- Scope, which is normally 'self'
- Id, as a local identity
- Kwargs, a set of optional initialisation arguments, specific to each construct. For example, for Lambda, it will be runtime, code and handler, more details here.
- Scope, which is normally 'self'
- Id, as a local identity
- Kwargs, a set of optional initialisation arguments, specific to each construct. For example, for Lambda, it will be runtime, code and handler, more details here.
The AWS CDK is shipped with an extensive library of constructs called the AWS Construct Library. The construct library is divided into modules, one for each AWS service. For example, if you want to define an AWS Lambda function, we will need to use the AWS Lambda construct library.
How complex is CDK?
It's actually pretty easy, if you're using the officially supported classes. But... what if you need "more stuff"?
Let me clarify this:
- AWS CDK is awesome, but it can be challenging to use, since the documentation is not the best... especially if you're not using TypeScript.
- In the official API reference, you'll see that there's an official way to create any resource. For example - for a DynamoDB Table, you'd go with an official class, MyDynamoDB = ddb.Table(), documented here.
- Problem? As you can see in the link above, not all parameters are supported (panic mode: ON).
- Solution: EVERYTHING you can do in CloudFormation, you can do using CDK (panic mode: OFF). You just need to not be scared to get electrocuted... a little. Every Official Class, has an CFN equivalent, that lets you use the EXACT parameters you're using to create CloudFormation Stack, but... in a different way.
Syntax for S3 CfnBucket or DynamoDB CfnTable
The whole reason I'm writing this, is that the official documentation, https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html is simply wrong.
We basically need to convert our good old CloudFormation Template written in JSON or YAML, into a Python code. Problem? Syntax isn't documented anywhere, and there are no examples on the web. I've spent the last few days trying to google "DynamoDB CfnTable KeySchema"... 0 hits! Even Google doesn't know about this.
Let's cut to the chase, let's say we've got the following CF Template in YAML, and we need to create a CDK Python code:
Resources:
MyDynamoDb:Type: AWS::DynamoDB::TableProperties:AttributeDefinitions:-AttributeName: "project"AttributeType: "S"-AttributeName: "owner"AttributeType: "S"-AttributeName: "votes"AttributeType: "N"-AttributeName: "members"AttributeType: "N"KeySchema:-AttributeName: "project"KeyType: "HASH"-AttributeName: "owner"KeyType: "RANGE"ProvisionedThroughput:ReadCapacityUnits: "5"WriteCapacityUnits: "5"
If you refer to the official class, https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_dynamodb/Table.html you'll see that there is no Attribute Definitions... you're basically just given two parameters, "partition_key" and "sort_key", and that's it. So... what do you do, how do you define other Attributes?
IMPORTANT: This is just an example that I'm using to explain the syntax, please don't get into the philosophy of whether we need to be defining attributes while creating a DynamoDB table.
Here's the "trick". You basically need to find the python class that matches each of your properties. In this case, we're looking for a Key Schema and Attribute Definitions, and the corresponding classes are KeySchemaProperty and AttributeDefinitionProperty. Once you've figured this out, you need to "guess" how to form the entire syntax around it with no documentation to guide you. It would look something like this (make sure to note which are VARIABLES, and which are ARRAYS):
from aws_cdk import (
core,
aws_s3 as s3,
aws_dynamodb as ddb,
)
…
MyDynamoDB = ddb.CfnTable(
self, "MyDynamoDB",
table_name="dynamodb-prod-unicorn",
key_schema=[
ddb.CfnTable.KeySchemaProperty(attribute_name="project",key_type="HASH"),
ddb.CfnTable.KeySchemaProperty(attribute_name="owner",key_type="RANGE")
],
attribute_definitions=[
ddb.CfnTable.AttributeDefinitionProperty(attribute_name="project",attribute_type="S"),
ddb.CfnTable.AttributeDefinitionProperty(attribute_name="owner",attribute_type="S"),
ddb.CfnTable.AttributeDefinitionProperty(attribute_name="votes",attribute_type="N"),
ddb.CfnTable.AttributeDefinitionProperty(attribute_name="project",attribute_type="S"),
ddb.CfnTable.AttributeDefinitionProperty(attribute_name="owner",attribute_type="S"),
ddb.CfnTable.AttributeDefinitionProperty(attribute_name="votes",attribute_type="N"),
ddb.CfnTable.AttributeDefinitionProperty(attribute_name="members",attribute_type="S"),
],
provisioned_throughput=ddb.CfnTable.ProvisionedThroughputProperty(
read_capacity_units=5,
write_capacity_units=5
)
)
This looks very complex, but it's actually quite simple. Also have in mind that this is ONLY in case you need to use a Property not supported by an official CDK construct, in this case aws-cdk_aws-dynamodb.Table .
Let me know in comments if this helped.