Now that you've installed cdktf, you will use it to deploy an AWS EC2 instance using TypeScript.
»Prerequisites
To follow this tutorial, you need the following installed locally:
- Terraform v0.12+
- cdktf
- Node.js v12.16+
- an AWS account and AWS Access Credentials
Terraform and the cdktf
tool will use credentials set in your environment or through other means as described in the Terraform documentation.
Add your AWS credentials as two environment variables, AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
, replacing AAAAAA
with each respective values.
$ export AWS_ACCESS_KEY_ID=AAAAAA
$ export AWS_SECRET_ACCESS_KEY=AAAAA
»Initialize a project
Start by creating a directory for the project. Name it typescript-aws
.
$ mkdir typescript-aws && cd $_
Inside the directory, run cdktf init
with the TypeScript template. Use --local
to store Terraform's state file on your machine instead of remotely in Terraform Cloud.
$ cdktf init --template="typescript" --local
This will initialize a brand new CDK for Terraform project in TypeScript using an interactive command. Accept the defaults when prompted.
»Write TypeScript code
Open the main.ts
file to view your application code. The template creates a scaffold with no functionality.
import { Construct } from 'constructs'
import { App, TerraformStack } from 'cdktf'
class MyStack extends TerraformStack {
constructor(scope: Construct, name: string) {
super(scope, name)
// define resources here
}
}
const app = new App()
new MyStack(app, 'hello-terraform')
app.synth()
The scaffold pre-configures the configuration to use AWS. Run the get
command to install the relevant dependencies.
$ cdktf get
Now, write a configuration in TypeScript that uses the AWS provider to create a compute instance in the us-west-1
region. Although it requires about 30 lines of code, most of the lines map to equivalents in HCL for traditional Terraform.
Copy the following code and paste it into main.ts
, replacing the existing code.
import { Construct } from 'constructs'
import { App, TerraformStack, TerraformOutput } from 'cdktf'
import { AwsProvider, Instance } from './.gen/providers/aws'
class MyStack extends TerraformStack {
constructor(scope: Construct, id: string) {
super(scope, id)
new AwsProvider(this, 'aws', {
region: 'us-west-1',
})
const instance = new Instance(this, 'compute', {
ami: 'ami-01456a894f71116f2',
instanceType: 't2.micro',
tags: {
Name: 'TypeScript-Demo',
fruit: 'blueberry',
Address: '123 Main St',
},
})
new TerraformOutput(this, 'public_ip', {
value: instance.publicIp,
})
}
}
const app = new App()
new MyStack(app, 'typescript-aws')
app.synth()
»Examine the code
Most of the code is similar to concepts you've seen in a traditional Terraform configuration written in HCL, but there are a few notable differences. Let's look at each.
Unlike HCL, your TypeScript code must explicitly import any classes it uses. A major addition is TerraformOutput
which you will use to print attributes of the resources that you create. The core Terraform classes are in the cdktf
library and respond to IntelliSense if you are using Visual Studio Code. Start typing "Terraform" inside the curly braces and you'll see a list of available objects.
import { App, TerraformStack, TerraformOutput } from 'cdktf'
AWS resources must also be explicitly imported. In this case we need the top level AwsProvider
and the Instance
for our compute resource.
import { AwsProvider, Instance } from './.gen/providers/aws'
Speaking of which, the AwsProvider
can be configured by passing keys and values that map to Terraform arguments as listed in the provider API. In the snippet below we use the region
key to set the region to us-west-1
.
The Terraform API documentation uses snake case (lowercase with underscores) but TypeScript uses camel case (mixed lower and uppercase with no underscores). So a key such as shared_credentials_file
is sharedCredentialsFile
in TypeScript.
TIP: One way to discover all the classes and properties for a provider is to examine the .gen/providers/aws
directory. You'll find files such as aws-provider.ts
which list the exact class names and properties for each resource.
new AwsProvider(this, 'aws', {
region: 'us-west-1',
})
Next we define a compute instance with the Instance
class. For this you'll also use camel case for properties that correspond to the Terraform API.
A significant difference from HCL is the need to store the new instance in a variable, shown as const instance
here. We will use the instance attributes in an output later, so we must create a variable. In HCL, any resource can be accessed from any point in the configuration file, but in TypeScript you must use a variable if you want to access the resource elsewhere.
const instance = new Instance(this, 'compute', {
ami: 'ami-01456a894f71116f2',
instanceType: 't2.micro',
tags: {
Name: 'TypeScript-Demo',
fruit: 'blueberry',
Address: '123 Main St',
},
})
The instance
variable is used in a TerraformOutput
. We want to know the publicIp
of the instance when it is created, and we might want to read this output value from another Terraform workspace.
When writing this code, you can use IntelliSense to view all the properties of the instance
variable. In this case, publicIp
the only one that is used.
new TerraformOutput(this, 'public_ip', {
value: instance.publicIp,
})
»Provision infrastructure
Now that you have initialized the project with the AWS provider and have written code to provision an instance, it's time to deploy
it.
$ cdktf deploy
Deploying Stack: typescript-aws
Resources
✔ AWS_INSTANCE compute
Summary: 1 created, 0 updated, 0 destroyed.
Output: typescriptaws_publicip_EEB4927B = 54.219.195.36
You will be prompted to confirm. After the instance is created, you'll see the output which displays the publicIp
we specified earlier (listed here with the full name of the project and the name of the output, typescriptaws_publicip_EEB4927B
).
»Destroy
In a full cycle development workflow, you would modify the code and run deploy
again to update your infrastructure as specified in the code.
For this tutorial, we're done with the compute instance, so you can run the destroy
command to de-provision it.
$ cdktf destroy
Destroying Stack: typescript-aws
Resources
✔ AWS_INSTANCE compute aws_instance.typescriptaws_compute_D9683B2F
Summary: 1 destroyed.
You'll be prompted to confirm and a message will be displayed that shows it was destroyed.
»Next Steps
Even in its current state of development, cdktf
is capable of much more. The synth
command will generate JSON which can be used by the standard terraform
executable to provision infrastructure using terraform apply
and related commands.
Any other Terraform provider can be used by listing it under terraformProviders
in cdktf.json
and running cdktf get
.
TypeScript language features can be used to build configuration around class inheritance or to fetch data from other sources which can be used together with your Terraform configuration.
Or, you can use cdktf
with Terraform Cloud for persistent storage of your state file and for team collaboration.
For other examples, see the documentation in the terraform-cdk
repository.