Terraform
Use Cases
Stacks provide a way to define, organize, and reuse components and then deploy the infrastructure those components describe consistently across different deployments.
Stacks are ideal for the following situations:
- Managing infrastructure with a common lifecycle, such as a microservices architecture where HCP Terraform needs to deploy multiple services together.
- Repeating infrastructure across different environments, regions, or accounts that require consistent and synchronized deployments.
- Tightly orchestrating infrastructure that changes across different environments. Stacks help you manage your dependencies and ensure Terraform creates resources in the correct order.
Stacks can simplify the complexity of wrangling the infrastructure in these scenarios, ensuring that your configurations remains organized, maintainable, and scalable.
Manage deployment dependencies
Stacks let you manage dependencies within complex infrastructure deployments automatically. If your infrastructure has interdependencies between components, HCP Terraform recognizes if a Stack component requires attributes that are not yet available and defers planning those changes until it can apply them.
Hands-on: Go through our tutorial on Managing Kubernetes workloads using Stacks for examples of Stacks that manage deployment dependencies.
For example, when managing Kubernetes workloads that use custom resources, you cannot provision a custom resource definition (CRD) API and the resources that use those APIs in a single step. In these scenarios, HCP Terraform first needs to deploy your CRD and then deploy the resources that require your CRD in a second plan and apply. When you deploy this setup with HCP Terraform workspaces, you manage multiple workspaces to accomplish this workflow, which can get complicated.
When you use a Stack, HCP Terraform recognizes the dependency between components, automatically deferring the component's plan and apply steps until it can complete them successfully. Learn more about how Stacks plan deferred changes.
Deploy to multiple environments
Managing infrastructure across multiple environments can be challenging, especially when you want to ensure that each environment remains consistent. For example, if you manage infrastructure for multiple environments, such as development, staging, and production. Each environment needs to be isolated, but they all mirror each other’s configuration.
Stacks let you define deployments for each environment within a single configuration, making it easier to maintain uniformity and make updates across all your environments.
deployments.tfdeploy.hcl
deployment "production" {
inputs = {
aws_region = "us-west-1"
instance_count = 2
role_arn = "<YOUR_ROLE_ARN>"
identity_token = identity_token.aws.jwt
}
}
deployment "development" {
inputs = {
aws_region = "us-west-1"
instance_count = 2
role_arn = "<YOUR_ROLE_ARN>"
identity_token = identity_token.aws.jwt
}
}
Stacks also simplify adding and removing environments. You can add a deployment
block to create a new environment using the same component configuration and infrastructure components.
deployments.tfdeploy.hcl
# deployments.tfdeploy.hcl
deployment "production" {
inputs = {
aws_region = "us-west-1"
instance_count = 2
role_arn = "<YOUR_ROLE_ARN>"
identity_token = identity_token.aws.jwt
}
}
deployment "development" {
inputs = {
aws_region = "us-west-1"
instance_count = 2
role_arn = "<YOUR_ROLE_ARN>"
identity_token = identity_token.aws.jwt
}
}
deployment "staging" {
inputs = {
aws_region = "us-west-1"
instance_count = 2
role_arn = "<YOUR_ROLE_ARN>"
identity_token = identity_token.aws.jwt
}
}
By default, HCP Terraform notices that you changed your configuration and will create a new plan for your new deployment.
Deploy across regions
For global applications, deploying infrastructure across multiple cloud regions is often necessary to ensure low latency and high availability. Stacks enable you to manage cross-region deployments with a unified configuration, ensuring that HCP Terraform sets up each region consistently while allowing for region-specific customization.
For example, if you want to deploy the same environment to two different regions, you could set up your deployments to be region-specific.
deployments.tfdeploy.hcl
identity_token "aws_west" {
audience = ["aws.workload.identity.west"]
}
identity_token "aws_east" {
audience = ["aws.workload.identity.east"]
}
deployment "us_dev_east" {
inputs = {
aws_region = "us-east-1"
instance_count = 2
role_arn = "<YOUR_ROLE_ARN>"
identity_token = identity_token.aws_east.jwt
}
}
deployment "us_dev_west" {
inputs = {
aws_region = "us-west-1"
instance_count = 2
role_arn = "<YOUR_ROLE_ARN>"
identity_token = identity_token.aws_west.jwt
}
}
Stacks support using the for_each
meta-argument in both provider
and component
blocks. You can use the for_each
meta-argument to streamline infrastructure deployment in repeating regions. In the following example, the regions
variable expects a set of regions to deploy in.
variables.tfcomponent.hcl
# variables.tfstack.hcl
# The regions variable is where we specify each region we want to deploy this
# Stack's infrastructure within.
variable "regions" {
type = set(string)
}
variable "identity_token" {
type = string
ephemeral = true
}
variable "role_arn" {
type = string
}
Then, you can set up your provider configuration to iterate through the var.regions
variable to configure a version of that provider for each region.
providers.tfcomponent.hcl
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.7.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.5.1"
}
}
provider "aws" "configurations" {
for_each = var.regions
config {
region = each.value
assume_role_with_web_identity {
role_arn = var.role_arn
web_identity_token = var.identity_token
}
}
}
Each of your Stack’s deployments uses a separate AWS provider configuration for each region you defined in the regions
variable. This means that in your configuration, you refer to the AWS provider for the us-east-1
region as provider.aws.configurations["us-east-1"]
.
You can keep Stack components dynamic by using the for_each
meta-argument to deploy a component
’s Terraform module in each region.
components.tfcomponent.hcl
component "s3" {
for_each = var.regions
source = "./s3"
inputs = {
region = each.value
}
providers = {
aws = provider.aws.configurations[each.value]
random = provider.random.this
}
}
The components in this example use the for_each
meta-argument to deploy their Terraform module in the region for the current deployment. Notice how the component configures the AWS provider to use the correct provider for the given region with provider.aws.configurations[each.value]
.
Deploy across accounts
Stacks can also be helpful when managing infrastructure across different cloud provider accounts, ensuring that each account's infrastructure is consistent but isolated.
deployments.tfdeploy.hcl
identity_token "aws_prod" {
audience = ["aws.prod.workload.identity"]
}
identity_token "aws_dev" {
audience = ["aws.dev.workload.identity"]
}
deployment "development" {
inputs = {
aws_region = "us-east-1"
role_arn = "<development AWS account IAM role ARN>"
identity_token = identity_token.aws_dev.jwt
}
}
deployment "production" {
inputs = {
regions = ["us-east-1", "us-west-1"]
role_arn = "<production AWS account IAM role ARN>"
identity_token = identity_token.aws_prod.jwt
}
}
Stacks let you define and deploy shared infrastructure components across different accounts, maintaining consistency while adhering to security and organizational boundaries.