Using terraform.workspace with Terraform Cloud
Have you ever tried Terraform Cloud before? Have you tried all the integration, collaboration features nicely setup on Terraform Cloud? Have you ever been so eager running all your configuration in Terraform Cloud and then suddenly realized it is not reading variable from your desired terraform.workspace
?
Let’s see what we can do to fix this.
Using terraform.workspace to setup multi environment
If you already know how to use terraform.workspace
to switch between multi environment on the same configuration, then you can skip this section.
When working with Terraform, we usually want to use the same configuration but with different variables for each environment (dev, test, prod). There are many technique to archive that, one of them is leverage on terraform.workspace
To use terraform.workspace
, first, we create the workspace corresponding to our environments. For example here I can create 3 workspace: dev, test and prod using the command: terraform workspace new dev
.
I can switch between workspace using the command: terraform workspace select dev/test/prod
Also, the Terraform state of each workspace is separated and managed by the workspace select
command.
Now, we can define resource as below example, that will switch to use the variables corresponding to current environment workspace
# Variables files
---- variables.tf ------
variable name {
description = "Environment"
type = map(string)
default = {
dev = "dev"
stg = "stg"
prod = "prod"
}
}# AWS ECS cluster configuration file
---- ecs.tf ------
module "ecs" {
source = "../modules/ecs/"
name = var.name[terraform.workspace]
}
As you can see, the variable name
is a map of key and value type, with the key is the env we defined with terraform.workspace
. Or in other word, we are mapping the variables with terraform.workspace
This is a very smart way to use different variables for each environment and not repeating a lot of code.
Use terraform.workspace with Terraform Cloud
Terraform Cloud is a cloud version of Terraform Enterprise, which promote collaborative IAC (Infrastructure-As-Code), make it easier for multi teams to work on Terraform.
The workspace concept on TF Cloud is not the same as local
terraform.workspace
.Locally, configuration codes are organized into directories, each directory has configuration, variables and state file. TF Cloud doesn’t have a directory structure, instead, those configuration, variables and state file are stored in a workspace, or you can say a cloud directory.
In local environment,
terraform.workspace
is just a way to switch state file.
In TF Cloud, we would like to have one workspace per environment per configuration. We shall organize the ECS example above into 3 workspace: ecs-dev
, ecs-stg
, ecs-prod
How do we match local workspace with TF Cloud workspace?
How can I configure that, locally, when I am inside ecs
configuration, terrafom.workspace=dev
, I would work with ecs-dev
on the cloud? This is archive-able using workspace prefix in backend config.
terraform {
backend "remote" {
hostname = "app.terraform.io"
organization = "my-org"
workspaces {
prefix = "ecs-"
}
}
}
With this, Terraform will always know which remote workspace you are working with by combining the prefix with the local terraform.workspace
Terraform Cloud run Plan/Apply on its own machine, which is great to ensure consistency and a single source of truth for all the Plan/Apply. However, because of this, we can’t set terraform.workspace
before each run, thus it is always set to default value default
. This is not what we want.
We have to modify our code a bit, to make it compatible with both running locally and on TF Cloud.
variable "TFC_WORKSPACE_NAME" {
type = string
default = ""
}
locals {
# If your backend is not Terraform Cloud, the value is ${terraform.workspace}
# otherwise the value retrieved is that of the TFC_WORKSPACE_NAME with trimprefix
workspace = var.TFC_WORKSPACE_NAME != "" ? trimprefix("${var.TFC_WORKSPACE_NAME}", "ecs-") : "${terraform.workspace}"
}
TFC_WORKSPACE_NAME
is a special variable that auto set by TF Cloud, it is the current TF Cloud workspace.- If I run locally, use
terraform.workspace
- Else in the cloud, use
TFC_WORKSPACE_NAME
without the prefixecs
In configuration code, switch to use local.workspace
instead:
module "ecs" {
source = "../modules/ecs/"
name = var.name[local.workspace]
}
This is done.
Now you can have the best of both world, use Terraform Cloud in remote execution mode, and still able to switch between terraform.workspace
on your local environment without any issue.