Hello!
In this programming, I will talk about variables in terraform and terraform data.
Variables
I will use the code from previous posts. I create a new file variables.tf
and add the instance_type variable to it.
variable "instance_type" {
default = "t2.micro"
description = "Instance type for test instance"
type = string
}
In this block, several attributes are added to the instance_type variable:
default
- the variable will have the value specified in this attribute unless otherwise specified
description
- description of the variable
type
- is the type of the variable
These attributes are optional. The instance_type variable can be created as follows
variable "instance_type" {}
But it is more difficult to understand what this variable is.
After the variable is created, it can be used in the terraform code as var.instance_type
resource "aws_instance" "foo" {
ami = "ami-0cff7528ff583bf9a"
instance_type = var.instance_type
subnet_id = "subnet-db73f0ac"
vpc_security_group_ids = ["sg-b04b8cd4"]
tags = {
Env = "Dev"
}
volume_tags = {
"Env" = "Dev"
}
}
If I need to use a different type of instance, there are several options. The first is to pass it when running terraform with parameter var
$ terraform apply -var instance_type=t3.micro
# aws_instance.foo will be created
+ resource "aws_instance" "foo" {
+ ami = "ami-0cff7528ff583bf9a"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t3.micro"
Another option is using a file with variables, I will create a file called prod.tfvars
with content
instance_type = "m5.large"
Then I will call terraform with -var-file
option
$ terraform plan -var-file=prod.tfvars
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.foo will be created
+ resource "aws_instance" "foo" {
+ ami = "ami-0cff7528ff583bf9a"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "m5.large"
The next option is via env variables. To do this, you need to create an env variable called TF_VAR_name
.
$export TF_VAR_instance_type=r5.xlarge
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.foo will be created
+ resource "aws_instance" "foo" {
+ ami = "ami-0cff7528ff583bf9a"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "r5.xlarge"
And the last option uses a file named .auto.tfvars
. Create a file with the name prod.auto.tfvars
with the next content
instance_type = "c5.large"
Once I launch terraform it will automatically read variables from this file
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.foo will be created
+ resource "aws_instance" "foo" {
+ ami = "ami-0cff7528ff583bf9a"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "c5.large"
Locals
In addition to the global variables in terraform, you can also use locals. They are convenient to use when some value is repeated often, but there is no need to transfer it to the global variables. They are created in the local’s block. Example:
locals {
subnet_id = "subnet-db73f0ac"
}
And now this local variable can be used in the code as local.subnet_id
resource "aws_instance" "foo" {
ami = "ami-0cff7528ff583bf9a"
instance_type = var.instance_type
subnet_id = local.subnet_id
vpc_security_group_ids = "sg-123"
tags = {
Env = "Dev"
}
volume_tags = {
"Env" = "Dev"
}
}
Data
Some attributes are not always convenient to use as variables, and it is better to dynamically receive values when starting terraform. For example, the ami attribute, if you need always to have the latest version of ami regardless of the region. Or there are other resources created by other terraform code or using the AWS UI, such as VPC or subnet_id and you need to use their IDs in your code. Terraform has a data block for this.
I will show how you can dynamically get the value of ami. To do this, I will create a separate file named data.tf
with such content
data "aws_ami" "amzn" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-kernel-*"]
}
}
Inside the data block are several attributes:
most_recent
- whether to always get the latest version of AMI or not
owners
- which AWS account owns ami
filter
- by what criteria to filter. In this case, I’m filtering by a name that must start with amzn2-ami-kernel. And that way I’ll always have the ID of the latest amazon Linux 2 AMI no matter in what region I’m creating the resources.
This can now be used in our aws_instance resource as data.aws_ami.amzn.id
resource "aws_instance" "foo" {
ami = data.aws_ami.amzn.id
instance_type = var.instance_type
subnet_id = local.subnet_id
vpc_security_group_ids = "sg-123"
tags = {
Env = "Dev"
}
volume_tags = {
"Env" = "Dev"
}
}