VERY Quick Start: Terraform

by Jannik Arndt

This post contains the absolut essence from the Terraform Getting Started Guide: https://www.terraform.io/intro/getting-started/install.html

Preparation

brew install terraform

Create aws.tf:

provider "aws" {
  region     = "us-east-1" 
}

resource "aws_instance" "example" {
  ami           = "ami-2757f631" // https://cloud-images.ubuntu.com/locator/ec2/
  instance_type = "t2.micro"
}

AMI = Amazon Machine Images

AWS credentials are stored in environment vars:

export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...

Init

$ terraform init
...
Terraform has been successfully initialized!
...
$ terraform plan -out planfile
  + aws_instance.example
      ami:                          "ami-2757f631"
      associate_public_ip_address:  "<computed>"
...
$ terraform apply planfile
aws_instance.example: Creating...
...
aws_instance.example: Still creating... (10s elapsed)
aws_instance.example: Still creating... (20s elapsed)
aws_instance.example: Still creating... (30s elapsed)
aws_instance.example: Still creating... (40s elapsed)
aws_instance.example: Creation complete (ID: i-00b2e1a29daee4371)
$ terraform show
aws_instance.example:
  id = i-00b2e1a29daee4371
  ami = ami-2757f631
  associate_public_ip_address = true

Change

ami-2757f631 (Ubuntu 16.04 LTS AMI) => ami-b374d5a5 (Ubuntu 16.10 AMI)

In aws.tf:

provider "aws" {
  region     = "us-east-1"
}

resource "aws_instance" "example" {
  ami           = "ami-b374d5a5"
  instance_type = "t2.micro"
}
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
aws_instance.example: Refreshing state... (ID: i-00b2e1a29daee4371)
...
-/+ aws_instance.example (new resource required)
      ami:                          "ami-2757f631" => "ami-b374d5a5" (forces new resource)
      associate_public_ip_address:  "true" => "<computed>"
...
$ terraform apply
aws_instance.example: Refreshing state... (ID: i-00b2e1a29daee4371)
aws_instance.example: Destroying... (ID: i-00b2e1a29daee4371)
...
aws_instance.example: Destruction complete
aws_instance.example: Creating...
  ami:                          "" => "ami-b374d5a5"
  associate_public_ip_address:  "" => "<computed>"
...
aws_instance.example: Creation complete (ID: i-05a8f2e88ae0faace)

Destroy

$ terraform plan -destroy
Refreshing Terraform state in-memory prior to plan...
...
  - aws_instance.example
...
$ terraform destroy
aws_instance.example: Refreshing state... (ID: i-05a8f2e88ae0faace)
...

  - aws_instance.example

Terraform will delete all your managed infrastructure, as shown above. 
There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

aws_instance.example: Destroying... (ID: i-05a8f2e88ae0faace)
aws_instance.example: Destruction complete

Destroy complete! Resources: 1 destroyed.

Assigning an IP to the instance

In aws.tf:

provider "aws" {
  region     = "us-east-1"
}

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

resource "aws_eip" "ip" {
  instance = "${aws_instance.example.id}"
}
$ terraform apply planfile 
aws_instance.example: Creating...
...
aws_instance.example: Creation complete (ID: i-0478b3c5b6a085287)
aws_eip.ip: Creating...
...
aws_eip.ip: Creation complete (ID: eipalloc-6be79a58)

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
$ terraform refresh
aws_instance.example: Refreshing state... (ID: i-0478b3c5b6a085287)
aws_eip.ip: Refreshing state... (ID: eipalloc-6be79a58)
$ terraform show
aws_eip.ip:
  id = eipalloc-6be79a58
  association_id = eipassoc-590d9e6c
  domain = vpc
  instance = i-0478b3c5b6a085287
  network_interface = eni-73845aa6
  private_ip = 172.31.17.98
  public_ip = 52.204.255.194
  vpc = true
aws_instance.example:
  id = i-0478b3c5b6a085287
  ami = ami-b374d5a5
  associate_public_ip_address = true

Dependencies

The order in which resources are created is determined by terraforms analysis of (implicit) dependencies. Dependencies can also be defined explicitly, for example:

resource "aws_eip" "ip" {
  instance   = "${aws_instance.example.id}"
  depends_on = ["aws_instance.example"] # <- explicit dependency
}

To view a dependency graph:

$ terraform graph > graph.dot

And open with graphviz: aws_eip.ip aws_instance.example provider.aws [root] meta.count-boundary (count boundary fixup) [root] provider.aws (close) [root] root

Provisioning/Bootstrapping

https://www.terraform.io/docs/provisioners/index.html

Change aws.tf:

resource "aws_instance" "example" {
  ami           = "ami-b374d5a5"
  instance_type = "t2.micro"
  
  # add provisioner
  provisioner "local-exec" {
      command = "echo ${aws_instance.example.public_ip} > ip_address.txt"
  }
}

# add output
output "ip" {
  value = "${aws_eip.ip.public_ip}"
}

Provisioners are only run, when a resource is first created!

$ terraform destroy
...
$ terraform apply
...
Outputs:

  ip = 50.17.232.209

Blog


Apples Time Machine is a great backup solution, you only have to do one thing: Connect your disk from time to time.

Since that is way harder than it sounds, there’s a second option: Buy a 329€ Time Capsule and do backups over wifi!

That’s too expensive? Here’s how to build your own Time Capsule with a Raspberry Pi 3 and an external hard drive.




Sonoff takes the standard ESP8266 chip and adds two things:

  • a casing with wifi and great connectors and
  • a custom OS and an app to control the devices.

Unfortunately, the second addition also means that all communication goes through Sonoff’s servers. Here’s how to get rid of that. Without soldering or connecting anything.




“Hey Siri, turn on the bedroom lights!” I want that. Here’s how I did it:

  • I bought a bunch of Sonoff devices (5€ each, 10€ for a light switch).
  • I bought a raspberry pi (33€).
  • I installed an MQTT broker and homebridge on the pi.