Skip to content

Instantly share code, notes, and snippets.

@voutasaurus
Last active November 26, 2020 06:08
Show Gist options
  • Save voutasaurus/f9959caa7b52c7bb642c51a211c36c9e to your computer and use it in GitHub Desktop.
Save voutasaurus/f9959caa7b52c7bb642c51a211c36c9e to your computer and use it in GitHub Desktop.
Terraform for morons like me

What is a Terraform?

Terraform is something you install on your computer that lets you tell other computers what to do.

It's kinda like puppet and ansible and all those other DevOps™ tools that I also have no clue about. But with added Cloud™.

Who should use Terraform?

If you have separate firefox, chrome AND safari windows all open just so you can log into three different AWS accounts to use Jeff Bezos' idea of a good GUI then Terraform might be for you.

Also if somebody in your team was in your GCE GUI and somehow deleted the main billing account thereby causing all of your company's servers to shut down unexpectedly then Terraform might be for you too.

Lastly if you have the AWS and GCE and Azure CLIs installed but you're worried that actually ever using them will be extremely error prone then again: Terraform might be for you!

THAT'S TOTALLY ME. PLEASE TAKE ME WITH YOU.

Okay chill. We still have a LOOOONG way to go.

How do I get a Terraform?

If you're on a Mac do this:

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

If you're not on a Mac then tell your boss to join us in the 21st century. If that doesn't work go here: https://learn.hashicorp.com/tutorials/terraform/install-cli

Okay now I am ready to TERRAFORM

Great so now it's time for you to meet *.tf files. They are Declarative Infrastructure As Code™ and written in a fun new document format literally nobody asked for. They look kind of like JSON had a baby with Shell function code.

(I mean look at this shit)

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 2.70"
    }
  }
}

provider "aws" {
  region = "eu-west-2"
}

resource "aws_instance" "example" {
  ami           = "ami-11212121"
  instance_type = "t2.micro"
}

If you have the above in a file called main.tf then from that directory you can make your cloud account create stuff:

terraform init # this is sorta like git init (it creates a .terraform subdirectory to store cloud plugins and whatnot)
terraform apply # this will actually call your cloud provider over The Internet and tell it to make whatever resources are in main.tf

(Note: if you don't have your Cloud's CLI configured then go do that first)

Whats the difference between a terraform, a provider and a resource in the .tf file?

I'll answer these questions backwards because sometimes it makes more sense to think that way in the t e c h n o s p a c e.

A resource is anything in your cloud account that you'd like created or updated or destroyed, like a VM or a security group or a Redis cluster.

A provider is a plugin which tells terraform how to talk to a specific cloud provider (in this case AWS).

We only need one terraform block, it's for telling terraform where to download the provider plugins from. It's actually new in Terraform 0.13 so if you're using an older version of Terraform the terraform part will actually confuse Terraform so you should either delete it or update Terraform (brew update hashicorp/tap/terraform).

If Terraform is declarative, and the cloud provider APIs operate imperatively, how does state work?

Wow this is actually a big brain question. Nice!

By default Terraform stores its knowledge of state in a local file in your working directory called terraform.tfstate.

If you want to share Terraform state across your team, you can also make it store the state in an s3 bucket.

Create a file called backend.tfvars that looks like this:

bucket = "unique-bucket-name-goes-here"
key    = "state/component-name-goes-here"
region = "us-east-2"

And run the init command with this backend info:

terraform init -backend-config backend.tfvars

Be aware that if you do use non-local state you can get into some weird situations. For instance if you lose network in the middle of running terraform apply then the state in the s3 bucket may be out of sync with both your local state and your cloud account's actual state. If you get into this kind of situation it's often possible to get out of with the local errorstate, so if you get stuck reach out to somebody who knows more about Terraform.

How do I reach out to people who know more about Terraform?

If you like web based forums: https://discuss.hashicorp.com/c/terraform-core/27

If you like Slack: #terraform-providers on Kubernetes slack (https://slack.k8s.io/), #terraform on SweetOps/CloudPosse slack (https://slack.cloudposse.com/)

If you like IRC: #terraform on freenode

If all else fails you could always post a question on StackOverflow or an issue on the relevant Github repo.

I once saw a terrform and there were many *.tf files, how does that work?

Just imagine that all the *.tf files are just different sections of the same file. Even a main.tf isn't needed, your files can be called whatever. It's helpful to other humans to give them descriptive names like load-balancer.tf and variables.tf.

Terraform has variables?

Yeah create a variables.tf file and put this in it:

variable "region" {
  default = "us-west-2"
}

Then in your other files you can use region = var.region instead of region = "us-east-2".

Plus now whenever you like you can specify an overriding value when you apply the config:

terraform apply -var 'region=us-west-2'

Wait doesn't this mean it's not Declarative™ anymore?

Uhhh. Hey what's that over there!

Why it's somebody else's very elaborate Terraform config files.

I don't understand most of this but, could I like, maybe use it as like, a dependency?

Yes! You can use somebody else's terraform directory as a module. You can even specify values for their variables.

Just put this in your main.tf and Terraform will flatten their *.tf files into yours when it applies state.

module "stack-1234" {
  source = "providername/stack/aws"
  version = "0.0.1"
  servers = 5
}

The name you give the module is your own so make it descriptive to your use case.

By the way the source here can be a local directory path, a Terraform registry location, a github repo (e.g. "github.com/hashicorp/example"), a bitbucket repo, a generic git repo ("git::https://example.com/tf.git"), mercurial repo, zip URL, S3 bucket or a GCS bucket. Here's a full rundown on how all that works.

The other values you set here (e.g. servers = 5) have to correspond to the variables described in the other terraform directory.

Oh right I get it now it's Declarative™ again

Oh, right. Yeah that was totally intentional...

Cool so what else do I need to know?

Maybe outputs? Maps? I dunno there's a bunch of other stuff here are the full Official Docs.

Also if you feel like this intro was too short or too informal then :'( but also check out the Official Learning Materials

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment