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