After two years of collaboration between AWS and HashiCorp and on the 9th of August, 2022, AWS announced the general availability of CDK for Terraform on AWS. As the CDKTF framework finally saw the light of day, the news triggered lots excitement among the community. The CDKTF framework is a new open-source project that enables developers to use their favorite programming languages to define and provision cloud infrastructure resources on AWS. Under the hood, it converts the programming language definitions into Terraform configuration files and uses Terraform to provision the resources.
“Learning is no longer a stage of life; itβs a lifelong journey” - Andy Bird
It’s often said that the best way to learn something new is to do it, and the first milestone in learning is often the hardest. However, with the right guidance, you can overcome the challenges and achieve your goals. My objective in this article is to guide you through the process of installing, configuring, and deploying your first AWS resource using CDKTF on AWS. In addition, I will also show you how to use the Construct Hub documentations to deploy your own AWS resources.
The tutorial should be easy to follow and understand for beginners and intermediate users. The tutorial is devoted to developers with adequate AWS, Terraform and Python knowledge but who are unsure of how and where to begin their CDKTF learning.
The main topics covered in this tutorial are:
This tutorial is also available on my GitHub - CDKTF-Tutorial repo. By the end of this tutorial, you shall be comfortable deploying AWS resources using the CDKTF framework. I will pass you the learning baton and you can take it from there. Enough said, let’s get started.
To complete this tutorial successfully, we should install and configure the following prerequisites properly. To set you up for success, I have to ensure you have the following prerequisites installed and configured properly:
named profile
(name it CDKFT as shown below). We will use the named profile to configure AWS Provider credentials later on.aws configure --profile CDKTF
Note: the profile name does not have to be CDKTF, you can name it however you like. However, I will be using CDKTF in this tutorial.
node -v
python3 --version
Additionally, we will need to make sure we have pip
installed and available.
pip3 --version
Note: if
pip
is unavailable, runsudo apt install python3-pip
to install it as per Python documentation.
pipenv
is 2022.9.20. We will use pip
to install pipenv
.pip3 install pipenv
Note: if you receive a
WARNING
statingpipenv
is not installed onPATH
as shown on the below image, run the below command to add it to the path:
export PATH="the-path-mentioned-in-the-warning:$PATH"
Actual example:
export PATH="/home/CDKTF/.local/bin:$PATH"
We have to confirm that pipenv
is installed and available before we proceed. Run the below command to confirm:
pipenv --version
Note: it’s tempting to install
pipenv
by using the package managersudo apt install pipenv
, but be aware that the system repository version ofpipenv
is outdated and will not work with the CDKTF framework.
CDKTF
using npm
:npm install --global cdktf-cli@latest
If you receive a permission denied error, use sudo
as shown below:
sudo npm install --global cdktf-cli@latest
Let’s confirm the version:
cdktf --version
Make sure you have all required prerequisite versions installed and configured successfully as shown on the below image:
Reaching this point means you have all required prerequisites installed and configured properly. We are ready to move on to the next step. This is a milestone, so take a moment to celebrate it. You deserve it.
In this section, we will learn how to use CDKTF
commands to create our first AWS CDKTF Python project. We will use the cdktf init
command to create a new project in the current directory. The command also creates a cdktf.json
file that contains the project configuration. The cdktf.json
file contains the project name, the programming language, and the Terraform provider. The cdktf.json
file is used by the cdktf
command to determine the project configuration. Follow the below steps to initialize the first CDKTF project using Python template:
cd
into the directory. I will create a directory on my Desktop and name it first_project
:mkdir first_project && cd first_project
A. Name of the project: leave it as first_project
and hit Enter
.
B. Project description: leave it as My first CDKTF project
and hit Enter
.
C. Send crash reports to CDKTF team. I would highly recommend you say yes
to send crash reports to the CDKTF team. This will help improve the product and fix bugs.
cdktf init --template="python" --local
Note 1: we are using the
--local
flag to store our Terraform state file locally. We will reconfigure the backend to S3 Remote backend in the next section.
Note 2: if you receive error
[ModuleNotFoundError: No module named 'virtualenv.seed.via_app_data']
, you would need to removevirtualenv
by runningsudo apt remove python3-virtualenv
. We should still havevirtualenv
as part of the pip packages. Runpip3 show virtualenv
to confirm. If you don’t seevirtualenv
in the list, runpip3 install virtualenv
to install it.
pipenv shell
Note: the purpose of creating a virtual environment is to isolate the project and and all its packages and dependencies from the host or local device. It’s a self contained environment within the host to prevent polluting the system. It’s highly recommended to activate it to keep your host healthy and clean.
pipenv
to install the AWS provider. Run the below command to install the AWS provider:pipenv install cdktf-cdktf-provider-aws
Note: as of the 26th of Sept, 2022, if you decide to install the AWS Provider using
cdktf provider add "aws@~>4.0"
, the installation will fail due to no matching distribution found for version v9.0.36. There are other methods of importing a provider but this tutorial won’t discuss to focus on simplicity.
Congratulations, you have successfully initialized your first CDKTF Python project. This is another milestone to celebrate. Get a cup of coffee βοΈ and let’s move on to the next section.
Terraform stores all managed infrastructure and configuration by default in a file named terraform.tfstate
. If a local backend is configured for the project, the state file is stored in the current working directly. However, when working in a team environment to collaborate with other team members, it is important to configure a remote backend. There are several remote backend options such as, consul, etcd, gcs, http and s3. For a full list of remote backends, refer to Terraform documentation.
For this tutorial, we will configure an S3 Remote Backend which includes an S3 bucket for storing the state file and a DynamoDB table for state locking and consistency checking.
Select one of the following options to configure the S3 Remote Backend:
From Step 2, while we still have the virtual environment activated, let’s open the project directory using our choice of an Integrated Development Environment (IDE). In my case, I’m using Visual Studios Code which I downloaded from the Ubuntu Software Store
. Run code .
on the terminal to open the project directory via VS Code.
Navigate to main.py
file and add the AWS provider construct to the imports section:
from cdktf_cdktf_provider_aws import AwsProvider
Note: the final
main.py
code will be provided at the end of this section.
MyStack
class:AwsProvider(self, "AWS", region="us-east-1", profile="CDKTF")
Note: we are using the
profile
attribute to specify the AWS profile to use. This is the AWS CLI profile we have previously discussed and created in the Required Prerequisites section. If you don’t have a profile created, you can remove theprofile
attribute and the AWS provider will use the default profile. Or, you can use a different authentication method as per the AWS Provider documentation.
S3Backend
class to the other imported classes. The S3Backend class is employing the S3 bucket and DynamoDB table as an S3 remote backend.from cdktf import App, TerraformStack, S3Backend
main.py
file. We will add the following S3 Backend configurations to the MyStack
class:bucket
- the name of the S3 bucket to store the state file. The bucket must exist and be in the same region as the stack. If the bucket doesn’t exist, the stack will fail to deploy.
key
- the name of the state file and its path. The default value is terraform.tfstate
.
encrypt
- whether to encrypt the state file using server-side encryption with AWS KMS. The default value is true
.
region
- the region of the S3 bucket and DynamoDB table. The default value is us-east-1
.
dynamodb_table
- the name of the DynamoDB table to use for state locking and consistency checking. The table must exist and be in the same region as the stack. If the table doesn’t exist, the stack will fail to deploy.
profile
- the AWS CLI profile to use. The default value is default
. But, we have already configured the AWS provider to use the CDKTF
profile.
Here is how the S3 Backend construct will look like:
S3Backend(self,
bucket="cdktf-remote-backend",
key="first_project/terraform.tfstate",
encrypt=True,
region="us-east-1",
dynamodb_table="cdktf-remote-backend-lock",
profile="CDKTF",
)
The final main.py
file should look like this:
from constructs import Construct
from cdktf import App, TerraformStack, S3Backend
from cdktf_cdktf_provider_aws import AwsProvider
class MyStack(TerraformStack):
def __init__(self, scope: Construct, ns: str):
super().__init__(scope, ns)
AwsProvider(self, "AWS", region="us-east-1", profile="CDKTF")
S3Backend(self,
bucket="cdktf-remote-backend",
key="first_project/terraform.tfstate",
encrypt=True,
region="us-east-1",
dynamodb_table="cdktf-remote-backend-lock",
profile="CDKTF",
)
# define resources here
app = App()
MyStack(app, "first_project")
app.synth()
cdktf synth
to generate the Terraform configuration files. The Terraform configuration files will be generated in the cdktf.out
directory. The synth
command will fail if the S3 bucket and DynamoDB table don’t exist.cdktf synth
You have successfully configured the S3 Remote Backend. Let’s move on to the next section.
main.py
file:from cdktf_cdktf_provider_aws import AwsProvider, s3
MyStack
class: my_bucket = s3.S3Bucket(self, "my_bucket",
bucket="Name-of-the-bucket",
)
Replace Name-of-the-bucket
with the name of the bucket you want to create. Note, S3 bucket names must be unique across all existing bucket names in Amazon S3.
Run cdktf deploy
to deploy the stack and create the S3 bucket.
cdktf deploy
Note: if you get
Incomplete lock file information for providers
warning, you can either ignore it or you can runterraform providers lock -platform=linux_amd64
from the project root directory to validate the lock file. For more information, refer to Terraform documentation.
Congratulations, you have successfully configured an S3 remote backend and created an S3 bucket using CDKTF. It’s time to take a break and stretch your legs.
For this option, we will take a different approach. We will create the S3 bucket and DynamoDB table using CDKTF and then configure the S3 remote backend to use the newly created resources. Follow the below steps to create the S3 bucket and DynamoDB table:
Open the project directory using your preferred IDE. If you are using VS Code, cd
into the project folder and run code .
on the terminal to open the project directory using VS Code.
Navigate to the main.py
file and replace the default code with the following. This code creates an S3 bucket and DynamoDB table for the S3 remote backend.
from constructs import Construct
from cdktf import App, TerraformStack, S3Backend
from cdktf_cdktf_provider_aws import AwsProvider, s3, dynamodb
class MyStack(TerraformStack):
def __init__(self, scope: Construct, ns: str):
super().__init__(scope, ns)
AwsProvider(self, "AWS", region="us-east-1", profile="CDKTF")
# define resources here
s3_backend_bucket = s3.S3Bucket(self,
"s3_backend_bucket",
bucket="cdktf-remote-backend-2",
)
dynamodb_lock_table = dynamodb.DynamodbTable(self,
"dynamodb_lock_table",
name="cdktf-remote-backend-lock-2",
billing_mode="PAY_PER_REQUEST",
attribute=[
{
"name": "LockID",
"type": "S"
}
],
hash_key="LockID",
)
app = App()
MyStack(app, "first_project")
app.synth()
Note, if the S3 bucket and DynamoDB table already exist, an error will be thrown. The S3 bucket names must be globally unique across all existing bucket names in Amazon S3 and DynamoDB table names must be unique within an AWS account. If you get an error, you can change the bucket and table names to unique names.
cdktf deploy
to deploy the stack and create the S3 bucket and DynamoDB table.cdktf deploy
Note: if you get
Incomplete lock file information for providers
warning, you can either ignore it or you can runterraform providers lock -platform=linux_amd64
from the project root directory to validate the lock file.
main.py
file and replace the code with the following. This code configures the S3 remote backend to use the newly created S3 bucket and DynamoDB table. Make sure to replace the bucket
and dynamodb_table
values with the names of the S3 bucket and DynamoDB table you created in the previous step.from constructs import Construct
from cdktf import App, TerraformStack, S3Backend
from cdktf_cdktf_provider_aws import AwsProvider, s3, dynamodb
class MyStack(TerraformStack):
def __init__(self, scope: Construct, ns: str):
super().__init__(scope, ns)
AwsProvider(self, "AWS", region="us-east-1", profile="CDKTF")
#S3 Remote Backend
S3Backend(self,
bucket="cdktf-remote-backend-2",
key="first_project/terraform.tfstate",
encrypt=True,
region="us-east-1",
dynamodb_table="cdktf-remote-backend-lock-2",
profile="CDKTF",
)
# Resources
s3_backend_bucket = s3.S3Bucket(self, "s3_backend_bucket",
bucket="cdktf-remote-backend-2",
)
dynamodb_lock_table = dynamodb.DynamodbTable(self, "dynamodb_lock_table",
name="cdktf-remote-backend-lock-2",
billing_mode="PAY_PER_REQUEST",
attribute=[
{
"name": "LockID",
"type": "S"
}
],
hash_key="LockID",
)
app = App()
MyStack(app, "first_project")
app.synth()
cdktf synth
to generate the Terraform configuration files. The Terraform configuration files will be generated in the cdktf.out
directory.cdktf synth
cdktf.out/stacks/first_project
directory and run the following command to start the migration process. The first_project
is the name of the project. If you have named your project differently, navigate to the cdktf.out/stacks/<project_name>
directory and run the command.Note: before running this command, read Important Notes below
cd cdktf.out/stacks/first_project
terraform init --migrate-state
Important Notes:
When you run terraform init --migrate-state
, Terraform prompts you to answer the following question:
Do you want to copy existing state to the new backend?
A. If you enter, yes
to migrate the state file to the S3 backend, CDKTF will manage the S3 remote backend (S3 bucket and DynamoDB table) for you. Therefore, if you delete the stack, the S3 bucket and DynamoDB table will be vurnerable to deletion. Note, we can’t delete a non-empty S3 unless we add force_destroy=True
to the S3 bucket configuration. This option is not recommended if you want to keep the S3 bucket and DynamoDB table, especially if you are using the S3 bucket and DynamoDB table as a remote backend for other Terraform projects. But, if you are just experimenting with CDKTF, this option is fine.
B. If you enter no
, to migrate the state file to the S3 backend, CDKTF will not manage the S3 bucket and DynamoDB table. If you delete the stack, the S3 bucket and DynamoDB table will not be deleted and you will have to manually delete the S3 bucket and DynamoDB table. Moreover, you will also need to remove the S3 bucket and DynamoDB table constructs from the main.py
file.
To read more about initializing remote backend manually, refer to the Terraform documentation.
The below terminal recording demonstrates the steps above. In the recording, I have shown the error message that you may get if you attempt to run cdktf deploy
prior to reconfiguring from local backend to an S3 remote backend.
I have entered yes
to migrate the state file to the S3 remote backend and let the CDKTF manage the S3 bucket and DynamoDB table.
cdktf diff
from the project root directory to compare the current state of the stack with the desired state of the stack. The output should be empty, which means there are no changes to be made and the state file is up to date.cdktf diff
Note: you have to be in the project root directory to run
cdktf diff
.
Great! You have successfully migrated the local state backend to an S3 remote backend. Way to go, you have achieved another milestone! πππ
Prior to digging into the AWS provider, let’s first understand most commonly used terms in the CDKTF documentation:
Submodules is a collection of related resources. For example, the s3.S3Bucket
construct is part of the s3
submodule. The s3.S3Bucket
construct creates an S3 bucket. The s3
submodule contains other constructs such as s3.S3BucketPolicy
, s3.S3BucketAcl
, s3.S3BucketObject
, etc.
Construct is another important term to understand. A construct is a class that represents a Terraform resource, data source, or provider. The s3
submodule contains constructs that represent S3 constructs, classes and struts.
Stack is a collection of constructs. The MyStack
class in the main.py
file is a stack. The MyStack
class contains constructs that represent S3 constructs, classes and struts.
Let’s say we would like to create an S3 but we don’t know which construct to use. Let’s head to the Python Construct hub for the AWS provider and follow the steps below:
Initializers
.s3.S3Bucket
.s3.S3Bucket
construct. Scan the page and look for configurations marked Required
. In this case, S3 bucket does not have any required configuration, not even a name. If you leave the name argument empty, the S3 bucket will be created with a random name. We can specify a name for the S3 bucket and other configurations, but this is not required.We have to distinguish between required and optional configurations. Required configurations must be specified when creating a resource. Optional configurations can be specified when creating a resource.
This is the code snippet for creating an S3 bucket with minimal configurations:
my_3bucket= s3.S3Bucket(self, "s3_bucket")
Note: if you leave the name argument empty, the S3 bucket will be created with a random name.
This time let’s say we would like to create an ECS cluster. Let’s head to the Python Construct hub for the AWS provider and follow the steps below:
Initializers
.ecs.EcsCluster
as shown below.ecs.EcsCluster
construct. The minimum required configurations to create an ECS cluster is just the name
of the cluster. But, we can also specify other configurations such as, capacity_providers
, default_capacity_provider_strategy
, configuration
, etc.my_ecs_cluster = ecs.EcsCluster(self, "my_ecs_cluster",
name = "My_Cluster"
)
There are several CDKTF commands that we need to be familiar with. The below table shows the commands, their descriptions and the corresponding Terraform commands.
Commands | Description | Aliases |
---|---|---|
cdktf init | Create a new cdktf project from a template. | |
cdktf get | Generate CDK Constructs for Terraform providers and modules. | |
cdktf convert | Converts a single file of HCL configuration to CDK for Terraform. Takes the file to be converted on stdin. | |
cdktf deploy | Deploy the given stacks | [aliases: apply] |
cdktf destroy | Destroy the given stacks | |
cdktf diff | Perform a diff (terraform plan) for the given stack | [aliases: plan] |
cdktf list | List stacks in app. | |
cdktf login | Retrieves an API token to connect to Terraform Cloud or Terraform Enterprise. | |
cdktf synth | Synthesizes Terraform code for the given app in a directory. | [aliases: synthesize] |
cdktf watch | [experimental] Watch for file changes and automatically trigger a deploy | |
cdktf output | Prints the output of stacks | [aliases: outputs] |
cdktf debug | Get debug information about the current project and environment | |
cdktf provider | A set of subcommands that facilitates provider management | |
cdktf completion | generate completion script |
To find out more about the cdktf
commands, run cdktf [command] --help
and replace [command]
with the command you want to learn more about.
For example, to learn more about the cdktf deploy
command, run cdktf deploy --help
.
CDKTF is a great tool to provision AWS resources. We have already created an S3 bucket and DynamoDB table in the previous section. In this section, I will show you how to create a Lambda function using CDKTF with function url enabled. The lambda will host a simple static web page, and well configure the function url as an output. The process requires creating an IAM role and attaching a policy to the role. I will also introduce you to multiple concepts in CDKTF.
In this section, I will cover the following topics:
Buckle up, we are going to learn a lot in this section! πππ
Follow the steps below to deploy a Lambda function URL using CDKTF:
Firstly, let’s keep out project organized and create a new directory called lambda
in the root directory of the project. This is where we will store our Lambda function code.
Create a new file called lambda_function.py
in the lambda
directory.
Copy the lambda_function.py
code from my GitHub repository and paste it into the lambda_function.py
file.
I will go over the main.py
code and the final main.py
file will provided at the end of the section.
main.py
file, import the TerraformOutput
, TerraformAsset
and AssetType
classes from the cdktf
module. Assets construct is introduced in CDK for Terraform v0.4+ and is used to package a local directory and python file into a zip file. The TerraformOutput
construct is used to create an output for the Lambda function url. The AssetType
is used to specify the type of asset.The final import statements should look like this:
from constructs import Construct
from cdktf import App, TerraformStack, S3Backend, TerraformOutput, TerraformAsset, AssetType
from cdktf_cdktf_provider_aws import AwsProvider, s3, dynamodb, iam, lambdafunction
import os
import os.path as Path
Note, we have imported
os
andos.path as Path
modules. We will use these modules to get the current working directory and to join the path to the lambda directory.
TerraformAsset
construct requires a path
argument. The path
argument is the path to the directory or file that you want to package. In this case, we will use the os
module to get the current working directory and then join the path to the lambda
directory. The AssetType.ARCHIVE
is to specify that the asset is an archive. The final path
argument should look like this:asset = TerraformAsset(self, "lambda_file",
path = Path.join(os.getcwd(), "lambda"),
type = AssetType.ARCHIVE,
)
AWSLambdaBasicExecutionRole
AWS managed policy to the IAM role. This policy allows the Lambda function to write logs to CloudWatch. Refer to AWS documentation for more information about the AWSLambdaBasicExecutionRole policy.The assume_role_policy
argument is the policy that grants permission to assume the IAM role, which requires a JSON string. The JSON string is the policy document that grants permission to assume the IAM role. The final snippet of code should look like this:
lambda_role = iam.IamRole(self, "lambda_role",
name="my-lambda-url-role",
managed_policy_arns=[
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
],
assume_role_policy="""{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}""",
)
handler
configuration is the name of the python file that contains the lambda function. The runtime
provides a language-specific environment that runs in an execution environment. The source_code_hash
argument is the hash of the file that contains the lambda function. The source_code_hash
argument is required to trigger a new deployment when the lambda function code changes. The filename
argument is the path to the file that contains the lambda function.The final snippet of code should look like this:
my_lambda = lambdafunction.LambdaFunction(self, "my_lambda",
function_name="my-lambda-url",
handler="lambda_function.lambda_handler",
role=lambda_role.arn,
runtime="python3.9",
source_code_hash = asset.asset_hash,
filename=asset.path,
)
authorization_type
for the function url. The authorization_type
argument is the type of authorization that is used to invoke the function url. The authorization_type
argument can be set to NONE
or AWS_IAM
. The final snippet of code should look like this: my_lambda_url = lambdafunction.LambdaFunctionUrl(self, "my_lambda_url",
function_name=my_lambda.function_name,
authorization_type="NONE",
)
value
argument is the value of the output. The value
argument can be a string, number, boolean, or a list. The final snippet of code should look like this: TerraformOutput(self, "lambda_url",
value=my_lambda_url.invoke_url,
)
The final main.py
code should look like this:
from constructs import Construct
from cdktf import App, TerraformStack, S3Backend, TerraformOutput, TerraformAsset, AssetType
from cdktf_cdktf_provider_aws import AwsProvider, s3, dynamodb, iam, lambdafunction
import os
import os.path as Path
class MyStack(TerraformStack):
def __init__(self, scope: Construct, ns: str):
super().__init__(scope, ns)
AwsProvider(self, "AWS", region="us-east-1", profile="CDKTF")
#S3 Remote Backend
S3Backend(self,
bucket="cdktf-remote-backend-2",
key="first_project/terraform.tfstate",
encrypt=True,
region="us-east-1",
dynamodb_table="cdktf-remote-backend-lock-2",
profile="CDKTF",
)
# Resources
s3_backend_bucket = s3.S3Bucket(self, "s3_backend_bucket",
bucket="cdktf-remote-backend-2",
)
dynamodb_lock_table = dynamodb.DynamodbTable(self, "dynamodb_lock_table",
name="cdktf-remote-backend-lock-2",
billing_mode="PAY_PER_REQUEST",
attribute=[
{
"name": "LockID",
"type": "S"
}
],
hash_key="LockID",
)
# Asset for Lambda Function
asset = TerraformAsset(self, "lambda_file",
path = Path.join(os.getcwd(), "lambda"),
type = AssetType.ARCHIVE,
)
# IAM Role for Lambda Function
lambda_role = iam.IamRole(self, "lambda_role",
name="my-lambda-url-role",
managed_policy_arns=[
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
],
assume_role_policy="""{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}""",
)
# Lambda Function
my_lambda = lambdafunction.LambdaFunction(self, "my_lambda",
function_name="my-lambda-url",
handler="lambda_function.lambda_handler",
role=lambda_role.arn,
runtime="python3.9",
source_code_hash = asset.asset_hash,
filename=asset.path,
)
# Lambda Function Url
my_lambda_url = lambdafunction.LambdaFunctionUrl(self, "my_lambda_url",
function_name=my_lambda.function_name,
authorization_type="NONE",
)
# Outputs for Lambda Function Url
TerraformOutput(self, "lambda_url",
value=my_lambda_url.function_url,
)
app = App()
MyStack(app, "first_project")
app.synth()
cdktf deploy
to deploy the stack.cdktf deploy
Note: you can also run
cdktf deploy --auto-approve
to deploy the stack without confirmation. However, I would suggest to refrain from using this option in production unless you are absolutely sure that you want to deploy the stack without confirmation.
Finally, grab the lambda_url
output and paste it in your browser. If you see the dancing bananas, then you have successfully deployed your first lambda function using CDKTF.
Congratulations! You have successfully deployed a lambda function with a function url using CDKTF. I’m sure you feel like you are on top of the world right now. Well done!
To delete the stack, we need to follow the below steps:
Note, we chose to allow CDKTF to manage the remote backend. This means that CDKTF will delete the remote backend (the S3 bucket and DynamoDB Table) when we delete the stack. There are many methods to delete the stack, but I find the below method to be the easiest. Let’s go through the steps:
A. Add force_destroy=True
to the s3_backend_bucket
configurations. The S3 bucket cannot be deleted if it is not empty. This is the reason why we need to add force_destroy=True
.
s3_backend_bucket = s3.S3Bucket(self, "s3_backend_bucket",
bucket="cdktf-remote-backend-2",
force_destroy=True
)
B. Run cdktf deploy
to update the S3 bucket configurations:
cdktf deploy
C. Run cdktf destroy
to delete the entire stack:
cdktf destroy
Note: after running
cdktf destroy
, you will get an error message sayingfailed to retrieve lock info
. This is expected due to the fact the dynamodb table is deleted. You can ignore this error message.
In this tutorial, we have learned how to properly install and configure CDKTF, how to migrate from a local backend to an S3 remote backend. We have also learned how to deploy a lambda function with a function url using CDKTF. We have also briefly learned how to read and utilize the CDKTF documentations from the Construct Hub.
The most important thing to remember is that CDKTF is still in its early stages. There are many features that are not yet available. However, I am confident that CDKTF will be a great tool for managing Terraform stacks in the future.
Congratulations on completing this tutorial and overcoming several challenges. You have achieved many learning milestones. I hope this tutorial added value to your learning journey. Thank you for reading!
Omar A Omar
Site Reliability Engineer