Terraform 101

Link da apresentação deste artigo: slides

Agenda

Fundamentos de IaC

Infrastructure as Code

Infraestrutura como código (em inglês: infrastructure as code, ou IaC) é o processo de gerenciamento e provisionamento de centros de processamentos dados usando arquivos de configuração ao invés de configurações físicas de hardware ou ferramentas de configuração interativas.

Dry - Don’t repeat yourself

Quando dizemos “como código”, queremos dizer que todas as boas práticas que aprendemos no mundo do software devem ser aplicadas à infraestrutura.

Uso do controle de versão, adesão ao princípio DRY, modularização, manutenção e uso de testes e implantação automatizados são práticas fundamentais.

Casos de Uso

Terraform

Terraform é uma ferramenta open source de provisionamento de infraestrutura, criada pela HashiCorp, que permite que definamos nossa infraestrutura como código(IaC), usando uma linguagem simples e declarativa (HCL - HashiCorp Configuration Language).

O terraform é desenvolvido em GO e é OpenSource

Terraform Workflow

O Workflow do terraform consiste em basicamente 3 etapas:

IaC

A ideia por trás do terraform é ele gerenciar o estado de uma infraestrutura, ou seja, o estado de cada recurso com base na interação com o seu provider.

Interacao Api

Arquivos

Para começarmos com o Terraform, nós temos que identificar as extensões dos arquivos utilizados por por ele.

Básico do Terraform

Variables

Variáveis são parametros para um módulo de Terraform, permitem que aspectos da implementação seja customizado sem que seu codigo seja alterado.

Temos 3 tipos de uso de variáveis:

Declarando uma variável de input

variable "image_id" {
  type = string
}
variable "availability_zone_names" {
  type    = list(string)
  default = ["us-west-1a"]
}
variable "docker_ports" {
  type = list(object({
    internal = number
    external = number
    protocol = string
  }))
  default = [
    {
      internal = 8300
      external = 8300
      protocol = "tcp"
    }
  ]
}
variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."

  validation {
    condition     = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
    error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
  }
}

Precedência de carregamento

Locals

Um Local é um valor que recebe um nome a partir de uma expressão ou valor.

locals {
  # Ids for multiple sets of EC2 instances, merged together
  instance_ids = concat(aws_instance.blue.-.id, aws_instance.green.-.id)
}

locals {
  # Common tags to be assigned to all resources
  common_tags = {
    Service = local.service_name
    Owner   = local.owner
  }
}

Output

Output é uma forma de expor o valor, seja como retorno de um módulo ou imprimindo como retorno do root.

output "instance_ip_addr" {
  value = aws_instance.server.private_ip
}
output "instance_ip_addr" {
  value       = aws_instance.server.private_ip
  description = "The private IP address of the main server instance."
}
output "db_password" {
  value       = aws_db_instance.db.password
  description = "The password for logging in to the database."
  sensitive   = true
}
output "instance_ip_addr" {
  value       = aws_instance.server.private_ip
  description = "The private IP address of the main server instance."

  depends_on = [
    # Security group rule must be created before this IP address could
    # actually be used, otherwise the services will be unreachable.
    aws_security_group_rule.local_access,
  ]
}

Type Constraints

São os tipos que as variáveis podem declarados como argumentos na declaração e que podem ser customizados. Veja elas como uma Classe na programação ou uma estrutura de dados.

Simples

Complexos

Functions

Principais funções

Format

format(spec, values...)

> format("Hello, %s!", "Ander")
Hello, Ander!
> format("There are %d lights", 4)
There are 4 lights
> format("Hello, %s!", var.name)
Hello, Valentina!
> "Hello, ${var.name}!"
Hello, Valentina!
Join

join(separator, list)

> join(", ", ["foo", "bar", "baz"])
foo, bar, baz
> join(", ", ["foo"])
foo
Split

split(separator, string)

> split(",", "foo,bar,baz")
[
  "foo",
  "bar",
  "baz",
]
> split(",", "foo")
[
  "foo",
]
> split(",", "")
[
  "",
]
Upper, lower, title
> upper("hello")
HELLO
> upper("алло!")
АЛЛО!
> lower("HELLO")
hello
> lower("АЛЛО!")
алло!
> title("hello world")
Hello World
Element Index

element(list, index)

> element(["a", "b", "c"], 1)
b

index(list, value)

> index(["a", "b", "c"], "b")
1
Map
tomap({
  a = "b"
  c = "d"
})
File

file(path)

> file("${path.module}/hello.txt")
Hello World

Providers

É a estrutura resposavel por comunicar com a API da estrutura desejada.

# The default provider configuration; resources that begin with `aws_` will use
# it as the default, and it can be referenced as `aws`.
provider "aws" {
  region = "us-east-1"
}

# Additional provider configuration for west coast region; resources can
# reference this as `aws.west`.
provider "aws" {
  alias  = "west"
  region = "us-west-2"
}

Terraform Registry

O registry do terrarform é uma coleção de providers, Módulos e policies que podem ser usados em qualquer projeto. Os principais providers são:

Resources

Item mais importante do Terraform, ele informa o recurso que será criado/gerenciado.

resource "aws_instance" "web" {
  ami           = "ami-a1b2c3d4"
  instance_type = "t2.micro"
}

Data Sources

Data recupera informações de recursos já criados no ambiente sem precisar de gerenciar o mesmo. Ou seja, sem precisar de importar o recurso e gerenciar ele.

data "aws_ami" "example" {
  most_recent = true

  owners = ["self"]
  tags = {
    Name   = "app-server"
    Tested = "true"
  }
}

Módulos

É como uma abstração de um conjunto de recursos para reaproveitamento do mesmo.

module "servers" {
  source = "./app-cluster"

  servers = 5
}

Backend - TFSTATE

O backend é a estrutrua que define onde o terraform irá guardar o estado (TFSTATE) do seu ambiente.

backend "s3" {
  bucket = "terraform-state"
  key    = "terraform.tfstate"
  region = "us-east-1"
}

Algo legal de utilizarmos é que os atributos do backend podem ser definidos dinamicamente no terraform init, isso trás uma maior flexibilidade podendo ser definido em tempo de execução.

terraform init \
    -backend-config="address=demo.consul.io" \
    -backend-config="path=example_app/terraform_state" \
    -backend-config="scheme=https"

Algumas opções de backend:

Workspaces

Workspaces é uma forma de gerenciar múltiplos ambientes de forma independente. Onde você pode associar cada ambiente com um conjunto de variáveis.

Workspaces

HashiCorp Certified Terraform Associate

A certificação Terraform é uma excelente opção para comprovar seu conhecimento sobre o Terraform. Ela não vai cobrir todos os aspectos do dia-a-dia, mas vai guiar você para entender o que é Terraform e como ele funciona.

A Hashicorp está atualizando o exame Terraform Associate 002 para a 003. A recomendação é que quem tem a Terraform Associate 002, faça o upgrade para a 003 quando for lançada, e quem não tem a 002 espere até o 003 ser lançada.

Timeline dos exames Terraform

Características

Objetivos do exame

Simulados

Dicas para a prova