Terraform Certification: A Journey

Journey Towards Learning Terraform and Certifying

  • First off, the Terraform docs are well written.
  • Much of this is from Moosa Khalid see the awesome class on ACoud Guru
  • Another great resource is KP Labs and Zeal Vora @zealvora excellent course is on Udemy https://kplabs.in @zealvora
  • The text Infrastructure as Code is also a great reference Kief Morris
  • Terraform: Up and Running was/is a great reference and continues to evolve (third edition) and be awesome! Thanks to @brikis98!

HashiCorp Tao

  • The Tao contains the principles and foundation of all of the products in the HashiCorp stack
  • These principles really frame the why and inform so much it's worthy of separate mention. Every part of their stacks allow solving problems and like Heroku's 12 Factors, the HashiCorp Tao is a substantial contribution. One could remove any mention of HashiCorp in the Tao and it would be a worthy model to follow.

  • Terraform, written in Go, is a single binary that provides the user magical powers.

What is Infrastructure as Code

  • What is Infrastructure as Code
  • What are the benefits of Infrastructure as Code?
  • What is immutable infrastructure and the benefits of this approach? Immutability of Variables in functional programming.

Declarative vs Procedural Approaches

Nice Summary - In many ways good configuration management principles and practices are a direct response to Click-Ops

  • Procedural Paradigm imperative (examples as iterative)

  • Declarative Paradigm Here it is. Behold my deploy.yaml. This is what is to be. This is the Desired State Snover/Monad Manifesto

Cloud Agnosticism with Providers

  • Enabling multi-cloud deployments is easy using Terraform

The Terraform Workflow

  • Scope what is needed
  • Write your code. Declare your resources as desired
  • (Optional) Make pretty and more readable via format terraform fmt (optional but nice )
  • Init: Initialize the providers you'll be supporting
  • (Optional) Validate terraform validate
  • Plan: This is where there is a a reconciliation between what exists and what is declaratively desired in the config.
  • Apply: Instantiate your resources. Terraform handles the needed dependencies and the sequence of the creation or resources.

  • Destroy: Destroy the resources you have created.

Other Cool Features

  • terraform fmt : format your code. Built-in way to make your code more beautiful

  • terraform graph : Visualize via a convertible text a graphical depiction of dependency.

  • terraform output: Display outputs as created in output.tf

  • terraform refresh refresh a resource or group of resources (options to limit refresh are supported)

  • terraform providers See the providers that were initialized and have support

Variables

  • Declaration of variables in .tf files as well as gathered in terraform.tfvars as a best practice.
  • Variables can have blank values {} for input and will require them or they'll error.
  • Use the variable reserved word to create a variable block that has the following:
variable "my-status" {
    description = "How I am"
    type = string
    default = "Fine"
}

Note that description, type and default are optional so For example, variable "mystatus" {} is valid

  • Introduce variables at the command line
export TF_VAR_instancetype="t2.nano"
terraform plan -var="instancetype=t2.small"
  • Define in a variables.tf file
variable "instancetype" {
  default = "t2.micro"
}

Validation Feature

  • A superpower of terraform is the validation feature providing conditional validation of configuration code. In this example conditional validation of variable length being greater than 4.
variable "my-status" {
    description = "How I am"
    type = string
    default = "Fine"
    validation {
        condition = length(var.my-status) > 4
        error = "There is an error in your status, my dude" 
    }
}
  • Use the sensitive config argument to indicate

Variable Types and Constraints

  • Base types: string, number and bool
  • Complex Types: list, set, map, object, tuple

EXAMPLE: Base Type: string

variable "os_name" {
    type = string
    default = "Arch"
    description = "BTW I run Arch"
}

EXAMPLE: Base Type: List

variable "availability_zone_names" {
    type = list(string)
    default = ["us-east-2b"]
}

EXAMPLE: Base Type: List

variable "docker_ports" {
    type = list(object({
    internal = number 
    external = number 
    protocol = string 
}))    
    default = [
      {
        internal = 8300
        external = 8300
        protocol = "tcp"
      }
]
}

Terraform Provisioners

  • Best Practices include using them sparingly, opting instead for a hyperscaler service if available, when possible.
  • Two types of Provisioners: Creation Time and Destroy Time provisioner. These can be set to run when a resource is being created or destroyed
  • Use only when actions desired are not within Terraforms's declartive model. A Provisioner's state is not examined
  • Only Zero return codes are valid. If a provisioner returns a non-zero return code , the resource is tainted

Here's an example of a local-exec provisioner

  resource "null_resource" "dummy_resource" {

    provisioner "local-exec" {
        command = "echo '0' > status.txt"
  } 
    provisioner "local-exec" {
        when = destroy
        command = "echo '1' > status.txt"
  } 
}

Terraform State

  • Critical for terraform operations. Without declarative state terraform doesn't work. It maps real resources to definitions in terraform code
  • By default, state is dumped locally into terraform.tfstate but can be stored in object storage (e.g. s3 or GCS)
  • Before any infrastructure is modified, terraform checks the existing state file is up to date with the existing infrastructure
  • Resource dependency metatdata is tracked in the state-file. Dependencies for providers (subnet before ec2 launch is completely handled in terraform)
  • The statefile also caches resource attributes, making it more performant and less chatty. So much of the data it will need and
  • What does the terraform state command do? It is a utility for manipulating and managing the state of resources
  • Advanced state management allows for manual removal of resources that will remove it from terraform management
  • List out the tracked resources in terraform via terraform state list
  • List out the tracked resources in terraform via terraform state show
  • List out the tracked resources in terraform via terraform state rm $RESOURCE

Local and Remote State and Storage

  • Use AWS S3 or GCS bucket to persist state and allow for collaboration.
  • Resource locking enable bby default with local state but not all backends support this so check.
- terraform {
  required_providers {
    docker = {
      source = "kreuzwerker/docker"
    }
  }
  required_version = ">= 0.13"
  backend "s3" {
    profile = "demo"
    region  = "us-east-1"
    key     = "terraform.tfstate"
    bucket  = "<AWS-S3-BUCKET-NAME-GOES-HERE>"
  }
}
  • Note: One can also create the bucket using either terraform or the aws cli as follows: aws --profile tempprofile s3api create-bucket --bucket tfstate-persist-04-01-2022

Using Modules

  • Can be hosted or local. Use a hierarhical structure to organize e.g. providers/vpc

Other Cool Features : Built-In Functions

  • Pre-packaged built-in functions allow to transform and combine values
  • The join function can be used to join together variables and resources
  • Useful functions include:
  • file function for inserting or manipulating files
  • timestamp() will provide a UTC timestamp
  • min(6,2,3,4) or max(82,88,19) to finnd the same
  • To find if a string is contained within use contains(["configparm1",configparm2", config3,625,23], "config3") This will return a boolean value of true or false

Variable Type Constraints

  • Variable Type Constraints control the type of variable values they are Primitive and Complex
  • Primitive: includes single type value: number, string, bool (e.g. 15,"Production",True)
  • Complex Type Constraints are: list, tuple, map, object These represent multiple types in a single variable
  • Complex types can be further divided into two types of Constructors. The first is a Collection which allows multiple values of one primitive to be grouped together. Examples of these are:

  • list(type)

  • map(type)

  • set(type)

Complex Type: Structural Variable

  • Another Complex type: allows for multiple types (num,string,bool) in the variable value. An example could be as follows:
variable "coach" {
  type = object({
    name = string
    hourly = number
  })

}

Looping and Idempotency are Amazing

If ever in an administrator's role of having to copy out a file or perform a task across a sh%t@%n of systems quickly and reliably iterating through a list of endpoints is a common task. The delightful task of assuring state of goodness on the servers you've just sprayed out an errant command and the details around state is an important detail.

Additional Tooling and Integrations

  • Terragrunt - See materials Git

HashiCorp Resources

Study Items

  • Understand state. Types of Backends. State locking and which backends support it
  • The types of blocks: resource data output variable terraform
  • How does state, the terraform.tfstate file and the live infra work together.
  • How are manually created resources dealt with
  • Terraform Cloud and Terraform Enterprise, and Terraform OSS. Know the additional features of HCP and differences
  • Understand the VCS' that are supported Github, BitBucket, remote backends,
  • Sensitive parameter and how secrets and Vault provider are used
  • The Provider model and plug-ins. How these work.
  • Provisioners: local-exec, remote-exec, using Ansible invocation
  • Using the terraform console to debug code
  • Loops and Conditionals within Terraform

Further Exploration

  • The AWS CDK is bananas.
  • CDKtf is available for Terraform so HCL can be used to build in AWS