Skip to content

Terraform

Setup

  • Install manually or use a repository manager
  • enable autocomplete terraform -install-autocomplete
  • Read provider specific setup documentation on terraform registry or here
  • Create folder, create your tf files and run: terraform init && terraform apply

Wording

  • a provider creates and manages resources. They wrap the API of a service (provider) like AWS, Azure or GCP.
  • If you use multiple providers you can qualifiy which provider uses which resource.
  • a resource might be a physical resource like a aws EC2 instance or a logical resource like a application.
  • A resource has a type and a name (e.g. resource "aws_instance" "example"`{...})and can be configured inside the curly brackets.
  • a datasource is a way to get information about existing infrastructure (mostly useful when it is not managed by terraform or by another terraform configuration)
  • a set of .tf files is called a terraform configuration

CLI

terraform init # initializes various local settings 
terraform fmt # format all files in directory
terraform validate # validate file

terraform apply # checks diff between config file and real infrastructure and creates execution plan to eliminate this diff

terraform state # The state of the infrastructure is saved in terraform.tfstate file. It can be manually modified by this command.

terraform destroy # completely destroys the Terraform-managed infrastructure

Resource Dependencies

There are explicit and implicit dependencies for creating a order of actions.

  • explicit: with the depends_on field of a resource.
  • implicit: e.g. usage of instance = aws_instance.example.id

Resources which are not dependant on others can be build in parallel.

Provisioning

  • Only necessary if you do not use image-based infrastructure (you can create images with vagrant or packer).
  • "can be used to model specific actions on the local machine or on a remote machine in order to prepare servers or other infrastructure objects for service."
  • is not declarative
  • provisioner are defined inside a resource and have a type like: local-exec or remote-exec
  • Are for bootstrapping components (on creation) not to change software on a running component.
  • You need to destroy the infrastructure if the resource already exist, so the resource will be recreated and the bootstrapping logic of the provisioner can be done.
  • If a resource successfully creates but fails during provisioning, Terraform will error and mark the resource as "tainted".
  • Terraform tries to destroy and recreate tainted resources every time apply ist called.
  • terraform taint <resource.id> manually marks a resource as tainted.

Input Variables

Official documentation

How to use variable

var.my_api_token

#use nested var
var.system.name
#use list
element(var.system.used_port, 0)
# use map
lookup(var.system.port_app, "80", "default_val")

How to declare a variable

# with default value and description
variable "my_api_token" {
  type        = string # number, bool, list(<TYPE>), map(<TYPE>) etc.
  description = "An API token."
  default = "1234-5679-123"
  #sensitive=true #does not show value in logs
}

# nested variable
```hcl
variable "system" {
  type = object({
    name      = string
    used_ports = list(string)
    port_app = map(string)
  })
  default = object({
    name      = "VLS"
    used_ports = ["80","43"]
    port_app ={"80":"http","43":"https"}
  })
}

Where to initialize variable:

In a nutshell:

  • preset in variables.tf file via the default field
  • overwrite console (-var 'var_name=var_value')
  • overwrite in terraform.tfvars file
  • overwrite in *.tfvars file and (-var-file 'production.tfvars')
  • overwrite in environmental variables (TF_VARS_)

A bit more extensive:

  • variables are defined in a variables.tf file and may be assigned a default value
  • variables are accessed with a var.<variable_name> notation.
  • variables can be overwritten in console: terraform apply -var 'region=us-east-2'
  • variables can also be overwritten from file. Terraform search automatically for terraform.tfvars or .auto.tfvars files. Alternatively you can pass a file in console terraform apply -var-file 'production.tfvars'.
  • variables can be overwritten by environment variables. They need to start with TF_VAR_. Environment variables are limited to string-type variables (can not use List and map type variables).
  • variables which are unspecified are asked for after executing terraform apply

Variable Types

Lists

# define
variable "cidrs" { type = list }`

# init
cidrs = [ "10.0.0.0/16", "10.1.0.0/16" ]

Maps

# define and init
variable "amis" {
  type = "map"
  default = {
    "us-east-1" = "ami-b374d5a5"
    "us-west-2" = "ami-4b32be2b"
  }
}

# use
resource "aws_instance" "example" {
  ami           = var.amis["us-east-1"]
  instance_type = "t2.micro"
}

Output Variables

Output blocks can be pasted in any of the *.tf files. Output are printed after ``terraform output`` or ``terraform apply`` are run. In a rot module the label of the output block is showed to the user as the name of the variable. In a module the label can be used to reference the variable. You may need to prefix the variable with the terraform type likedataorvar`.

Example:

output "ip" {
  value = aws_eip.ip.public_ip
}

modules

Modules are self-contained packages of Terraform configurations that are managed as a group. Any set of Terraform configuration files in a folder can be a module. The official modules can be downloaded from Terraform Registry.

use module

  • After adding new modules you need to rerun terraform init not only terraform apply
  • terraform get will download the modules
  • Modules reside under ~/.terraform/modules/
  • You can define from where to download the module via the source attribute of module
    • local: ./my-module
    • git: 'github.com/crowdsalat/examplemodule'
    • Terraform Registry: source = 'hashicorp/consul/aws'

Example for module usage via registry:

module "consul" {
  source      = "hashicorp/consul/aws"
  version = "0.7.3" # optional
  num_servers = "3"
}

create module

  • A module is a bunch of .tf files in a directory
  • The files are only for organization, terraform just merges them to one file before using
  • The name of the module is defined by the folder

Files (convention):

  • main.tf
  • variables.tf: input parameters for the module
  • outputs.tf: return values of the module
  • backend.tf: define remote backend
  • variables.tf: used variables

Remote State Storage

  • Use a remote backend to store state-data on a server.
  • When not configured the state is stored locally in a terraform.tfstate file
  • There are different backends. Terraform Cloud is one of such.

Google cloud backend example:

 backend "gcs" {
    bucket = "existing-bucket-name"
  }

expressions

Documentation