Infrastructure as Code with Terraform by Mitchell Hashimoto
Terraform enables you to describe almost anything with an API as code. From infrastructure to high level services, Terraform can help construct everything required to run your applications. In this talk, we’ll explore using Terraform to manage both traditional and non-traditional resources and dive into how to write best practices Terraform for reusability within teams.
24. Terraform
Tool to manage anything with an API as code
Open source (> 12,000 stars, > 1,000 contributors)
Support for over 100 providers, including all major
clouds: AWS, Azure, GCP, and more.
25. Goals
Unify the view of resources using infra as code
Expose a way for individuals and teams to safely and
predictably change infrastructure
Manage anything with an API
26. resource "aws_instance" "web" {
ami = "ami-b123125"
}
resource "dnsimple_record" "hello" {
domain = "example.com"
name = "test"
value = "${aws_instance.web.public_ip}"
type = "A"
}
C O D E E D I T O R
27. resource "aws_instance" "web" {
ami = "ami-b123125"
}
resource "dnsimple_record" "hello" {
domain = "example.com"
name = "test"
value = "${aws_instance.web.public_ip}"
type = "A"
}
C O D E E D I T O R
28. resource "aws_instance" "web" {
ami = "ami-b123125"
}
resource "dnsimple_record" "hello" {
domain = "example.com"
name = "test"
value = "${aws_instance.web.public_ip}"
type = "A"
}
C O D E E D I T O R
29. resource "aws_instance" "web" {
ami = "ami-b123125"
}
resource "dnsimple_record" "hello" {
domain = "example.com"
name = "test"
value = "${aws_instance.web.public_ip}"
type = "A"
}
C O D E E D I T O R
31. resource "aws_instance" "web" {
- ami = "ami-b123125"
+ ami = "ami-c345123"
}
resource "dnsimple_record" "hello" {
domain = "example.com"
name = "test"
value = "${aws_instance.web.public_ip}"
type = "A"
}
C O D E E D I T O R
32. Command: terraform plan
The plan shows you what will happen
You can save plans to guarantee what will happen
Plans show reasons for certain actions (such as re-
create)
Prior to Terraform, users had to guess change ordering,
parallelization, and rollout effect
33. Command: terraform plan
+ resource will be created
- resource will be destroyed
~ resource will be updated in-place
-/+ resources will be destroyed and re-created
34. T E R M I N A L
$ terraform plan
+ aws_instance.web
ami: "ami-db24d8b6"
availability_zone: "<computed>"
ebs_block_device.#: "<computed>"
ephemeral_block_device.#: "<computed>"
instance_state: "<computed>"
instance_type: "t2.micro"
key_name: "<computed>"
network_interface_id: "<computed>"
placement_group: "<computed>"
private_dns: "<computed>"
private_ip: "<computed>"
public_dns: "<computed>"
public_ip: "<computed>"
# ...
35. Command: terraform apply
Executes changes in order based on the resource graph
Parallelizes changes when possible
Handles and recovers transient errors
Runs plan first unless given a serialized plan file
36. T E R M I N A L
$ terraform apply
aws_instance.web: Creating...
ami: "" => "ami-db24d8b6"
# ...
source_dest_check: "" => "true"
subnet_id: "" => "subnet-f6e6a5dc"
aws_instance.web: Still creating... (10s elapsed)
aws_instance.web: Still creating... (20s elapsed)
aws_instance.web: Creation complete
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
37. A Workflow for Safe Infrastructure
"terraform apply"
The make things happen command (after confirm)
Tell Terraform what you want, sit back and let
Terraform make it a reality.
38. Modules
Reusable packages of Terraform configuration
Enable broader usage of Terraform
Share and discover: https://registry.terraform.io/
39. module "consul" {
source = "hashicorp/consul/aws"
version = "~> 0.3.0"
}
output "servers" {
value = "${module.consul.asg_name_servers}
}
C O D E E D I T O R
51. resource "pagerduty_team" "engineering" {
name = "Engineering"
description = "All engineering"
}
resource "pagerduty_user" "earline" {
name = "Earline Greenholt"
email = "125.greenholt.earline@graham.name"
teams = ["${pagerduty_team.engineering.id}"]
}
C O D E E D I T O R
52. resource "pagerduty_schedule" "foo" {
name = "Daily Engineering Rotation"
time_zone = "America/New_York"
layer {
name = "Night Shift"
...
users = ["${pagerduty_user.earline.id}"]
restriction {
type = "daily_restriction"
start_time_of_day = "08:00:00"
duration_seconds = 32400
}
}
}
C O D E E D I T O R
54. resource "datadog_timeboard" "redis" {
title = "Redis Timeboard (created via Terraform)"
read_only = true
graph {
title = "Redis latency (ms)"
viz = "timeseries"
request {
q = "avg:redis.info.latency_ms{$host}"
type = "bars"
}
}
}
C O D E E D I T O R
55. resource "datadog_monitor" "foo" {
name = "Name for monitor foo"
type = "metric alert"
message = "Monitor triggered. Notify:
@hipchat-channel"
escalation_message = "Escalation message @pagerduty"
query = "avg(last_1h):avg:cpu{host:foo} by {host} > 4"
thresholds {
ok = 0
warning = 2
warning_recovery = 1
critical = 4
critical_recovery = 3
}
C O D E E D I T O R
57. variable "issue_labels" {
default = {
"custom-label" = "533D99"
"documentation" = "FFB340"
"waiting-reply" = "CC6A14"
}
}
resource "github_issue_label" "test_repo" {
repository = "${github_repository.example-repo.id}"
count = "${length(var.issue_labels)}"
name = "${element(keys(var.issue_labels),
count.index)}"
color = "${element(values(var.issue_labels),
count.index)}"
}
C O D E E D I T O R