Domine o Terraform: Tutorial Completo para Iniciantes

Gostaria de saber o que é Terraform? Vamos explorar!

Infraestrutura como código (IaC) é um conceito amplamente adotado por profissionais de DevOps. Refere-se ao processo de gerenciar e provisionar toda a infraestrutura de TI, tanto física quanto virtual, por meio de arquivos de configuração legíveis por máquina. Essencialmente, é uma abordagem de engenharia de software aplicada às operações, facilitando a automação completa de data centers por meio de scripts de programação.

Apesar das vantagens que a Infraestrutura como Código oferece, ela apresenta alguns desafios:

  • Curva de aprendizado em programação.
  • Dificuldade em prever o impacto de alterações.
  • Necessidade de reverter mudanças.
  • Complexidade em monitorar alterações.
  • Obstáculos na automação de recursos específicos.
  • Gerenciamento de múltiplos ambientes de infraestrutura.

Terraform surgiu como uma solução para esses desafios.

O que é Terraform?

Terraform é uma ferramenta de código aberto para Infraestrutura como Código, desenvolvida pela HashiCorp. Ele permite definir e provisionar infraestruturas completas utilizando uma linguagem declarativa de fácil compreensão. Terraform armazena a configuração da infraestrutura em nuvem como código, semelhante a ferramentas como CloudFormation, utilizada para automatizar infraestruturas AWS, porém, o Terraform se destaca por sua capacidade de operar em diversas plataformas de nuvem.

Confira alguns benefícios do uso do Terraform:

  • Realiza orquestração, indo além do simples gerenciamento de configurações.
  • Compatível com diversos provedores, como AWS, Azure, GCP, DigitalOcean e outros.
  • Proporciona infraestrutura imutável, onde as mudanças são aplicadas de forma suave.
  • Utiliza HCL (Linguagem de Configuração HashiCorp), uma linguagem intuitiva.
  • Facilmente portável para diferentes provedores.
  • Adota uma arquitetura somente cliente, dispensando gerenciamento adicional em servidores.

Conceitos Essenciais do Terraform

A seguir, os principais conceitos e terminologias utilizadas no Terraform:

  • Variáveis: Também conhecidas como variáveis de entrada, são pares chave-valor que permitem a personalização de módulos do Terraform.
  • Provider (Provedor): É um plugin que possibilita a interação com APIs de serviços, permitindo acesso aos seus recursos.
  • Módulo: Uma pasta contendo templates do Terraform, onde as configurações são definidas.
  • Estado: Informações em cache sobre a infraestrutura gerenciada pelo Terraform e suas configurações.
  • Recursos: Blocos que representam um ou mais objetos de infraestrutura, como instâncias computacionais ou redes virtuais, utilizados para configuração e gerenciamento.
  • Data Source (Fonte de Dados): Permite aos provedores retornar informações sobre objetos externos ao Terraform.
  • Valores de Saída: Valores de um módulo Terraform que podem ser utilizados por outras configurações.
  • Plano: Etapa que define o que precisa ser criado, alterado ou removido para que a infraestrutura alcance o estado desejado.
  • Aplicar: Etapa onde as alterações são aplicadas para mover a infraestrutura do estado atual para o desejado.

Ciclo de Vida do Terraform

O ciclo de vida do Terraform abrange quatro etapas: inicialização, planejamento, aplicação e destruição.

  • Inicialização (init): Configura o diretório de trabalho e seus arquivos de configuração.
  • Planejamento (plan): Elabora um plano de execução para alcançar o estado desejado da infraestrutura, com base nas alterações nos arquivos de configuração.
  • Aplicação (apply): Implementa as mudanças na infraestrutura conforme o plano definido, levando-a ao estado desejado.
  • Destruição (destroy): Remove todos os recursos de infraestrutura que se tornaram obsoletos após a fase de aplicação.

Como o Terraform Funciona?

O Terraform possui dois componentes principais:

Núcleo do Terraform

O núcleo do Terraform opera com base em duas fontes de entrada:

Primeiramente, uma configuração definida pelo usuário, que especifica os recursos a serem criados ou provisionados. Em segundo lugar, o estado, que armazena informações atualizadas sobre a configuração atual da infraestrutura. O núcleo do Terraform processa essas entradas e cria um plano de execução. Ele compara o estado atual com a configuração desejada, e identifica as ações necessárias para alcançar o resultado final, seja criação, atualização ou exclusão de recursos.

Provedores

Os provedores são o segundo componente essencial. Eles são específicos para tecnologias como plataformas de nuvem (AWS, Azure, GCP) ou outras ferramentas de infraestrutura como serviço, Kubernetes, e até mesmo softwares de autoatendimento. Essa abordagem flexível permite a criação de infraestruturas em diversos níveis, por exemplo, construindo uma infraestrutura na AWS, implementando Kubernetes sobre ela e, em seguida, criando serviços dentro do cluster.

O Terraform oferece suporte a mais de uma centena de provedores, cada um dando acesso aos seus recursos específicos. Por exemplo, o provedor da AWS possibilita o uso de instâncias EC2, usuários IAM, enquanto o provedor do Kubernetes dá acesso a serviços, deployments e namespaces.

Dessa forma, o Terraform busca auxiliar no provisionamento e configuração completa de aplicações, desde a infraestrutura até o nível de aplicação.

Vamos agora para alguns exemplos práticos.

Vamos instalar o Terraform no Ubuntu e provisionar uma infraestrutura básica.

Instalação do Terraform

Baixe o pacote do Terraform mais recente.

Acesse a página oficial de download e baixe a versão adequada para seu sistema operacional.


 [email protected]:~$ wget https://releases.hashicorp.com/terraform/0.13.0/terraform_0.13.0_linux_amd64.zip
 --2020-08-14 16:55:38--
 https://releases.hashicorp.com/terraform/0.13.0/terraform_0.13.0_linux_amd64.zip
 Resolving releases.hashicorp.com (releases.hashicorp.com)... 151.101.153.183, 2a04:4e42:24::439
 Connecting to releases.hashicorp.com (releases.hashicorp.com)|151.101.153.183|:443... connected.
 HTTP request sent, awaiting response... 200 OK
 Length: 34851622 (33M) [application/zip]
 Saving to: ‘terraform_0.13.0_linux_amd64.zip’
 
 terraform_0.13.0_linux_amd64.zip
 100%[=================================================================>] 33.24M
 90.3KB/s in 5m 28s
 
 2020-08-14 17:01:06 (104 KB/s) - ‘terraform_0.13.0_linux_amd64.zip’ saved [34851622/34851622]
 

Extraia o pacote baixado:


 [email protected]:~$ unzip terraform_0.13.0_linux_amd64.zip
 Archive:  terraform_0.13.0_linux_amd64.zip
 inflating: terraform
 

Mova o executável do Terraform para o caminho indicado abaixo. Verifique a versão do Terraform:


 [email protected]:~$ sudo mv terraform /usr/local/bin/
 [sudo] password for etechpt.com:
 [email protected]:~$ terraform -v
 Terraform v0.13.0
 

Estes são os comandos disponíveis para execução no Terraform:


 [email protected]:~$ terraform
 Usage: terraform [-version] [-help] <command> [args]
 
 The available commands for execution are listed below.
 The most common, useful commands are shown first, followed by
 less common or more advanced commands. If you're just getting
 started with Terraform, stick with the common commands. For the
 other commands, please read the help and docs before usage.
 
 Common commands:
 apply     Builds or changes infrastructure
 console   Interactive console for Terraform interpolations
 destroy   Destroy Terraform-managed infrastructure
 env       Workspace management
 fmt       Rewrites config files to canonical format
 get       Download and install modules for the configuration
 graph     Create a visual graph of Terraform resources
 import    Import existing infrastructure into Terraform
 init      Initialize a Terraform working directory
 login     Obtain and save credentials for a remote host
 logout    Remove locally-stored credentials for a remote host
 output    Read an output from a state file
 plan      Generate and show an execution plan
 providers Prints a tree of the providers used in the configuration
 refresh   Update local state file against real resources
 show      Inspect Terraform state or plan
 taint     Manually mark a resource for recreation
 untaint   Manually unmark a resource as tainted
 validate  Validates the Terraform files
 version   Prints the Terraform version
 workspace Workspace management
 
 All other commands:
 0.12upgrade Rewrites pre-0.12 module source code for v0.12
 0.13upgrade Rewrites pre-0.13 module source code for v0.13
 debug     Debug output management (experimental)
 force-unlock Manually unlock the terraform state
 push      Obsolete command for Terraform Enterprise legacy (v1)
 state     Advanced state management
 

Provisionar Instância AWS EC2 usando Terraform

Nesta demonstração, vamos iniciar uma nova instância AWS EC2 com o Terraform.

Crie um diretório de trabalho para esta demonstração:


 [email protected]:~$ mkdir terraform_demo
 

Acesse o diretório e crie um arquivo de configuração do Terraform onde definiremos o provedor e os recursos para uma instância AWS EC2:


 [email protected]:~$ cd terraform_demo/
 [email protected]:~/terraform_demo$ gedit awsec2.tf
 
 provider "aws" {
 access_key = "B5KG6Fe5GUKIATUF5UD"
 secret_key = "R4gb65y56GBF6765ejYSJA4YtaZ+T6GY7H"
 region = "us-west-2"
 }
 
 resource "aws_instance" "terraform_demo" {
 ami = "ami-0a634ae95e11c6f91"
 instance_type = "t2.micro"
 }
 

Atenção: altere as chaves de acesso e secretas para suas credenciais.

Na configuração acima, o provedor definido é a AWS, com as credenciais do usuário e região. Em seguida, os detalhes da AMI (ami-0a634ae95e11c6f91) e tipo de instância t2.micro.

Observe como a configuração é simples e fácil de ler, mesmo para quem não tem experiência em programação.

Inicialização do Terraform

Inicialize o Terraform:


 [email protected]:~/terraform_demo$ terraform init
 
 Initializing the backend...
 
 Initializing provider plugins...
 - Using previously-installed hashicorp/aws v3.2.0
 
 The following providers do not have any version constraints in configuration,
 so the latest version was installed.
 
 To prevent automatic upgrades to new major versions that may contain breaking
 changes, we recommend adding version constraints in a required_providers block
 in your configuration, with the constraint strings suggested below.
 
 * hashicorp/aws: version = "~> 3.2.0"
 
 Terraform has been successfully initialized!
 
 You may now begin working with Terraform. Try running "terraform plan" to see
 any changes that are required for your infrastructure. All Terraform commands
 should now work.
 
 If you ever set or change modules or backend configuration for Terraform,
 rerun this command to reinitialize your working directory. If you forget, other
 commands will detect it and remind you to do so if necessary.
 

Planejamento do Terraform

Em seguida, o plano: ele cria o gráfico de execução para construir e provisionar a infraestrutura:


 [email protected]:~/terraform_demo$ terraform plan
 Refreshing Terraform state in-memory prior to plan...
 The refreshed state will be used to calculate this plan, but will not be
 persisted to local or remote state storage.
 
 ------------------------------------------------------------------------
 
 An execution plan has been generated and is shown below.
 Resource actions are indicated with the following symbols:
 + create
 
 Terraform will perform the following actions:
 
 # aws_instance.terraform_demo will be created
 + resource "aws_instance" "terraform_demo" {
 + ami                       = "ami-0a634ae95e11c6f91"
 + arn                       = (known after apply)
 + associate_public_ip_address = (known after apply)
 + availability_zone         = (known after apply)
 + cpu_core_count            = (known after apply)
 + cpu_threads_per_core      = (known after apply)
 + get_password_data         = false
 + host_id                   = (known after apply)
 + id                        = (known after apply)
 + instance_state            = (known after apply)
 + instance_type             = "t2.micro"
 + ipv6_address_count        = (known after apply)
 + ipv6_addresses            = (known after apply)
 + key_name                  = (known after apply)
 + outpost_arn               = (known after apply)
 + password_data             = (known after apply)
 + placement_group           = (known after apply)
 + primary_network_interface_id = (known after apply)
 + private_dns               = (known after apply)
 + private_ip                = (known after apply)
 + public_dns                = (known after apply)
 + public_ip                 = (known after apply)
 + secondary_private_ips     = (known after apply)
 + security_groups           = (known after apply)
 + source_dest_check         = true
 + subnet_id                 = (known after apply)
 + tenancy                   = (known after apply)
 + volume_tags               = (known after apply)
 + vpc_security_group_ids   = (known after apply)
 
 + ebs_block_device {
 + delete_on_termination = (known after apply)
 + device_name           = (known after apply)
 + encrypted             = (known after apply)
 + iops                  = (known after apply)
 + kms_key_id            = (known after apply)
 + snapshot_id           = (known after apply)
 + volume_id             = (known after apply)
 + volume_size           = (known after apply)
 + volume_type           = (known after apply)
 }
 
 + ephemeral_block_device {
 + device_name = (known after apply)
 + no_device   = (known after apply)
 + virtual_name  = (known after apply)
 }
 
 + metadata_options {
 + http_endpoint           = (known after apply)
 + http_put_response_hop_limit = (known after apply)
 + http_tokens             = (known after apply)
 }
 
 + network_interface {
 + delete_on_termination = (known after apply)
 + device_index          = (known after apply)
 + network_interface_id  = (known after apply)
 }
 
 + root_block_device {
 + delete_on_termination = (known after apply)
 + device_name           = (known after apply)
 + encrypted             = (known after apply)
 + iops                  = (known after apply)
 + kms_key_id            = (known after apply)
 + volume_id             = (known after apply)
 + volume_size           = (known after apply)
 + volume_type           = (known after apply)
 }
 }
 
 Plan: 1 to add, 0 to change, 0 to destroy.
 
 ------------------------------------------------------------------------
 
 Note: You didn't specify an "-out" parameter to save this plan, so Terraform
 can't guarantee that exactly these actions will be performed if
 "terraform apply" is subsequently run.
 

Aplicação do Terraform

A etapa de aplicação executa a configuração e inicia uma instância AWS EC2. Ao executar, o comando perguntará se você deseja realizar as ações, digite “sim” e pressione enter:


 [email protected]:~/terraform_demo$ terraform apply
 
 An execution plan has been generated and is shown below.
 Resource actions are indicated with the following symbols:
 + create
 
 Terraform will perform the following actions:
 
 # aws_instance.terraform_demo will be created
 + resource "aws_instance" "terraform_demo" {
 + ami                       = "ami-0a634ae95e11c6f91"
 + arn                       = (known after apply)
 + associate_public_ip_address = (known after apply)
 + availability_zone         = (known after apply)
 + cpu_core_count            = (known after apply)
 + cpu_threads_per_core      = (known after apply)
 + get_password_data         = false
 + host_id                   = (known after apply)
 + id                        = (known after apply)
 + instance_state            = (known after apply)
 + instance_type             = "t2.micro"
 + ipv6_address_count        = (known after apply)
 + ipv6_addresses            = (known after apply)
 + key_name                  = (known after apply)
 + outpost_arn               = (known after apply)
 + password_data             = (known after apply)
 + placement_group           = (known after apply)
 + primary_network_interface_id = (known after apply)
 + private_dns               = (known after apply)
 + private_ip                = (known after apply)
 + public_dns                = (known after apply)
 + public_ip                 = (known after apply)
 + secondary_private_ips     = (known after apply)
 + security_groups           = (known after apply)
 + source_dest_check         = true
 + subnet_id                 = (known after apply)
 + tenancy                   = (known after apply)
 + volume_tags               = (known after apply)
 + vpc_security_group_ids   = (known after apply)
 
 + ebs_block_device {
 + delete_on_termination = (known after apply)
 + device_name           = (known after apply)
 + encrypted             = (known after apply)
 + iops                  = (known after apply)
 + kms_key_id            = (known after apply)
 + snapshot_id           = (known after apply)
 + volume_id             = (known after apply)
 + volume_size           = (known after apply)
 + volume_type           = (known after apply)
 }
 
 + ephemeral_block_device {
 + device_name = (known after apply)
 + no_device   = (known after apply)
 + virtual_name  = (known after apply)
 }
 
 + metadata_options {
 + http_endpoint           = (known after apply)
 + http_put_response_hop_limit = (known after apply)
 + http_tokens             = (known after apply)
 }
 
 + network_interface {
 + delete_on_termination = (known after apply)
 + device_index          = (known after apply)
 + network_interface_id  = (known after apply)
 }
 
 + root_block_device {
 + delete_on_termination = (known after apply)
 + device_name           = (known after apply)
 + encrypted             = (known after apply)
 + iops                  = (known after apply)
 + kms_key_id            = (known after apply)
 + volume_id             = (known after apply)
 + volume_size           = (known after apply)
 + volume_type           = (known after apply)
 }
 }
 
 Plan: 1 to add, 0 to change, 0 to destroy.
 
 Do you want to perform these actions?
 Terraform will perform the actions described above.
 Only 'yes' will be accepted to approve.
 
 Enter a value: yes
 
 aws_instance.terraform_demo: Creating...
 aws_instance.terraform_demo: Still creating... [10s elapsed]
 aws_instance.terraform_demo: Still creating... [20s elapsed]
 aws_instance.terraform_demo: Still creating... [30s elapsed]
 aws_instance.terraform_demo: Still creating... [40s elapsed]
 aws_instance.terraform_demo: Creation complete after 44s [id=i-0eec33286ea4b0740]
 
 Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
 

Acesse o painel do AWS EC2 e observe a nova instância criada, com o ID de instância exibido no final do comando apply.

Parabéns! Você executou uma instância AWS EC2 com sucesso usando o Terraform.

Destruição com Terraform

Por fim, para remover a infraestrutura, use o comando destroy:


 [email protected]:~/terraform_demo$ terraform destroy
 aws_instance.terraform_demo: Refreshing state... [id=i-0eec33286ea4b0740]
 
 An execution plan has been generated and is shown below.
 Resource actions are indicated with the following symbols:
 - destroy
 
 Terraform will perform the following actions:
 
 # aws_instance.terraform_demo will be destroyed
 - resource "aws_instance" "terraform_demo" {
 - ami                       = "ami-0a634ae95e11c6f91" -> null
 - arn                       = "arn:aws:ec2:us-west-2:259212389929:instance/i-0eec33286ea4b0740" -> null
 - associate_public_ip_address = true -> null
 - availability_zone         = "us-west-2c" -> null
 - cpu_core_count            = 1 -> null
 - cpu_threads_per_core      = 1 -> null
 - disable_api_termination  = false -> null
 - ebs_optimized           = false -> null
 - get_password_data         = false -> null
 - hibernation             = false -> null
 - id                        = "i-0eec33286ea4b0740" -> null
 - instance_state            = "running" -> null
 - instance_type             = "t2.micro" -> null
 - ipv6_address_count        = 0 -> null
 - ipv6_addresses            = [] -> null
 - monitoring               = false -> null
 - primary_network_interface_id = "eni-02a46f2802fd15634" -> null
 - private_dns               = "ip-172-31-13-160.us-west-2.compute.internal" -> null
 - private_ip                = "172.31.13.160" -> null
 - public_dns                = "ec2-34-221-77-94.us-west-2.compute.amazonaws.com" -> null
 - public_ip                 = "34.221.77.94" -> null
 - secondary_private_ips     = [] -> null
 - security_groups           = [
 - "default",
 ] -> null
 - source_dest_check         = true -> null
 - subnet_id                 = "subnet-5551200c" -> null
 - tags                     = {} -> null
 - tenancy                   = "default" -> null
 - volume_tags               = {} -> null
 - vpc_security_group_ids   = [
 - "sg-b5b480d1",
 ] -> null
 
 - credit_specification {
 - cpu_credits = "standard" -> null
 }
 
 - metadata_options {
 - http_endpoint           = "enabled" -> null
 - http_put_response_hop_limit = 1 -> null
 - http_tokens             = "optional" -> null
 }
 
 - root_block_device {
 - delete_on_termination = true -> null
 - device_name           = "/dev/sda1" -> null
 - encrypted             = false -> null
 - iops                  = 100 -> null
 - volume_id             = "vol-0be2673afff6b1a86" -> null
 - volume_size           = 8 -> null
 - volume_type           = "gp2" -> null
 }
 }
 
 Plan: 0 to add, 0 to change, 1 to destroy.
 
 Do you really want to destroy all resources?
 Terraform will destroy all your managed infrastructure, as shown above.
 There is no undo. Only 'yes' will be accepted to confirm.
 
 Enter a value: yes
 
 aws_instance.terraform_demo: Destroying... [id=i-0eec33286ea4b0740]
 aws_instance.terraform_demo: Still destroying... [id=i-0eec33286ea4b0740, 10s elapsed]
 aws_instance.terraform_demo: Still destroying... [id=i-0eec33286ea4b0740, 20s elapsed]
 aws_instance.terraform_demo: Still destroying... [id=i-0eec33286ea4b0740, 30s elapsed]
 aws_instance.terraform_demo: Destruction complete after 34s
 
 Destroy complete! Resources: 1 destroyed.
 

Verificando o painel do EC2, a instância estará encerrada.

Conclusão

Espero que esta explicação tenha lhe dado uma base sólida para começar a usar o Terraform. Recomendo que você tente reproduzir o exemplo apresentado.

Considere também explorar outras ferramentas de automação de infraestrutura.

Para aprofundar seus conhecimentos, sugiro o Curso Aprendendo DevOps com Terraform.