Terraform: Cloud Configuration Management (WTC/IPC'16)

Post on 26-Jan-2017

132 views 4 download

Transcript of Terraform: Cloud Configuration Management (WTC/IPC'16)

Terraform:Cloud Configuration Management

Martin Schütte26 October 2016

Concepts

by Rodzilla at Wikimedia Commons (CC-BY-SA-3.0)

From Servers …

Martin Schütte | Terraform | WTC 2016 2/42

…to Services

Martin Schütte | Terraform | WTC 2016 3/42

Services also need Configuration Management

• Replace “click paths” with source code in VCS• Lifecycle awareness, not just a setup.sh• Reproducible environments• Specification, documentation, policy enforcement

⇒ Infrastructure as Code

Martin Schütte | Terraform | WTC 2016 4/42

TERRAFORMBuild,  Combine,  and  Launch  Infrastructure

Example: Simple Webservice (part 1)

### AWS Setupprovider ”aws” {profile = ”${var.aws_profile}”region = ”${var.aws_region}”

}

# Queueresource ”aws_sqs_queue” ”importqueue” {name = ”${var.app_name}-${var.aws_region}-importqueue”

}

# Storageresource ”aws_s3_bucket” ”importdisk” {bucket = ”${var.app_name}-${var.aws_region}-importdisk”acl = ”private”

}

Martin Schütte | Terraform | WTC 2016 6/42

Example: Simple Webservice (part 2)

### Heroku Setupprovider ”heroku” { ... }

# Importerresource ”heroku_app” ”importer” {name = ”${var.app_name}-${var.aws_region}-import”region = ”eu”config_vars {

SQS_QUEUE_URL = ”${aws_sqs_queue.importqueue.id}”S3_BUCKET = ”${aws_s3_bucket.importdisk.id}”

}}

resource ”heroku_addon” ”mongolab” {app = ”${heroku_app.importer.name}”plan = ”mongolab:sandbox”

}

Martin Schütte | Terraform | WTC 2016 7/42

Core Ideas in Terraform

• Simple model of resource entities with attributes• Stateful lifecycle with CRUD operations• Declarative configuration• Dependencies by inference• Parallel execution

Martin Schütte | Terraform | WTC 2016 8/42

Core Concepts in Terraform

• Provider: a source of resources(usually with an API endpoint & authentication)

• Resource: every thing “that has a set of configurableattributes and a lifecycle (create, read, update, delete)” –implies ID and state

• Data Source: information read from provider(e. g. lookup own account ID or AMI-ID)

• Provisioner: initialize a resource with local orremote scripts

Martin Schütte | Terraform | WTC 2016 9/42

Design Choices in Terraform

• Order: directed acyclic graph of all resources• Plan: generate an execution plan for reviewbefore applying a configuration

• State: execution result is kept in state file(local or remote)

• Lightweight: little provider knowledge, no error handling

Martin Schütte | Terraform | WTC 2016 10/42

Available services

Providers:• AWS• Azure• Google Cloud• Heroku• DNSMadeEasy• OpenStack• Docker• …

Resources:• aws_instance• aws_vpc• aws_elb• aws_iam_user• azure_instance• heroku_app• …

Provisioners:• chef• file• local-exec• remote-exec

Martin Schütte | Terraform | WTC 2016 11/42

DSL Syntax

• Hashicorp Configuration Language (HCL),think “JSON-like but human-friendly”

• Variables• Interpolation, e. g.”number ${count.index + 1}”

• Attribute access with resource_type.resource_name• Few build-in functions, e. g.base64encode(string), format(format, args…)

Martin Schütte | Terraform | WTC 2016 12/42

HCL vs. JSON

# An AMIvariable ”ami” {description = ”custom AMI”

}

/* A multiline comment. */

resource ”aws_instance” ”web” {ami = ”${var.ami}”count = 2source_dest_check = false

connection {user = ”root”

}}

{”variable”: {

”ami”: {”description”: ”custom AMI”

}},”resource”: {

”aws_instance”: {”web”: {

”ami”: ”${var.ami}”,”count”: 2,”source_dest_check”: false,

”connection”: {”user”: ”root”

}}

}}

}Martin Schütte | Terraform | WTC 2016 13/42

terraform graph | dot -Tpdf

aws_s3_bucket.importdisk

provider.aws

aws_sqs_queue.importqueue

heroku_addon.mongolab

heroku_app.importer

provider.heroku

Martin Schütte | Terraform | WTC 2016 14/42

Terraform Process

*.tf override.tfModules

“source” terraform.tfvars

plan

state

get

plan

apply

destroy

Martin Schütte | Terraform | WTC 2016 15/42

Example: Add Provisioning

# Importerresource ”heroku_app” ”importer” {name = ”${var.app_name}-${var.aws_region}-import”region = ”eu”

config_vars { ... }

provisioner ”local-exec” {command = <<EOT

cd ~/projects/go-testserver &&git remote add heroku ${heroku_app.importer.git_url} &&git push heroku masterEOT}

}

Martin Schütte | Terraform | WTC 2016 16/42

Example: Add Outputs

# Storageresource ”aws_s3_bucket” ”importdisk” { ... }

# Importerresource ”heroku_app” ”importer” { ... }

# Outputsoutput ”importer_bucket_arn” {value = ”${aws_s3_bucket.importdisk.arn}”

}

output ”importer_url” {value = ”${heroku_app.importer.web_url}”

}

output ”importer_gitrepo” {value = ”${heroku_app.importer.git_url}”

}

Martin Schütte | Terraform | WTC 2016 17/42

Example: Add Lifecycle Meta-Parameter

# Storageresource ”aws_s3_bucket” ”importdisk” {bucket = ”${var.app_name}-${var.aws_region}-importdisk”acl = ”private”

lifecycle {prevent_destroy = true

}}

Martin Schütte | Terraform | WTC 2016 18/42

Demo

$ terraform validate$ terraform plan -out=my.plan$ terraform show my.plan$ terraform apply my.plan

$ terraform output$ terraform output -json$ terraform output importer_url$ curl -s $(terraform output importer_url)

$ terraform plan -destroy$ terraform destroy

Martin Schütte | Terraform | WTC 2016 19/42

Features

Modules

“Plain terraform code” lacks structure and reusability

Modules

• are subdirectories with self-contained terraform code• may be sourced from Git, Mercurial, HTTPS locations• use variables and outputs to pass data

Martin Schütte | Terraform | WTC 2016 20/42

Module Example

Every Terraform directory may be used as a module.

Here I use the previous webservice example.

Martin Schütte | Terraform | WTC 2016 21/42

Using a Module Example (part 1)

module ”importer_west” {source = ”../simple”aws_region = ”eu-west-1”

app_name = ”${var.app_name}”aws_profile = ”${var.aws_profile}”heroku_login_email = ”${var.heroku_login_email}”heroku_login_api_key = ”${var.heroku_login_api_key}”

}

module ”importer_central” {source = ”../simple”aws_region = ”eu-central-1”

# ...}

Martin Schütte | Terraform | WTC 2016 22/42

Using a Module Example (part 2)

# Main App, using modulesresource ”heroku_app” ”main” {name = ”${var.app_name}-main”region = ”eu”

config_vars {IMPORTER_URL_LIST = <<EOT

[ ”${module.importer_west.importer_url}”,”${module.importer_central.importer_url}” ]

EOT}

}

output ”main_url” {value = ”${heroku_app.main.web_url}”

}

Martin Schütte | Terraform | WTC 2016 23/42

terraform.tfstate

• Terraform keeps known state of resources• Defaults to local state in terraform.tfstate• Optional remote state with different backends(S3, Consul, Atlas, …)• Useful to sync multiple team members• Needs additional mutex mechanism• Remote state is a data source

Martin Schütte | Terraform | WTC 2016 24/42

Example: Using State Import

$ terraform import aws_db_instance.foo tf-20160927095319078600159ekcaws_db_instance.foo: Importing from ID ”tf-20160927095319078600159ekc”...aws_db_instance.foo: Import complete!Imported aws_db_instance (ID: tf-20160927095319078600159ekc)

aws_db_instance.foo: Refreshing state... (ID: tf-20160927095319078600159ekc)

Import success! The resources imported are shown above. These arenow in your Terraform state. Import does not currently generateconfiguration, so you must do this next. If you do not create configurationfor the above resources, then the next ‘terraform plan‘ will markthem for destruction.

$ terraform state listaws_db_instance.foo

$ terraform state show aws_db_instance.fooid = tf-20160927095319078600159ekcaddress = tf-20160927095319078600159ekc.cdtlwiwa6l8t.eu-central-......

Martin Schütte | Terraform | WTC 2016 25/42

Example: Use Remote State

$ terraform remote config -backend=s3 \-backend-config=”bucket=my-iaas-config” \-backend-config=”key=${env}_vpc/terraform.tfstate” \-backend-config=”region=eu-central-1”

Martin Schütte | Terraform | WTC 2016 26/42

Example: Use Remote State to Chain Projects

data ”terraform_remote_state” ”vpc” {backend = ”s3”config {

bucket = ”my-iaas-config”key = ”${var.env}_vpc/terraform.tfstate”region = ”eu-central-1”

}}

resource ”aws_instance” ”foo” {# use state from vpc_projectsubnet_id = ”${data.terraform_remote_state.vpc.subnet_id}”

}

Martin Schütte | Terraform | WTC 2016 27/42

Data Sources

• Lookup information from Provider• New feature in 0.7• Eliminate glue code likepacker | tee | grep &&terraform apply -var ”ami=$ami”

Martin Schütte | Terraform | WTC 2016 28/42

Example: Using Data Source

# searches for most recent tagged AMI in own accountdata ”aws_ami” ”webami” {most_recent = trueowners = [”self”]

filter {name = ”tag:my_key”values = [”my_value”]

}}

# use AMIresource ”aws_instance” ”web” {instance_type = ”t2.micro”ami = ”${data.aws_ami.webami.id}”

}

Martin Schütte | Terraform | WTC 2016 29/42

How to Write Own Plugins

• Learn you some Golang• Use the schema helper lib• Adapt to model ofProvider (setup steps, authentication) andResources (arguments/attributes and CRUD methods)

Martin Schütte | Terraform | WTC 2016 30/42

Plugin Example

Simple Plugin: MySQL

Implements provider mysql with resource mysql_database.

Code at builtin/providers/mysql

Martin Schütte | Terraform | WTC 2016 31/42

Usage

Issues

Under active development, current version 0.7.7 (October 18)

• Still a few bugs, e. g. losing state info is possible• Modules are very simple• Lacking syntactic sugar(e. g. aggregations, common repetitions)

Martin Schütte | Terraform | WTC 2016 32/42

General Problemes for all Tools

• Testing is inherently difficult• Provider coverage largely depends on community• Resource model mismatches, e. g. with Heroku apps, orwith multiple ways to represent AWS security groups

• Ignorant of API rate limits, account ressource limits, etc.

Martin Schütte | Terraform | WTC 2016 33/42

Reasons to Upgrate to 0.7.x

• terraform fmt (ok, actually since 0.6.15)• Internal Plugins, reduced binary size• Output flag -json• Lists and Maps may be passed to modules• State Import• Data Sources

Martin Schütte | Terraform | WTC 2016 34/42

Size of Terraform Releases (linux amd64)

v0.6.10 v0.6.13 v0.6.16 v0.7.0 v0.7.2 v0.7.40

200

400

600554 567 549

8865 66

SizeinMb

0

20

40

60

28 30

4044 45 46

ProviderCount

Martin Schütte | Terraform | WTC 2016 35/42

Comparable Tools

Configuration Management Tools:

• SaltStack Salt Cloud• Ansible modules• Puppet modules

Libraries:

• libcloud, Python cloud abstraction library• fog, Ruby cloud abstraction library

Tools:

• AWS CloudFormation• OpenStack Heat• Azure Resource Manager Templates

Martin Schütte | Terraform | WTC 2016 37/42

Workflow

• Avoid user credentials in Terraform code,use e. g. profiles and assume-role wrapper scripts

• At least use separate user credentials,know how to revoke them

• To hold credentials in VCS use PGP encryption,e. g. with Blackbox

Martin Schütte | Terraform | WTC 2016 38/42

Workflow (contd.)

• Use a VCS, i. e. git• Always add some ”${var.shortname}” to namespace• Use remote state and consider access locking,e. g. with a single build server

• Take a look at Hashicorp Atlas and its workflow

Martin Schütte | Terraform | WTC 2016 39/42

Hashicorp Workflow

image by Hashicorp Atlas: Artifact Pipeline and Image Deploys with Packer and Terraform

Martin Schütte | Terraform | WTC 2016 40/42

Links and Resources

• Terraform.io and hashicorp/terraform

• terraform-community-modules

• StackExchange/blackbox• newcontext/kitchen-terraform

• Terraforming – Export existing AWS resources

• Terraform: Beyond the Basics with AWS• A Comprehensive Guide to Terraform• Terraform, VPC, and why you want a tfstate file per env

Martin Schütte | Terraform | WTC 2016 41/42

The End

Defining system infrastructure as code andbuilding it with tools doesn’t make the quality anybetter. At worst, it can complicate things.— Infrastructure as Code by Kief Morris

Martin Schütte@m_schuett

info@martin-schuette.de

slideshare.net/mschuett/

Martin Schütte | Terraform | WTC 2016 42/42