Official Documentation https://developer.hashicorp.com/terraform
Installation
https://developer.hashicorp.com/terraform/downloads
Commands
Main Commands
terraform + |
|
---|---|
init |
Prepare your working directory (including provider plugins) for other commands |
validate |
Check whether the configuration is valid |
plan |
Show changes required by the current configuration |
apply |
Create or update infrastructure |
destroy |
Destroy previously-created infrastructure |
All Other Commands
terraform + |
|
---|---|
console |
Try Terraform expressions at an interactive command prompt |
fmt |
Reformat your configuration in the standard style |
force-unlock |
Release a stuck lock on the current workspace |
get |
Install or upgrade remote Terraform modules |
graph |
Generate a Graphviz graph of the steps in an operation |
import |
Associate existing infrastructure with a Terraform resource |
login |
Obtain and save credentials for a remote host |
logout |
Remove locally-stored credentials for a remote host |
metadata |
Metadata related commands |
output |
Show output values from your root module |
providers |
Show the providers required for this configuration |
refresh |
Update the state to match remote systems |
show |
Show the current state or a saved plan |
state |
Advanced state management |
taint |
Mark a resource instance as not fully functional |
test |
Experimental support for module integration testing |
untaint |
Remove the ‘tainted’ state from a resource instance |
version |
Show the current Terraform version |
workspace |
Workspace management |
Frequently Used Flags
--refresh=false
to skip reconciling the real state and the state file terraform.tfstate
Import Existing Resources to tfstate
1
2
terraform import <RESOURCE TYPE>.<NAME> <ID>
terraform import module.<MODULE NAME>.<RESOURCE TYPE>.<NAME> <ID>
Please note that <ID> is specific to each provider, where you should check the provider documentation.
Remove Resource from tfstate
1
2
terraform state rm <RESOURCE TYPE>.<NAME>
terraform state rm module.<MODULE NAME>.<RESOURCE TYPE>.<NAME>
Terraform Configuration Language Basics
Terraform language was previously known as HCL (HashiCorp Configuration Language).
Value Types
Types | Example |
---|---|
String | “Hello” |
Number | 1.23 |
Bool | true |
List | [1, 2, 2, 3] |
Set | [“us-west-1a”, “us-west-1c”] |
Map | {name = “Mabel”, age = 52} |
Null | null |
Structural Types:
Types | Schema | Example |
---|---|---|
Tuple | [<TYPE>, <TYPE>, …] | [“a”, 15, true] |
Object | { <KEY> = <TYPE>, <KEY> = <TYPE>, … } | {name = “John”, age = 52} |
Syntax
1
2
3
4
<BLOCK TYPE> <LABELS> {
<ARGUMENT NAME> = <ARGUMENT VALUE> # a comment
# ...
}
Resource Block
1
2
3
4
resource "<RESOURCE TYPE>" "<NAME>" {
<KEY1> = <VALUE1>
# ...
}
<RESOURCE TYPE>
is usually in the format of <PROVIDER>_<TYPE>
, e.g. aws_instance
Resource Providers Documentation https://registry.terraform.io/browse/providers
Meta-Arguments
-
depends_on
to explicitly specify a dependency which may affect the order of resource provisioning.
e.g.
1 2 3 4 5 6 7
resource "aws_instance" "example" { ami = "ami-a1b2c3d4" instance_type = "t2.micro" depends_on = [ aws_iam_role_policy.example ] }
-
life_cycle
to specify the lifecycle behavior of a resource.
e.g.
1 2 3
lifecycle { create_before_destroy = true }
create_before_destroy
prevent_destroy
(cannot preventterraform destroy
from destroying the resource)ignore_changes
replace_triggered_by
-
count
e.g.
1 2 3 4 5 6 7 8 9 10 11 12 13
resource "local_file" "example" { count = length(var.filenames) filename = var.filenames[count.index] content = "I'm number ${count.index + 1}" } variable "filenames" { default = [ "first_file.txt", "second_file.txt", "third_file.txt", ] }
count.index
refers to the distinct index number (starting with 0) corresponding to this instance.<TYPE>.<NAME>
refers to the resource block.<TYPE>.<NAME>[<INDEX>]
refers to individual instances. -
for_each
e.g.
1 2 3 4 5
module "bucket" { for_each = toset(["assets", "media"]) source = "./publish_bucket" name = "${each.key}_bucket" }
e.g.
1 2 3 4 5 6 7 8
resource "azurerm_resource_group" "rg" { for_each = { a_group = "eastus" another_group = "westus2" } name = each.key location = each.value }
each.key
refers to the map key or set member corresponding to this instance.each.value
refers to the map value corresponding to this instance. (If a set was provided, this is the same aseach.key
)<TYPE>.<NAME>
refers to the resource block.<TYPE>.<NAME>["<KEY>"]
refers to individual instances.
Variable Block
1
2
3
4
5
variable "<NAME>" {
type = <TYPE>
default = <VALUE>
# ...
}
The default type is any
, which can be specified as:
string
number
bool
list(<TYPE>)
set(<TYPE>)
map(<TYPE>)
object({<ATTR NAME> = <TYPE>, ... })
tuple([<TYPE>, ...])
Output Block
Output block helps to print out the value and make it able to be referenced by other modules.
1
2
3
4
Output "<VARIABLE NAME>" {
value = <VALUE>
# ...
}
Locals Block
Use it to assign a local variables to reduce code duplication.
1
2
3
4
5
locals {
<VAR> = <VALUE>
<VAR2> = <VALUE2>
# ...
}
Data Block
Data sources allow Terraform to use information defined outside of Terraform, defined by another separate Terraform configuration, or modified by functions.
Data sources are READ-ONLY infrastructure resources.
1
2
3
4
data "<TYPE>" "<NAME>" {
<KEY1> = <VALUE1>
# ...
}
Reference expression: data.<TYPE>.<NAME>.<ATTRIBUTE>
References to Values
Input Variables
var.<NAME>
E.g. var.mylist[0]
(list), var.members["age"]
(map), var.user_information.name
(object)
Resource Attributes
<RESOURCE TYPE>.<NAME>.<ATTRIBUTE>
E.g. aws_instance.example.ami
, aws_instance.example.ebs_block_device[*].device_name
Local Values
local.<NAME>
From Other Modules
module.<MODULE NAME>.<OUTPUT NAME>
String Templates
Interpolation
${...}
E.g.
"Hello, ${aws_instance.myec2.id}"
Heredoc String
<<
and <<-
For Loop & If Condition
1
"Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"
1
2
3
4
5
<<EOT
%{ for ip in aws_instance.example[*].private_ip ~}
server ${ip}
%{ endfor ~}
EOT
Provider Version Constraints
example:
1
2
3
4
5
6
7
8
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 1.2.0, < 2.0.0, != 1.3.0"
}
}
}
-
=
(or no operator): Allows only one exact version number. Cannot be combined with other conditions. -
!=
: Excludes an exact version number. -
>
,>=
,<
,<=
: Comparisons against a specified version, allowing versions for which the comparison is true. “Greater-than” requests newer versions, and “less-than” requests older versions. -
~>
: Allows only the rightmost version component to increment. For example, to allow new patch releases within a specific minor release, use the full version number: ~> 1.0.4 will allow installation of 1.0.5 and 1.0.10 but not 1.1.0. This is usually called the pessimistic constraint operator.
Configure Remote State
e.g.
1
2
3
4
5
6
7
terraform {
backend "s3" {
bucket = "mybucket"
key = "path/to/my/key"
region = "us-east-1"
}
}
Provisioners
You can use provisioners to model specific actions on the local machine or on a remote machine in order to prepare servers or other infrastructure objects for service.
-
e.g.
1 2 3 4 5 6 7 8
resource "aws_instance" "web" { # ... provisioner "local-exec" { command = "echo ${self.private_ip} >> private_ips.txt" on_failure = continue # by default on_failure = continue } }
-
e.g.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
resource "aws_instance" "web" { # ... # Establishes connection to be used by all # generic remote provisioners (i.e. file/remote-exec) connection { type = "ssh" user = "root" password = var.root_password host = self.public_ip } provisioner "remote-exec" { inline = [ "puppet apply", "consul join ${aws_instance.web.private_ip}", ] } }
Compared with exec provisioners or user data, custom image is usually a batter practice!
-
e.g.
1 2 3 4 5 6 7 8 9
resource "aws_instance" "web" { # ... # Copies the myapp.conf file to /etc/myapp.conf provisioner "file" { source = "conf/myapp.conf" destination = "/etc/myapp.conf" } }
Assign Input Variables
-
Command Line
-var
terraform apply -var 'image_id=ami-abc123' -var 'availability_zone_names=["us-east-1a","us-west-1c"]'
-
Variable Definitions Files
.tfvars
terraform apply -var-file="testing.tfvars"
1 2 3 4 5 6
# testing.tfvars image_id = "ami-abc123" availability_zone_names = [ "us-east-1a", "us-west-1c", ]
-
Environment Variables
TF_VAR_<NAME>
export TF_VAR_image_id=ami-abc123
export TF_VAR_availability_zone_names='["us-east-1a","us-west-1c"]'
Loading Order (from low to high priority):
(1) Environment Variables
(2) terraform.tfvars
(3) *.auto.tfvars
(alphabetical order)
(4) -var
or -var-file
command line flags
Logs
Set Log Levels
export TF_LOG=<log_level>
- INFO
- WARNING
- ERROR
- DEBUG
- TRACE
Set Log File Path
export TF_LOG_PATH=<log_file_path>
unset TF_LOG_PATH
Licensed under CC BY-SA 4.0
Comments