Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Julien Vey DevOps OpenStack Contributor Works with Ansible, Docker, Go Contributed to the OpenStack Provider for Terraform @julienvey founded bywan

Slide 3

Slide 3 text

Éric Bellemon DevOps Works with Docker, Go, JavaScript Contributed to the OpenStack Provider for Terraform @haklop founded bywan

Slide 4

Slide 4 text

We live in a Cloud era

Slide 5

Slide 5 text

THE PATH OF A STARTUP

Slide 6

Slide 6 text

Day 1, let’s start an EC2 Instance

Slide 7

Slide 7 text

Day 2, let’s start more instances

Slide 8

Slide 8 text

Day 3, let’s hire more developers

Slide 9

Slide 9 text

Day 4, Hey! Google looks great, let’s start some GCE instances

Slide 10

Slide 10 text

Day 5, let’s use a Cloud DNS

Slide 11

Slide 11 text

Day 6, let’s use a Cloud Storage

Slide 12

Slide 12 text

Day 7, let’s add some OpenStack instances

Slide 13

Slide 13 text

Day 8, Docker is so cool, let’s add some Docker containers

Slide 14

Slide 14 text

this is how you get from A BASIC INFRASTRUCTURE to a COMPLEX CLOUD INFRASTRUCTURE

Slide 15

Slide 15 text

and this is NORMAL !

Slide 16

Slide 16 text

How to ? Keep Track of your inventory Manage changes in your infrastructure Control the lifecycle of your resources

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Infrastructure as code Description of desired state Knowledge sharing Version Control and Code reviews

Slide 19

Slide 19 text

Infrastructure as code Friendly config Simple file based configuration Declarative

Slide 20

Slide 20 text

resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" }

Slide 21

Slide 21 text

resource "" "web" { ami = "ami-1234" instance_type = "m1.small" }

Slide 22

Slide 22 text

resource "aws_instance" "" { ami = "ami-1234" instance_type = "m1.small" }

Slide 23

Slide 23 text

resource "aws_instance" "web" { = "" = "" }

Slide 24

Slide 24 text

Providers Combine multiple providers in a single file 12+ providers AWS, Docker, OpenStack, Google Cloud, Simple DNS…

Slide 25

Slide 25 text

resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" } resource "dnssimple_record" "web" { domain = "example.com" name = "test" type = "A" value = "${aws_instance.web.public_ip}" }

Slide 26

Slide 26 text

THE PATH OF A STARTUP WITH TERRAFORM

Slide 27

Slide 27 text

Day 1, let’s start an EC2 Instance

Slide 28

Slide 28 text

Day 1, let’s start an EC2 Instance resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" }

Slide 29

Slide 29 text

Day 2, let’s start more instances

Slide 30

Slide 30 text

Day 2, let’s start more instances resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" } resource "aws_instance" "backoffice" { ami = "ami-1234" instance_type = "m1.large" }

Slide 31

Slide 31 text

Day 3, let’s hire more developers

Slide 32

Slide 32 text

Day 3, let’s hire more developers git init git add revolutionaryApplication.tf git commit -m "Here is my amazing infrastructure" git push origin master

Slide 33

Slide 33 text

Day 3, let’s hire more developers git clone vim revolutionaryApplication.tf # add more instances git add revolutionaryApplication.tf git commit -m "More amazing instances" git push origin master

Slide 34

Slide 34 text

Day 4, Hey! Google looks great, let’s start some GCE instances

Slide 35

Slide 35 text

Day 4, Hey! Google looks great, let’s start some GCE instances resource "google_compute_instance" "default" { name = "test" machine_type = "n1-standard-1" zone = "us-central1-a" }

Slide 36

Slide 36 text

And so on…

Slide 37

Slide 37 text

UNDER THE HOOD

Slide 38

Slide 38 text

provider "aws" { access_key = "ACCESS_KEY_HERE" secret_key = "SECRET_KEY_HERE" region = "us-east-1" } Setup your provider

Slide 39

Slide 39 text

resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" } Create your infrastructure as code

Slide 40

Slide 40 text

Apply your infrastructure $ terraform apply

Slide 41

Slide 41 text

Generate a tfstate file Store the last known state of the infrastructure Apply your infrastructure $ terraform apply

Slide 42

Slide 42 text

$ terraform apply aws_instance.web: Creating… ami: "" => "ami-1234" instance_type: "" => "m1.small" aws_instance.web: Creation complete Apply complete! Resources: 1 added, 0 changed, 0 destroyed Apply your infrastructure

Slide 43

Slide 43 text

DEMO

Slide 44

Slide 44 text

State of your infrastructure $ terraform show

Slide 45

Slide 45 text

State of your infrastructure $ terraform show Read and print the tfstate file

Slide 46

Slide 46 text

State of your infrastructure $ terraform show aws_instance.web: id = i-e60900cd ami = ami-1234 availability_zone = us-east-1c instance_type = m1.small private_dns = domU-12-31-39-12-38-AB.compute-1.internal private_ip = 10.200.59.89 public_dns = ec2-54-81-21-192.compute-1.amazonaws.com public_ip = 54.81.21.192 security_groups.# = 1 security_groups.0 = default

Slide 47

Slide 47 text

DEMO

Slide 48

Slide 48 text

resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" } Update your infrastructure

Slide 49

Slide 49 text

resource "aws_instance" "web" { ami = "ami-1234" # instance_type = "m1.small" instance_type = "m1.medium" } Update your infrastructure

Slide 50

Slide 50 text

$ terraform plan Plan your update

Slide 51

Slide 51 text

$ terraform plan Plan your update Generates an execution plan

Slide 52

Slide 52 text

Refreshing Terraform state prior to plan... aws_instance.web: Refreshing state... (ID: i-464b0bec) -/+ aws_instance.web ami: "ami-e4ff5c93" => "ami-e4ff5c93" instance_type: "t2.micro" => "t2.small" (forces new resource) Plan your update $ terraform plan

Slide 53

Slide 53 text

Refreshing Terraform state prior to plan... aws_instance.web: Refreshing state... (ID: i-464b0bec) -/+ aws_instance.web ami: "ami-e4ff5c93" => "ami-e4ff5c93" instance_type: "t2.micro" => "t2.small" (forces new resource) Plan your update $ terraform plan

Slide 54

Slide 54 text

Refreshing Terraform state prior to plan... aws_instance.web: Refreshing state... (ID: i-464b0bec) -/+ aws_instance.web ami: "ami-e4ff5c93" => "ami-e4ff5c93" instance_type: "t2.micro" => "t2.small" (forces new resource) Plan your update $ terraform plan

Slide 55

Slide 55 text

Refreshing Terraform state prior to plan... aws_instance.web: Refreshing state... (ID: i-464b0bec) -/+ aws_instance.web ami: "ami-e4ff5c93" => "ami-e4ff5c93" instance_type: "t2.micro" => "t2.small" (forces new resource) Plan your update $ terraform plan

Slide 56

Slide 56 text

1. Read local tfstate tfstate

Slide 57

Slide 57 text

AWS 1. Read local tfstate 2. Compare with current status tfstate

Slide 58

Slide 58 text

AWS 1. Read local tfstate 2. Compare with current status 3. Generate an execution plan tfstate tfplan

Slide 59

Slide 59 text

Apply your update $ terraform apply Apply the execution plan Udpate the tfstate

Slide 60

Slide 60 text

aws_instance.web: Refreshing state... (ID: i-464b0bec) aws_instance.web: Destroying... aws_instance.web: Destruction complete aws_instance.web: Creating... ami: "" => "ami-e4ff5c93" instance_type: "" => "t2.small" aws_instance.web: Creation complete Apply complete! Resources: 1 added, 0 changed, 1 destroyed. Apply your update $ terraform apply

Slide 61

Slide 61 text

DEMO

Slide 62

Slide 62 text

Destroy your infrastructure $ terraform plan -destroy

Slide 63

Slide 63 text

Destroy your infrastructure $ terraform plan -destroy Generates an execution plan for the destroy command

Slide 64

Slide 64 text

Destroy your infrastructure $ terraform plan -destroy Refreshing Terraform state prior to plan... aws_instance.web: Refreshing state... (ID: i-d54e0e7f) - aws_instance.web

Slide 65

Slide 65 text

Destroy your infrastructure $ terraform destroy

Slide 66

Slide 66 text

Destroy your infrastructure $ terraform destroy Apply the destroy execution plan

Slide 67

Slide 67 text

Destroy your infrastructure $ terraform destroy aws_instance.web: Refreshing state... (ID: i-d54e0e7f) aws_instance.web: Destroying... aws_instance.web: Destruction complete Apply complete! Resources: 0 added, 0 changed, 1 destroyed.

Slide 68

Slide 68 text

DEMO

Slide 69

Slide 69 text

AND MORE…

Slide 70

Slide 70 text

Resource dependencies

Slide 71

Slide 71 text

Implicit dependencies resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.medium" }

Slide 72

Slide 72 text

Implicit dependencies resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.medium" } resource "aws_eip" "ip" { instance = "${aws_instance.web.id}" }

Slide 73

Slide 73 text

resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.medium" } resource "aws_eip" "ip" { instance = "${aws_instance.web.id}" } Implicit dependencies

Slide 74

Slide 74 text

Plan your infrastructure $ terraform plan + aws_eip.ip instance: "" => "${aws_instance.web.id}" private_ip: "" => "" public_ip: "" => "" + aws_instance.web ami: "" => "ami-1234" availability_zone: "" => "" instance_type: "" => "m1.medium" private_ip: "" => "" public_ip: "" => ""

Slide 75

Slide 75 text

Apply your infrastructure $ terraform apply aws_instance.web: Creating... ami: "" => "ami-1234" instance_type: "" => "m1.medium" aws_eip.ip: Creating... instance: "" => "i-0e737b25" Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Slide 76

Slide 76 text

Explicit dependencies

Slide 77

Slide 77 text

resource "aws_instance" "back" { ami = "ami-1234" instance_type = "m1.medium" } Explicit dependencies

Slide 78

Slide 78 text

resource "aws_instance" "back" { ami = "ami-1234" instance_type = "m1.medium" } resource "aws_instance" "database" { ami = "ami-1234" instance_type = "m1.large" } Explicit dependencies

Slide 79

Slide 79 text

resource "aws_instance" "back" { ami = "ami-1234" instance_type = "m1.medium" depends_on = ["aws_instance.database"] } resource "aws_instance" "database" { ami = "ami-1234" instance_type = "m1.large" } Explicit dependencies

Slide 80

Slide 80 text

resource "aws_instance" "back" { ami = "ami-1234" instance_type = "m1.medium" depends_on = ["aws_instance.database"] } resource "aws_instance" "database" { ami = "ami-1234" instance_type = "m1.large" } Explicit dependencies

Slide 81

Slide 81 text

$ terraform graph Terraform graph

Slide 82

Slide 82 text

$ terraform graph Terraform graph

Slide 83

Slide 83 text

DEMO

Slide 84

Slide 84 text

Variables

Slide 85

Slide 85 text

variable "access_key" {} variable "secret_key" {} variable "region" { default = "us-east-1" } Variables

Slide 86

Slide 86 text

provider "aws" { access_key = "${var.access_key}" secret_key = "${var.secret_key}" region = "${var.region}" } Variables

Slide 87

Slide 87 text

Variables $ terraform apply

Slide 88

Slide 88 text

Variables $ terraform apply -var 'access_key=foo' \ -var 'secret_key=bar'

Slide 89

Slide 89 text

Variables $ export TF_VAR_access_key=foo $ export TF_VAR_secret_key=bar

Slide 90

Slide 90 text

Variables $ vim terraform.tfvars access_key = "foo" secret_key = "bar"

Slide 91

Slide 91 text

Variables $ terraform apply -var-file terraform.tfvars

Slide 92

Slide 92 text

(DEMO)

Slide 93

Slide 93 text

Modules self-contained packages create reusable components

Slide 94

Slide 94 text

Modules module "postgresql" { source = "[email protected]:tf/postgresql.git" servers = "3" }

Slide 95

Slide 95 text

PROVISIONNERS

Slide 96

Slide 96 text

Provisioners Chef Files Local-exec Remote-exec

Slide 97

Slide 97 text

resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "local-exec" { command = "ansible-playbook -i invnt/aws.py web.yml" } } Provisionning with local-exec

Slide 98

Slide 98 text

resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "local-exec" { command = "ansible-playbook -i invnt/aws.py web.yml" } } Provisionning with local-exec

Slide 99

Slide 99 text

resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "remote-exec" { inline = ["puppet apply"] } } Provisionning with remote-exec

Slide 100

Slide 100 text

Provisionning with remote-exec resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "remote-exec" { inline = ["puppet apply"] } }

Slide 101

Slide 101 text

DEMO

Slide 102

Slide 102 text

WORKFLOWS

Slide 103

Slide 103 text

#some real work git commit

Slide 104

Slide 104 text

# tf and tfvars files resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "remote-exec" { inline = ["puppet apply"] } } .git git push #some real work git commit

Slide 105

Slide 105 text

# tf and tfvars files resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "remote-exec" { inline = ["puppet apply"] } } .git git push #some real work git commit review pull requests

Slide 106

Slide 106 text

# tf and tfvars files resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "remote-exec" { inline = ["puppet apply"] } } .git git push #some real work git commit git hook review pull requests

Slide 107

Slide 107 text

# tf and tfvars files resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "remote-exec" { inline = ["puppet apply"] } } .git git push #some real work git commit git hook review pull requests # tfstate files "resources": { "aws_instance.web": { "type": "aws_instance", "primary": { "id": "i-17e1a6bd", "attributes": { "ami": "ami-e4ff5c93", "instance_type": "t2.small", } } } } .git git pull

Slide 108

Slide 108 text

# tf and tfvars files resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "remote-exec" { inline = ["puppet apply"] } } .git git push #some real work git commit git hook review pull requests # tfstate files "resources": { "aws_instance.web": { "type": "aws_instance", "primary": { "id": "i-17e1a6bd", "attributes": { "ami": "ami-e4ff5c93", "instance_type": "t2.small", } } } } .git terraform apply git pull

Slide 109

Slide 109 text

# tf and tfvars files resource "aws_instance" "web" { ami = "ami-1234" instance_type = "m1.small" provisioner "remote-exec" { inline = ["puppet apply"] } } .git git push #some real work git commit git hook review pull requests # tfstate files "resources": { "aws_instance.web": { "type": "aws_instance", "primary": { "id": "i-17e1a6bd", "attributes": { "ami": "ami-e4ff5c93", "instance_type": "t2.small", } } } } .git terraform apply git commit *.tfsate git push git pull

Slide 110

Slide 110 text

CONCLUSION

Slide 111

Slide 111 text

+ terraform Provider Agnostic Cloud resources as code Everything command line

Slide 112

Slide 112 text

- terraform Providers maturity Updating infrastructure Backward compatibility Error messages

Slide 113

Slide 113 text

THANK YOU QUESTIONS ?