The Terraform Orb for CircleCI is a convenient way to manage your Terraform infrastructure as code directly within your CI/CD pipelines. It abstracts away much of the boilerplate configuration, allowing you to focus on your Terraform code and deployment strategy.
Let’s see it in action. Imagine you have a main.tf file like this:
provider "aws" {
region = "us-east-1"
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0" # Example AMI, replace with a valid one for your region
instance_type = "t2.micro"
tags = {
Name = "HelloWorld"
}
}
And you want to use the Terraform Orb to plan and apply this configuration. Your CircleCI configuration (.circleci/config.yml) might look like this:
version: 2.1
orbs:
terraform: circleci/terraform@3.1.2
jobs:
terraform-deploy:
docker:
- image: cimg/base:stable
steps:
- checkout
- terraform/init:
path: .
- terraform/plan:
path: .
container-filters:
filter-tags:
only:
- v1.0.0 # Only plan for tags matching this pattern
- terraform/apply:
path: .
container-filters:
filter-tags:
only:
- v1.0.0 # Only apply for tags matching this pattern
workflows:
main:
jobs:
- terraform-deploy
In this example, the terraform/init command sets up your Terraform working directory. The terraform/plan command generates an execution plan, showing you what changes Terraform will make. The terraform/apply command then executes that plan, provisioning your infrastructure. The container-filters are used here to demonstrate how you might restrict when plan and apply actions occur, for instance, only when a Git tag matching v1.0.0 is pushed.
The power of the Orb lies in its ability to handle common Terraform workflows. It provides commands for init, plan, apply, destroy, and more, each with configurable options. For example, you can specify the Terraform version you want to use:
orbs:
terraform: circleci/terraform@3.1.2
jobs:
terraform-deploy:
docker:
- image: cimg/base:stable
steps:
- checkout
- terraform/init:
path: .
terraform_version: 1.5.0 # Explicitly set Terraform version
- terraform/plan:
path: .
- terraform/apply:
path: .
This ensures that your Terraform code is executed with a specific, tested version of Terraform, preventing compatibility issues.
The Orb also integrates seamlessly with CircleCI’s context feature for managing sensitive variables like AWS credentials. You would typically set up an AWS context in CircleCI with your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, and the Orb will automatically pick them up, making your deployments secure.
Internally, the Orb is a collection of CircleCI commands that wrap standard Terraform CLI commands. When you use terraform/init, the Orb executes terraform init in the specified path. Similarly, terraform/plan runs terraform plan, and terraform/apply executes terraform apply. The Orb handles the Docker image execution and argument passing, simplifying your .circleci/config.yml. It’s designed to be highly composable within your existing CircleCI workflows, allowing you to add Terraform steps alongside your application build and test steps.
One of the most impactful, yet often overlooked, aspects of using the Terraform Orb is how it manages state. By default, Terraform stores its state in a local file. However, for any production or team-based workflow, you must use a remote backend like S3, Azure Blob Storage, or Google Cloud Storage. The Orb doesn’t automatically configure a remote backend for you in the init step directly through its parameters, but it expects your Terraform code to define a backend block in your configuration. The terraform/init command will then correctly initialize the backend as defined in your .tf files. This means your .circleci/config.yml might look simple, but your actual main.tf (or other .tf files) needs to contain the remote backend configuration, which is crucial for state locking and preventing concurrent writes.
The next logical step after mastering basic deployments is to explore how to manage multiple Terraform workspaces and implement more sophisticated deployment strategies like blue/green deployments using the Orb.