Terraform 101

@tlvince

2020-10-30

Basics

  • Infrastructure as Code Config
  • multi provider
    • cloud-orientated, but not limited to
  • declarative
  • execution plans
  • composeable resources
  • parallel resource creation

Syntax

  • Written in HashiCorp configuration language (HCL)
    • .ini like, supports comments
  • resources, modules
    • everything’s centred around managing resources
<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
  # Block body
  <IDENTIFIER> = <EXPRESSION> # Argument
}

Resource example

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-bucket"
  acl    = "private"

  tags = {
    Name        = "My bucket"
    Environment = "Dev"
  }
}

Lifecycle

  • state file: map config to real resources
  • refresh: reconcile state with reality
  • plan: diff state against desired state
  • apply: apply changes, update state

Execution plan

  • main differentiator
  • integrates nicely with PRs
  • easy to read diff
  • approve before applying changes

Plan example

Terraform v0.12.24
Configuring remote state backend...
Initializing Terraform configuration...
2020/03/25 17:12:54 [DEBUG] Using modified User-Agent: Terraform/0.12.24 TFC/d55ce1e9f0
Refreshing Terraform state in-memory prior to plan...
aws_cloudwatch_log_group.example_log_group: Refreshing state... [id=/aws/lambda/example]

----------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
  - remove

Terraform will perform the following actions:

  # aws_lambda_function.example will be created
  + resource "aws_lambda_function" "example" {
      + arn                            = (known after apply)
      + description                    = "My lambda"

  # aws_lambda_function.example_2 will be updated in-place
  ~ resource "aws_lambda_function" "example_2" {
      ~ memory_size                    = 1024 -> 512

  # aws_lambda_function.example_3 will be removed
  - resource "aws_lambda_function" "example_3"

Workspaces

  • logical grouping of resources
  • each workspace gets its own isolated state file
  • use cases:
    • isolate environments (though account-level isolation better)
    • as a temporary infra copy (per Git branches)
    • same infra, different env variables
    • modularise larger workspaces to limit blast radius

Caveats*

  • providers are just (Go) wrappers over vendor APIs
  • behaviour can be inconsistent with admin console
  • interpolations are unknown until apply
  • language limitations: count vs if, no module count, depends_on
  • tests?! localstack can help
  • not suitable for app code
  • importing existing infra into Terraform is painful

*as of v0.12

Automation ideas

  • plan output in PRs
  • terraform {fmt,validate}
  • tflint: provider-specific linting + house style
  • interactive approval and apply

Thanks!

// reveal.js plugins