Build, Combine, Launch Infrastructure


What ?
Infrastructure as Code
Again ?




What ?

Building, Changing, Versioning
Infrastructure
Safely and Efficiently.
Why ?
Multi-Tier Applications

Building and Managing
infrastructure / external component
Why ?
Disposable Environments
Spawn environments
Disposed of
Quickly and Easily

Why ?
Software Defined Network
Allows the network to better support the applications running on top.

Why ?
Multi-Cloud Deployment
Increase fault-tolerance

Terraform Concept
HCL
HashiCorp Configuration Language
Comments start with # or // or /* and */
Values are assigned with the syntax key = value
Value primitive : string, number, boolean, object, or list.
my_str = "foobar"
Multi-line strings :
<<FOO
hello
world
FOO
Numbers :
foo = 42
bar = 0x2A
toto = 042
Boolean : true, false
Arrays : ["foo", "bar", 42, [78]]
Objects :
variable "ami" {
description = "the AMI to use"
}
Terraform Concept
Interpolation
${}
Call a user attribute
${var.foo}
${count.index + 1} # math
${var.amis.us-east-1} # map
Call a reference attributes
of other resources
TYPE.NAME.ATTRIBUTE
${aws_instance.web.id}
Ressource ___/ | \___ Attribute
|
resource name
${aws_instance.web.0.id} return the id
${aws_instance.web.*.id} return a list of id
Call a reference attributes
of your own resource
self.ATTRIBUTE
${self.private_ip_address}
Terraform Concept
Built-in function
String manipulation
base64encode / base64decode (string)
upper / lower (string)
format(format, args...) - the format is standard sprintf syntax.
Example used commonly for naming servers: format("web-%03d", count.index + 1).
split(delim, string) - Example: split(",", module.amod.server_ids)
Terraform Concept
Built-in function
Network manipulation
cidrhost(iprange, hostnum) - Example, cidrhost("10.0.0.0/8", 2) returns 10.0.0.2.
The hostnum can be equal to the server ressource count
cidrnetmask(iprange) - Example, cidrmask("10.0.0.0/8") returns 255.0.0.0.
Terraform Concept
Built-in function
Other functions
concat(list1, list2)
file(path) - file("${path.module}/file").
element(list, index) - Example: element(aws_subnet.foo.*.id, count.index)
lookup(map, key) - Example on var.amis.
uuid() - Returns a UUID4 string.
Terraform Concept
Provider
provider "aws" {
region = "eu-west"
}
provider "google" {
region = "foo"
project = "bar"
credentials = "creds"
}
That all ?
AtlaS, Azure, Chef, CenturyLinkCloud, CloudFlare, CloudStack, Cobbler, Consul, Datadog, DigitalOcean, DNSMadeEasy, DNSimple,Docker, Dyn, GitHub, Fastly, Google Cloud, Heroku, InfluxDB, Mailgun, MySQL, OpenStack, Packet, PostgreSQL, PowerDNS , Rundeck, VMware vSphere ...
Terraform Concept
Ressources
provider "aws" {
region = "us-east-1"
}
resource "aws_instance" "web" {
ami = "ami-408c7f28" # Ubuntu 14.04
instance_type = "t1.micro"
tags {
Name = "HelloWorld"
}
}
Terraform Concept
Ressources
resource "aws_iam_role" "iam_for_lambda" {
name = "iam_for_lambda"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_lambda_function" "test_lambda" {
filename = "lambda_function_payload.zip"
function_name = "lambda_function_name"
role = "${aws_iam_role.iam_for_lambda.arn}"
handler = "exports.test"
source_code_hash = "${base64sha256(file("lambda_function_payload.zip"))}"
}
Terraform Concept
Provisionners
resource "aws_instance" "web" {
...
# Copies the myapp.conf file to /etc/myapp.conf
provisioner "file" {
source = "conf/myapp.conf"
destination = "/etc/myapp.conf"
}
# Copies the configs.d folder to /etc/configs.d
provisioner "file" {
source = "conf/configs.d"
destination = "/etc"
connection {
user = "${var.aws_ssh_user}"
private_key = "${var.aws_ssh_cert}"
}
}
}
Terraform Concept
Provisionners
resource "aws_instance" "web" {
...
provisioner "remote-exec" {
inline = [
"puppet apply",
"consul join ${aws_instance.web.private_ip}"
]
connection {
user = "${var.aws_ssh_user}"
private_key = "${var.aws_ssh_cert}"
}
}
}
Terraform Concept
Variables
variable "key" {
type = "string"
default = "value"
}
variable "images" {
type = "map"
default = {
us-east-1 = "image-1234"
us-west-2 = "image-4567"
}
}
Terraform Concept
Output
output "ip" {
value = "${aws_eip.ip.public_ip}"
}
Terraform Concept
Module
self-contained packages of Terraform configurations
reusable components in Terraform

Terraform plugin

Terraform is built on a plugin-based architecture
package main
import (
"github.com/hashicorp/terraform/plugin"
)
func main() {
plugin.Serve(new(MyPlugin))
}
Demo
AWS:
- Key pair
- VPC : SDN
- 2 security groups
- subnet
- gateway
- route rules
- ec2 instance (with nginx)
- elb (loabalancer)
Demo
terraform graph:
digraph {
compound = "true"
newrank = "true"
subgraph "root" {
"[root] aws_elb.demo_web" [label = "aws_elb.demo_web", shape = "box"]
"[root] aws_instance.demo_web" [label = "aws_instance.demo_web", shape = "box"]
"[root] aws_internet_gateway.demo_default" [label = "aws_internet_gateway.demo_default", shape = "box"]
"[root] aws_key_pair.demo_auth" [label = "aws_key_pair.demo_auth", shape = "box"]
"[root] aws_route.demo_internet_access" [label = "aws_route.demo_internet_access", shape = "box"]
"[root] aws_security_group.demo_default" [label = "aws_security_group.demo_default", shape = "box"]
"[root] aws_security_group.demo_elb" [label = "aws_security_group.demo_elb", shape = "box"]
"[root] aws_subnet.demo_default" [label = "aws_subnet.demo_default", shape = "box"]
"[root] aws_vpc.demo_default" [label = "aws_vpc.demo_default", shape = "box"]
"[root] provider.aws" [label = "provider.aws", shape = "diamond"]
"[root] aws_elb.demo_web" -> "[root] aws_instance.demo_web"
"[root] aws_elb.demo_web" -> "[root] aws_security_group.demo_elb"
"[root] aws_elb.demo_web" -> "[root] aws_subnet.demo_default"
"[root] aws_elb.demo_web" -> "[root] provider.aws"
"[root] aws_instance.demo_web" -> "[root] aws_key_pair.demo_auth"
"[root] aws_instance.demo_web" -> "[root] aws_security_group.demo_default"
"[root] aws_instance.demo_web" -> "[root] aws_subnet.demo_default"
"[root] aws_instance.demo_web" -> "[root] provider.aws"
"[root] aws_internet_gateway.demo_default" -> "[root] aws_vpc.demo_default"
"[root] aws_internet_gateway.demo_default" -> "[root] provider.aws"
"[root] aws_key_pair.demo_auth" -> "[root] provider.aws"
"[root] aws_route.demo_internet_access" -> "[root] aws_internet_gateway.demo_default"
"[root] aws_route.demo_internet_access" -> "[root] aws_vpc.demo_default"
"[root] aws_route.demo_internet_access" -> "[root] provider.aws"
"[root] aws_security_group.demo_default" -> "[root] aws_vpc.demo_default"
"[root] aws_security_group.demo_default" -> "[root] provider.aws"
"[root] aws_security_group.demo_elb" -> "[root] aws_vpc.demo_default"
"[root] aws_security_group.demo_elb" -> "[root] provider.aws"
"[root] aws_subnet.demo_default" -> "[root] aws_vpc.demo_default"
"[root] aws_subnet.demo_default" -> "[root] provider.aws"
"[root] aws_vpc.demo_default" -> "[root] provider.aws"
}
Demo


Demo

Terraform
By Damien Goldenberg
Terraform
- 945