Como versionar sua infraestrutura com Terraform e GitLab
Deixando um pouco o assunto sobre Corona Vírus de lado, chegamos ao penúltimo post da nossa série de postagens sobre Terraform. Aqui iremos falar sobre como versionar sua infraestrutura utilizando Git no GitLab.
Caso tenha perdido os 4 primeiros posts desta série, recomendo lê-los e depois retornar aqui ou ainda poderia aproveitar o período de quarentena para revisá-los, não ? Os posts podem ser consultados através de seus respectivos links:
#parte1 #parte2 #parte3 #parte4
Caso todo o assunto já esteja na ponta da língua (ou dos dedos hehe) … mãos à obra!
Hands-On
Primeira coisa que devemos fazer é destruir toda sua infraestrutura (caso ainda não tenha feito) com o comando:
$ terraform destroy -auto-approve
Quando criamos software, temos várias pessoas trabalhando neste desenvolvimento e para que todos consigam enviar seu código para o repositório, onde fica a versão estável do projeto, precisamos realizar o processo de Continuous Integration – CI (ou no Português, Integração Contínua) toda vez que enviamos um novo código ao nosso repositório.
Para todo o desenvolvimento de código existe um fluxo, porém este fluxo pode variar dependendo da empresa/pessoa/projeto, mas é basicamente temos:
- Desenvolvimento de código local.
- Build do código enviado para o repositório.
- Testes são realizados.
- Em caso de falha, o desenvolvedor ficará sabendo do problema para resolver os problemas.
- Em caso de sucesso, o código é mesclado com o branch principal para todos terem acesso ao código mais recente.
Não iremos abordar instalação de Git em sua máquina ou criar uma conta no GitLab, ambos os processos são simples e certamente você saberá fazer o processo.
Porém, caso este seja seu primeiro contato com Git e repositórios, vamos detalhar algumas coisas.
Criando um repositório no GitLab
Preencha os campos conforme exemplo abaixo. Sempre coloque nomes que representem o propósito do projeto.
Para os exemplos foi criado um repositório chamado gcp-instances.
Ao criar o projeto, aparecerá uma nova tela com alguns passos que devemos configurar para Git. Todos os passos também serão realizados via linha de comando.
Neste podemos configurar de duas maneiras distintas, clonando o repositório vazio ou criando estrutura diretamente na sua máquina, mas iremos prosseguir apenas clonando o repositório vazio.
Faça o clone do seu repositório.
$ git clone git@gitlab.com:rd-public/blog-tf-modules/4linux/gcp-instances.git
Você receberá uma mensagem parecida com esta abaixo:
Cloning into 'gcp-instances'... warning: You appear to have cloned an empty repository.
Para enviarmos nosso código fonte para este projeto precisaremos configurar nossa chave SSH.
Criando chaves SSH
Chaves públicas estabelecem de forma confiável a comunicação de sua máquina com o seu repositório, o GitLab é o método mais utilizado para enviar/receber arquivos de um repositório.
Para quem já utiliza chaves públicas, é possível utilizar a mesma, ou criar outra.
O comando para criar está abaixo. Quando solicitado para inserir senhas, apenas pressione ENTER :
$ ssh-keygen -t rsa -b 4096
Para aqueles que queiram criar outra chave:
$ ssh-keygen -t rsa -b 4096 -f ${HOME}/.ssh/4linux
Para ambos os processos, a saída será similar.
Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/rafael/.ssh/4linux. Your public key has been saved in /home/rafael/.ssh/4linux.pub. The key fingerprint is: SHA256:mtABqryIABsxIw4YmnKBL55mqC2rREHIhfFRpuotTqI rafael@nazgul The key's randomart image is: +---[RSA 4096]----+ |@==ooo | |XB.o+. | |*+oo . | |==+ . . | |*=. . . S | |B=o . o | |BB . o | |O o | |E+ | +----[SHA256]-----+
Adicionando as chaves na sua conta do GitLab
Precisamos copiar o conteúdo desta chave gerada para comunicar com o GitLab. Este processo além de utilizar criptografia, nos permite realizar _commits_ sem que seja necessário a cada momento informar usuário e senha ao sistema.
Copie o conteúdo da chave pública:
$ cat ${HOME}/.ssh/4linux.pub
Vá até o GitLab e clique em [https://gitlab.com/profile](https://gitlab.com/profile) e no menu esquerdo selecione SSH Keys colando o conteúdo da chave no formulário.
Para aqueles que estão utilizando uma segunda chave: deverá ser criado um arquivo dentro do seu ${HOME} para suportar a outra chave.
Crie um arquivo chamado de config em ${HOME}/.ssh:
$ vim ${HOME}/.ssh/config
Adicione o seguinte conteúdo abaixo:
Host gitlab.com HostName gitlab.com User git IdentityFile ~/.ssh/4linux IdentitiesOnly yes
* Entre no diretório do módulo que foi criado no post anterior.
* Faça um teste criando um arquivo chamado README.md.
$ echo "Módulo para gerenciamento de instâncias para Google Cloud Platform" > README.md
Verifique o arquivo com o comando:
$ git status
Você deverá receber um resultado com o seguinte resultado:
On branch master No commits yet Untracked files: (use "git add ..." to include in what will be committed) README.md main.tf variables.tf nothing added to commit but untracked files present (use "git add" to track)
Adicione o arquivo com:
$ git add README.md
Faça o commit do arquivo:
$ git commit -m 'Envio do arquivo README.md para teste de autenticação'
Talvez aparecerá a seguinte mensagem no seu terminal. Esta mensagem irá aparecer caso você não tenha em modo global dizendo quem você é:
*** Please tell me who you are. Run git config --global user.email "you@example.com" git config --global user.name "Your Name" to set your account's default identity. Omit --global to set the identity only in this repository. fatal: unable to auto-detect email address (got 'rafael@nazgul.(none)')
Preste atenção no parâmetro –global do git, aqui é configurado para todo o seu sistema utilizar sempre os mesmos valores, porém não é aconselhado caso tenha mais de uma credencial. Este caso de ter mais de uma credencial acontece quando você faz commit com mais de uma conta de email, como por exemplo projetos pessoais e projetos da empresa no mesmo computador, fique atento!
$ git config user.name "Nome" $ git config user.email "email@dominio"
Uma vez configurado informado os valores para o seu nome e email repita o comando de commit.
$ git commit -m 'Envio do arquivo README.md para teste de autenticação'
Com o seguinte resultado:
On branch master Your branch is based on 'origin/master', but the upstream is gone. (use "git branch --unset-upstream" to fixup) nothing to commit, working tree clean
Faça o envio do arquivo:
$ git push origin master
Com o seguinte resultado:
Enumerating objects: 3, done. Counting objects: 100% (3/3), done. Writing objects: 100% (3/3), 296 bytes | 296.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) To gitlab.com:rd-public/blog-tf-modules/4linux/gcp-instances.git * [new branch] master -> master
Neste último comando, origin é o nome padrão do git para uma conexão e master é o nome do branch padrão de qualquer repositório git, porém tudo isto é configurável no seu repositório, caso seja necessário.
Verifique no GitLab o envio de seu código.
Envie agora o arquivo main.tf e variables.tf
$ git add main.tf variables.tf
Faça o commit:
$ git commit -m 'Envio de projeto'
Faça o envio para o repositório:
$ git push origin master
Com os comandos acima você irá enviar todos os arquivos para o repositório e assim ele poderá ser consumido por todos.
Agora é necessário alterar o código do capítulo anterior para consumir o novo módulo enviado.
Altere o arquivo instances.tf com o seguinte conteúdo (que foi visto inicialmente no post #4):
module "instances" { source = "git@gitlab.com:rd-public/blog-tf-modules/4linux/gcp-instances.git" amount = 2 name = "linux-vm-1" } module "group-web" { source = "git@gitlab.com:rd-public/blog-tf-modules/4linux/gcp-instances.git" amount = 3 name = "linux-web" image = "centos-cloud/centos-8" } module "group-gitlab" { source = "git@gitlab.com:rd-public/blog-tf-modules/4linux/gcp-instances.git" amount = 2 name = "linux-gitlab" image = "centos-cloud/centos-7" }
Reinicialize o Terraform:
$ terraform init
Initializing modules... Downloading git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git for group-gitlab... - group-gitlab in .terraform/modules/group-gitlab Downloading git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git for group-web... - group-web in .terraform/modules/group-web Downloading git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git for instances... - instances in .terraform/modules/instances Initializing the backend... ...... ...... ...... ......
Faça o plano de execução:
$ terraform plan
Nesta saída, vamos deixar apenas os recursos que serão criados omitindo todo o restante:
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: # module.group-gitlab.google_compute_instance.this[0] will be created ...... ...... # module.group-gitlab.google_compute_instance.this[1] will be created ...... ...... # module.group-web.google_compute_instance.this[0] will be created ...... ...... # module.group-web.google_compute_instance.this[1] will be created ...... ...... # module.group-web.google_compute_instance.this[2] will be created ...... ...... # module.instances.google_compute_instance.this[0] will be created ...... ...... ...... ...... Plan: 7 to add, 0 to change, 0 to destroy. ...... ......
Aplique a infraestrutura:
$ terraform apply -auto-approve
Com o seguinte resultado:
module.group-gitlab.google_compute_instance.this[0]: Creating... module.group-web.google_compute_instance.this[3]: Creating... module.instances.google_compute_instance.this[0]: Creating... module.group-web.google_compute_instance.this[2]: Creating... module.group-gitlab.google_compute_instance.this[1]: Creating... module.group-web.google_compute_instance.this[1]: Creating... module.instances.google_compute_instance.this[1]: Creating... module.group-web.google_compute_instance.this[0]: Creating... module.group-gitlab.google_compute_instance.this[0]: Still creating... [10s elapsed] module.instances.google_compute_instance.this[0]: Still creating... [10s elapsed] module.group-web.google_compute_instance.this[1]: Still creating... [10s elapsed] module.group-web.google_compute_instance.this[1]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-web] module.group-gitlab.google_compute_instance.this[0]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-gitlab] module.instances.google_compute_instance.this[0]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-vm-1] Error: Error creating instance: googleapi: Error 409: The resource 'projects/projeto-1-265222/zones/us-central1-a/instances/linux-gitlab' already exists, alreadyExists on .terraform/modules/group-gitlab/main.tf line 1, in resource "google_compute_instance" "this": 1: resource "google_compute_instance" "this" { ...... ...... ...... ......
Oops, temos um problema. Precisamos colocar uma forma de que o nome da máquina não se repita, por esse motivo o erro acima aconteceu, portanto devemos alterar um detalhe em nosso módulo.
Adicione no arquivo main.tf a seguinte linha no atributo name:
name = format("%s-%d", var.name, count.index)
Adicione o arquivo main.tf:
$ git add main.tf
Faça o commit:
$ git commit -m 'Correçao para suportar multiplas maquinas sem duplicar nomes'
Com o seguinte resultado:
[master e6bf395] Correçao para suportar multiplas maquinas sem duplicar nomes 1 file changed, 1 insertion(+), 1 deletion(-)
Envie a correção para o repositório:
$ git push origin master
Com o seguinte resultado:
Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Delta compression using up to 8 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 969 bytes | 969.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0) To gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git 0ac9bb5..e6bf395 master -> master
Para começar de fato a versionar um módulo de maneira apropriada, devemos criar uma tag utilizando git para fazer uma marcação no tempo.
$ git tag -a v1.0 -m 'Versão 1.0 que realiza a criação de múltiplas máquinas'
Confirme sua tag com o comando:
$ git tag
Com a saída:
v1.0
Envie a tag para o repositório:
$ git push --tags
Com o seguinte resultado:
Enumerating objects: 1, done. Counting objects: 100% (1/1), done. Writing objects: 100% (1/1), 205 bytes | 205.00 KiB/s, done. Total 1 (delta 0), reused 0 (delta 0) To gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git * [new tag] v1.0 -> v1.0
Devemos alterar nosso código que consome este módulo para utilizar a nova tag:
Altere o arquivo instances.tf
module "instances" { source = "git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git?ref=v1.0" amount = 2 name = "linux-vm-1" } module "group-web" { source = "git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git?ref=v1.0" amount = 3 name = "linux-web" image = "centos-cloud/centos-8" } module "group-gitlab" { source = "git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git?ref=v1.0" amount = 2 name = "linux-gitlab" image = "centos-cloud/centos-7" }
Verifique no final de cada chamada do módulo o argumento ?ref=v1.0. Com este argumento você irá dizer em qual versão o seu módulo está. Desta forma você está garantindo que sua infraestrutura funcionará com este módulo na versão 1.0
Reinicialize o Terraform:
$ terraform init
Verifique a saída:
Initializing modules... Downloading git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git?ref=v1.0 for group-gitlab... - group-gitlab in .terraform/modules/group-gitlab Downloading git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git?ref=v1.0 for group-web... - group-web in .terraform/modules/group-web Downloading git@gitlab.com:rd-public/4linux/blog-tf-modules/gcp-instances.git?ref=v1.0 for instances... - instances in .terraform/modules/instances Initializing the backend... ...... ...... ...... ......
Antes de executar o plan e apply, destrua a infraestrutura que foi criada anteriormente, pois mesmo retornando um erro, algumas máquinas foram criadas até o erro ser disparado.
$ terraform destroy -auto-approve
Agora faça o plano de execução e em seguida crie a infraestrutura. Vou pular aqui o plan, vou diretamente para o apply para mostrar o funcionamento do módulo.
$ terraform apply -auto-approve
Com o seguinte resultado esperado desta vez:
module.group-web.google_compute_instance.this[0]: Creating... module.instances.google_compute_instance.this[0]: Creating... module.group-gitlab.google_compute_instance.this[0]: Creating... module.group-web.google_compute_instance.this[2]: Creating... module.group-gitlab.google_compute_instance.this[1]: Creating... module.instances.google_compute_instance.this[1]: Creating... module.group-web.google_compute_instance.this[1]: Creating... module.group-web.google_compute_instance.this[0]: Still creating... [10s elapsed] module.instances.google_compute_instance.this[0]: Still creating... [10s elapsed] module.group-gitlab.google_compute_instance.this[0]: Still creating... [10s elapsed] module.group-web.google_compute_instance.this[2]: Still creating... [10s elapsed] module.group-gitlab.google_compute_instance.this[1]: Still creating... [10s elapsed] module.instances.google_compute_instance.this[1]: Still creating... [10s elapsed] module.group-web.google_compute_instance.this[1]: Still creating... [10s elapsed] module.group-web.google_compute_instance.this[2]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-web-2] module.instances.google_compute_instance.this[1]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-vm-1-1] module.group-web.google_compute_instance.this[1]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-web-1] module.instances.google_compute_instance.this[0]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-vm-1-0] module.group-gitlab.google_compute_instance.this[1]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-gitlab-1] module.group-web.google_compute_instance.this[0]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-web-0] module.group-gitlab.google_compute_instance.this[0]: Creation complete after 12s [id=projects/projeto-1-265222/zones/us-central1-a/instances/linux-gitlab-0] Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
Perfeito, módulo funcionando perfeitamente desta vez sem repetições de nomes.
Este módulo está disponível em: https://gitlab.com/rd-public/4linux/blog-tf-modules/gcp-instances
Finalizamos aqui este post sobre Terraform, espero que tenham gostado.
Para nosso próximo post, iremos criar um módulo para gerenciamento de rede, outro módulo para gerenciamento de subredes na GCP e fazer sua integração com nosso módulo de gerenciamento de instâncias.
Abraços.
Líder em Treinamento e serviços de Consultoria, Suporte e Implantação para o mundo open source. Conheça nossas soluções:
About author
Você pode gostar também
Descubra o DevSecOps: Segurança e eficiência no desenvolvimento de software
Saudações pessoal! Hoje vamos explorar o fascinante mundo do “DevSecOps”. Talvez você já tenha ouvido falar desse termo, mas não tenha ideia do que ele realmente significa. Neste artigo, vamos
Guia para atualizar o AWS Load Balancer Controller após migração do Kubernetes 1.21 para 1.22
Após atualizar o cluster do Kubernetes da versão 1.21 para a 1.22, você pode precisar atualizar o AWS Load Balancer Controller (anteriormente conhecido como ALB Ingress Controller) para garantir que
Descubra como a Cloud Computing está revolucionando o mundo da tecnologia
A famosa “Cloud Computing”, a ideia de que todos os tipos de tecnologias podem ser entregues totalmente pela Internet está crescendo cada vez mais e mudando tudo! Isso afeta nossas