Aprenda a criar módulos com Terraform na prática

Aprenda a criar módulos com Terraform na prática

Este seria o último capítulo da nossa série de postagens sobre Terraform, mas se podemos também falar sobre versionamento de infraestrutura, acho que vale a pena no aprofundarmos em mais alguns posts, certo? Então não marque bobeira e siga a 4Linux para acompanhar de perto nossos próximos posts.

Dando sequência então a nossa série, neste post iremos falar sobre módulos e como criá-los.

Caso tenha perdido o início da nossa série, recomendo fortemente visitá-los e depois retornar aqui:

#parte1

#parte2

#parte3

Toda vez que você roda o comando terraform plan ou terraform apply, este diretório é basicamente um módulo. Módulos, podem chamar outros módulos e podem se conectar juntos quando necessário.

Módulos devem ser genéricos o suficiente para suportar parâmetros e uma das melhoras formas de aprender como utilizar eles é com módulos públicos, mas que não serão abordados aqui neste post.

Módulos públicos podem ser encontrados neste link e lá podem ser encontrados diversos módulos para diferentes Providers, como Google Cloud, AWS, Digital Ocean entre outros, portanto fica a dica: “antes de sair construindo módulos para o seu problema, procure primeiro no repositório público, pois certamente alguém deve ter passado pelo mesmo problema que você”.

Como estamos aprendendo alguns aspectos super básicos de Terraform, precisamos saber como construir um módulo e começarmos a evitar o control + c + v em nossos códigos.

Primeiramente iremos criar um módulo para lidar com instâncias na plataforma do Google, porém, caso ainda tenha alguma infraestrutura rodando dos capítulos anteriores, faça a deleção primeiro.

Destrua toda sua infraestrutura com o comando:

$ terraform destroy -auto-approve

Agora crie um diretório chamado gcp-instances e dentro deste diretório iremos criar nosso primeiro módulo:

Crie um arquivo chamado de main.tf com o seguinte conteúdo:

resource "google_compute_instance" "this" {
  name         = var.name
  machine_type = var.machine_type
  zone         = var.zone

  boot_disk {
    initialize_params {
      image = var.image
    }
  }

  network_interface {
    network = "default"
  }
}

Este arquivo basicamente é o mesmo conteúdo que estávamos utilizando nos capítulos anteriores, porém estamos acrescentando variáveis (var.name, por exemplo) que serão passadas (caso exista um valor default, este valor não é obrigatório) quando o usuário consumir seu módulo.

Crie um arquivo chamado de variables.tf com o seguinte conteúdo:

variable "name" {
  description = "Nome da instância"
  type        = string
}

variable "machine_type" {
  description = "Tamanho da instância"
  type        = string
  default     = "f1-micro"
}

variable "zone" {
  description = "Em qual zona sua instância irá ficar"
  type        = string
  default     = "us-central1-a"
}

variable "image" {
  description = "Qual Sistema deseja utilizar"
  type        = string
  default     = "debian-cloud/debian-9"
}

O código acima é um bloco de declaração para variáveis e é basicamente composto de 3 atributos.

  1. Description: Descrição para ajudar o usuário que for consumir seu módulo do que este argumento faz.
  2. Type: o tipo da variável, pode ser bool, string, list, map, number e etc.
  3. Default: se deseja que este atributo tenha já um valor já preenchido por padrão, assim não será necessário passar qualquer valor quando o módulo for utilizado .

Acredite ou não, um módulo pode ser super simples como nosso código acima, até módulos consumindo outros módulos, portanto a necessidade é de cada projeto.

Por fim, altere seu código do arquivo instance.tf para o seguinte conteúdo:

module "instances" {
  source = "./gcp-instances"

  name = "linux-vm-1"
}

Aqui neste código vimos que o único atributo que devemos preencher com variável é a variável chamada “name”, caso deseja alterar o tamanho de sua máquina, seria possível sobrescrever o valor padrão, por exemplo:

module "instances" {
  source = "./gcp-instances" # Utilizando ./ informamos que o módulo está em nosso diretório gcp-instances criado anteriormente

  name         = "linux-vm-1"
  machine_type = "g1-small"
}

Toda vez que um módulo for adicionado ou alterado, deve-se rodar o comando terraform init para que o Terraform faça o download deste módulo e possa ser utilizado.

Rode o comando de inicialização:

$ terraform init

Preste atenção no resultado:

Initializing modules...
- instances in gcp-instances

Initializing the backend...
......
......
......
......

Repare que estamos consumindo um módulo que acabamos de criar em um diretório local. Este módulo está em nossa máquina, ou seja, somente nós conseguimos consumir ele, e por este motivo que iremos ter mais um post falando sobre versionamento.

Faça o plano de execução:

$ terraform plan

Com o seguinte resultado:

......
......
......
......
  + create

Terraform will perform the following actions:

  # module.instances.google_compute_instance.this will be created
  + resource "google_compute_instance" "this" {
      + can_ip_forward       = false
      + cpu_platform         = (known after apply)
      + deletion_protection  = false
      + guest_accelerator    = (known after apply)
      + id                   = (known after apply)
      + instance_id          = (known after apply)
      + label_fingerprint    = (known after apply)
      + machine_type         = "f1-micro"
      + metadata_fingerprint = (known after apply)
      + min_cpu_platform     = (known after apply)
......
......
......
......

Aplique sua infraestrutura:

$ terraform apply -auto-approve

Com o seguinte conteúdo:

module.instances.google_compute_instance.this: Creating...
module.instances.google_compute_instance.this: Still creating... [10s elapsed]
module.instances.google_compute_instance.this: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-vm-1]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Com este módulo criado, apenas precisamos passar o valor do campo “name” para que seja criada uma máquina no GCP, mas e se precisarmos mais de uma máquina? devemos repetir o código? a resposta é sempre a mesma… depende!

Depende 1:

Se estas máquinas forem iguais em termos de parâmetros/atributos podemos passar apenas a quantidade de máquinas que queremos utilizar com o atributo chamado “count” no código de nosso módulo e depois informar no uso do módulo a quantidade que queremos utilizar.

Altere o seu arquivo main.tf do módulo com o novo atributo:

resource "google_compute_instance" "this" {
  count        = var.amount
  name         = var.name
  machine_type = var.machine_type
  zone         = var.zone

  boot_disk {
    initialize_params {
      image = var.image
    }
  }

  network_interface {
    network = "default"
  }
}

Adicione no arquivo variables.tf apenas neste bloco de variáveis no final do seu arquivo.

variable "amount" {
  description = "Quantidade de máquinas que deseja criar"
  type        = number
  default     = 1
}

Por fim altere o código que chama o módulo:

module "instances" {
  source = "./gcp-instances"
  name = "linux-vm-1"
}

Faça o plano de execução normalmente e depois faça o apply:

$ terraform apply -auto-approve

Com o seguinte resultado:

module.instances.google_compute_instance.this[0]: Creating...
module.instances.google_compute_instance.this[0]: Still creating... [10s elapsed]
module.instances.google_compute_instance.this[0]: Creation complete after 13s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-vm-1]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Como visto anteriormente, estamos deixando um valor default para a quantidade de instâncias que queremos utilizar, caso não seja utilizada o valor 1 será adotado.

Agora vamos para o outro caso.

Depende 2:

Caso os atributos para cada grupo de instâncias sejam diferentes, você terá que duplicar a chamada do módulo passando o que difere para este grupo novo, por exemplo:

module "instances" {
  source = "./gcp-instances"
 
  amount = 2
  name   = "linux-vm-1"
}

module "group-web" {
  source = "./gcp-instances"

  amount = 3
  name   = "linux-web"
  image  = "centos-cloud/centos-8"
}

module "group-gitlab" {
  source = "./gcp-instances"

  amount = 2
  name   = "linux-gitlab"
  image  = "centos-cloud/centos-7"
}

Atenção, este código acima é apenas uma demonstração dos tipos de casos que podemos ter, o código não irá funcionar e veremos o motivo no próximo post.

Finalizamos aqui o post #4 sobre Terraform, logo mais iremos falar sobre versionamento do nosso módulo/infraestrutura, assim qualquer uma pode contribuir com melhorias e também utilizá-lo.

Até breve.

 

Líder em Treinamento e serviços de Consultoria, Suporte e Implantação para o mundo open source. Conheça nossas soluções:

CURSOSCONSULTORIA

Anterior Criando um Container do Docker (Sem o Docker!)
Próxima Guia prático: Como criar grupos e aplicar regras de política com SUDO no FreeIPA

About author

Você pode gostar também

Infraestrutura TI

Avaliando a Segurança em Ambientes Kubernetes com Kubeaudit

Essa é a segunda parte falando de segurança em ambientes Kubernetes. Caso você ainda não tenha visto a Parte 1, fique a vontade para clicar no link abaixo: No post

Infraestrutura TI

Melhore a performance do seu Elasticsearch com um eficiente Capacity Planning

E aí meus amiguinhos, hoje vamos falar um pouquinho sobre o ElasticSearch, um motor de buscas para indexar dados de maneira fácil.  A ideia aqui é discutir um pouco sobre

Desenvolvimento

Entenda o ciclo de vida dos arquivos no Git e facilite seu trabalho

Git é um versionador de código fonte fácil de usar, isso quase todos sabem, entretanto sua experiência de uso pode ser bem confusa em alguns casos. Convido-os a uma breve