terraform: cloud configuration management...2016/09/30  · example:usingstateimport $ terraform...

41
Terraform: Cloud Configuration Management Martin Schütte 30 September 2016

Upload: others

Post on 12-Jul-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Terraform:Cloud Configuration Management

Martin Schütte30 September 2016

Page 2: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Concepts

Page 3: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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

From Servers …

Martin Schütte | Terraform | code.talks 2016 2/38

Page 4: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

…to Services

Martin Schütte | Terraform | code.talks 2016 3/38

Page 5: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 4/38

Page 6: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

TERRAFORMBuild,  Combine,  and  Launch  Infrastructure

Page 7: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 6/38

Page 8: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 7/38

Page 9: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 8/38

Page 10: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 9/38

Page 11: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Core Concepts 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 | code.talks 2016 10/38

Page 12: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 11/38

Page 13: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 12/38

Page 14: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 13/38

Page 15: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 14/38

Page 16: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Terraform Process

*.tf override.tfModules

“source” terraform.tfvars

plan

state

get

plan

apply

destroy

Martin Schütte | Terraform | code.talks 2016 15/38

Page 17: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 16/38

Page 18: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 17/38

Page 19: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 18/38

Page 20: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 19/38

Page 21: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Features

Page 22: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 20/38

Page 23: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Module Example

Every Terraform directory may be used as a module.

Here I use the previous webservice example.

Martin Schütte | Terraform | code.talks 2016 21/38

Page 24: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 22/38

Page 25: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 23/38

Page 26: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 24/38

Page 27: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 25/38

Page 28: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Example: Use Remote State

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

Martin Schütte | Terraform | code.talks 2016 26/38

Page 29: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Example: Use Remote State to Chain Projects

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

bucket = ”my-iaas-config”key = ”vpc_project/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 | code.talks 2016 27/38

Page 30: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 28/38

Page 31: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 29/38

Page 32: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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 | code.talks 2016 30/38

Page 33: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Plugin Example

Simple Plugin: MySQL

Implements provider mysql with resource mysql_database.

Code at builtin/providers/mysql

Martin Schütte | Terraform | code.talks 2016 31/38

Page 34: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Usage

Page 35: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Issues

Under active development, current version 0.7.4(September 19)

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

General problems for this kind of tool

• Testing is inherently difficult• Provider coverage• Resource model mismatch, e. g. with Heroku apps• Ignorant of API rate limits, account ressource limits, etc.

Martin Schütte | Terraform | code.talks 2016 32/38

Page 36: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Reasons to Upgrate to 0.7

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

Martin Schütte | Terraform | code.talks 2016 33/38

Page 37: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Comparable Tools

Tools:

• AWS CloudFormation (with generator tools)• OpenStack Heat• Azure Resource Manager Templates

Configuration Management:

• SaltStack Salt Cloud• Ansible v2.x includes cloud modules

Libraries:

• fog, Ruby cloud abstraction library

Martin Schütte | Terraform | code.talks 2016 34/38

Page 38: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Workflow

• Use a VCS, i. e. git• Use separate user credentials, know how to revoke them• Use PGP to encrypt sensitive data, e. g. with Blackbox• 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 | code.talks 2016 35/38

Page 39: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Hashicorp Workflow

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

Martin Schütte | Terraform | code.talks 2016 36/38

Page 40: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

Links and Resources

• Terraform• hashicorp/terraform

• terraform-community-modules

• StackExchange/blackbox• newcontext/kitchen-terraform

• Terraforming – Export existing AWS resources

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

Martin Schütte | Terraform | code.talks 2016 37/38

Page 41: Terraform: Cloud Configuration Management...2016/09/30  · Example:UsingStateImport $ terraform import aws_db_instance.foo tf-20160927095319078600159ekc aws_db_instance.foo: Importing

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

[email protected]

slideshare.net/mschuett/tinyurl.com/ct16-tf

Martin Schütte | Terraform | code.talks 2016 38/38