Terraformer - Infraestrutura para codificar

Terraformer - Infraestrutura para codificar
Gostaria de falar sobre a nova ferramenta CLI que escrevi para resolver um problema antigo.

problema

Terraform é há muito tempo um padrão na comunidade Devops/Cloud/TI. A coisa é muito conveniente e útil para lidar com infraestrutura como código. Existem muitas delícias no Terraform, assim como muitos garfos, facas afiadas e ancinhos.
Com o Terraform é muito conveniente criar coisas novas e depois gerenciá-las, alterá-las ou excluí-las. O que deve fazer quem tem uma enorme infraestrutura na nuvem e não criada através do Terraform? Reescrever e recriar toda a nuvem é caro e inseguro.
Encontrei esse problema em 2 trabalhos, o exemplo mais simples é quando você deseja que tudo esteja no Git na forma de arquivos terraform, mas você tem mais de 250 buckets e é muito difícil escrevê-los manualmente no terraform.
Tem emitem desde 2014 no terrafom que foi encerrado em 2016 com a esperança de que haja importação.

Em geral tudo está como na foto apenas da direita para a esquerda

Advertências: O autor não mora metade de sua vida na Rússia e escreve pouco em russo. Cuidado com erros ortográficos.

Soluções

1. Existem soluções prontas e antigas para AWS terraformação. Quando tentei passar meus mais de 250 baldes, percebi que tudo estava ruim ali. A AWS vem introduzindo muitas opções novas há muito tempo, mas o terraforming não as conhece e, em geral, é Ruby o modelo parece esparso. Depois das 2 da tarde eu enviei Puxar pedido para adicionar mais recursos lá e percebi que tal solução não é adequada.
Como funciona o terraforming: ele pega dados do AWS SDK e gera tf e tfstate por meio de um template.
Existem 3 problemas aqui:
1. Sempre haverá um atraso nas atualizações
2. Arquivos tf às vezes saem quebrados
3. tfstate é coletado separadamente de tf e nem sempre converge
Em geral, é difícil obter um resultado em que o `terraform plan` diga que não há alterações

2. `terraform import` é um comando integrado no terraform. Como funciona?
Você escreve um arquivo TF vazio com o nome e tipo de recurso, então executa `terraform import` e passa o ID do recurso. O terraform entra em contato com o provedor, recebe os dados e cria um arquivo tfstate.
Existem 3 problemas aqui:
1. Obtemos apenas um arquivo tfstate, e o tf está vazio, você precisa escrevê-lo manualmente ou convertê-lo de tfstate
2. Só pode trabalhar com um recurso por vez e não oferece suporte a todos os recursos. E o que devo fazer novamente com mais de 250 baldes?
3. Você precisa saber o ID dos recursos - ou seja, você precisa envolvê-lo em um código que obtenha a lista de recursos
Em geral, o resultado é parcial e não é bem dimensionado

Minha decisão

Requisitos:
1. Capacidade de criar arquivos tf e tfstate para recursos. Por exemplo, baixe todos os buckets/grupo de segurança/balanceador de carga e aquele `terraform plan` retornou que não há alterações
2. Você precisa de 2 nuvens GCP + AWS
3. Solução global que é fácil de atualizar sempre e não perde tempo em cada recurso durante 3 dias de trabalho
4. Torne-o Open Source – todos têm o mesmo problema

A linguagem Go é o motivo pelo qual eu adoro ela, e ela possui uma biblioteca para criação de arquivos HCL que é usada no terraform + muito código no terraform que pode ser útil

Caminho

Primeira tentativa
Comecei com uma versão simples. Entrar em contato com a nuvem por meio do SDK para obter o recurso necessário e convertê-lo em campos para terraform. A tentativa morreu imediatamente no grupo de segurança porque não gostei dos 1.5 dias para converter apenas o grupo de segurança (e há muitos recursos). Por muito tempo e depois os campos podem ser alterados/adicionados

Segunda tentativa
Com base na ideia descrita aqui. Basta pegar e converter tfstate em tf. Todos os dados estão lá e os campos são os mesmos. Como obter o tfstate completo para muitos recursos? Foi aqui que o comando `terraform update` veio em socorro. O terraform pega todos os recursos do tfstate e, por ID, extrai dados deles e grava tudo no tfstate. Ou seja, crie um tfstate vazio apenas com nomes e IDs, execute `terraform update` e então obteremos tfstates completos. Viva!
Agora vamos fazer a pornografia recursiva de escrever um conversor de tfstate para tf. Para quem nunca leu tfstate, é JSON, mas especial.
Aqui estão seus atributos importantes

 "attributes": {
                            "id": "default/backend-logging-load-deployment",
                            "metadata.#": "1",
                            "metadata.0.annotations.%": "0",
                            "metadata.0.generate_name": "",
                            "metadata.0.generation": "24",
                            "metadata.0.labels.%": "1",
                            "metadata.0.labels.app": "backend-logging",
                            "metadata.0.name": "backend-logging-load-deployment",
                            "metadata.0.namespace": "default",
                            "metadata.0.resource_version": "109317427",
                            "metadata.0.self_link": "/apis/apps/v1/namespaces/default/deployments/backend-logging-load-deployment",
                            "metadata.0.uid": "300ecda1-4138-11e9-9d5d-42010a8400b5",
                            "spec.#": "1",
                            "spec.0.min_ready_seconds": "0",
                            "spec.0.paused": "false",
                            "spec.0.progress_deadline_seconds": "600",
                            "spec.0.replicas": "1",
                            "spec.0.revision_history_limit": "10",
                            "spec.0.selector.#": "1",

Há:
1. id - string
2. metadados - uma matriz de tamanho 1 e nela um objeto com campos descritos abaixo
3. especificação - hash de tamanho 1 e chave, valor nele
Resumindo, um formato divertido, tudo pode ter vários níveis de profundidade

                   "spec.#": "1",
                            "spec.0.min_ready_seconds": "0",
                            "spec.0.paused": "false",
                            "spec.0.progress_deadline_seconds": "600",
                            "spec.0.replicas": "1",
                            "spec.0.revision_history_limit": "10",
                            "spec.0.selector.#": "1",
                            "spec.0.selector.0.match_expressions.#": "0",
                            "spec.0.selector.0.match_labels.%": "1",
                            "spec.0.selector.0.match_labels.app": "backend-logging-load",
                            "spec.0.strategy.#": "0",
                            "spec.0.template.#": "1",
                            "spec.0.template.0.metadata.#": "1",
                            "spec.0.template.0.metadata.0.annotations.%": "0",
                            "spec.0.template.0.metadata.0.generate_name": "",
                            "spec.0.template.0.metadata.0.generation": "0",
                            "spec.0.template.0.metadata.0.labels.%": "1",
                            "spec.0.template.0.metadata.0.labels.app": "backend-logging-load",
                            "spec.0.template.0.metadata.0.name": "",
                            "spec.0.template.0.metadata.0.namespace": "",
                            "spec.0.template.0.metadata.0.resource_version": "",
                            "spec.0.template.0.metadata.0.self_link": "",
                            "spec.0.template.0.metadata.0.uid": "",
                            "spec.0.template.0.spec.#": "1",
                            "spec.0.template.0.spec.0.active_deadline_seconds": "0",
                            "spec.0.template.0.spec.0.container.#": "1",
                            "spec.0.template.0.spec.0.container.0.args.#": "3",

Em geral, se alguém quiser um problema de programação para uma entrevista, basta pedir que escreva um analisador para esta tarefa :)
Depois de muitas tentativas de escrever um analisador sem bugs, encontrei parte dele no código do terraform, e a parte mais importante. E tudo parecia funcionar bem

Tentativa três
Os provedores terraform são binários que contêm código com todos os recursos e lógica para trabalhar com a API da nuvem. Cada nuvem tem seu próprio provedor e o próprio terraform só os chama através de seu protocolo RPC entre dois processos.
Agora decidi entrar em contato com os provedores de terraform diretamente por meio de chamadas RPC. Ficou lindo e tornou possível mudar os provedores de terraform para outros mais novos e obter novos recursos sem alterar o código. Acontece também que nem todos os campos em tfstate deveriam estar em tf, mas como você pode descobrir? Basta perguntar ao seu provedor sobre isso. Então começou outra pornografia recursiva de montagem de expressões regulares, procurando campos dentro de tfstate em todos os níveis de profundidade.

No final, obtivemos uma ferramenta CLI útil que possui uma infraestrutura comum para todos os provedores de terraform e você pode facilmente adicionar uma nova. Além disso, adicionar recursos exige pouco código. Além de todos os tipos de vantagens, como conexões entre recursos. É claro que houve muitos problemas diferentes que não podem ser descritos todos.
Chamei o animal de Terrafomer.

Final

Usando o Terrafomer, geramos de 500 a 700 mil linhas de código tf + tfstate de duas nuvens. Conseguimos pegar coisas legadas e começar a tocá-las apenas por meio do terraform, tanto na melhor infraestrutura quanto nas ideias de código. É simplesmente mágico quando você pega uma nuvem enorme e a recebe por meio de uma equipe na forma de arquivos de trabalho terraform. E então grep/replace/git e assim por diante.

Penteei e coloquei em ordem, consegui permissão. Lançado no GitHub para todos na quinta-feira (02.05.19/XNUMX/XNUMX). github.com/GoogleCloudPlatform/terraformer
Já recebi 600 estrelas, 2 pull requests para adicionar suporte para openstack e kubernetes. Boa resposta. Em geral, o projeto é útil para pessoas
Aconselho a todos que desejam começar a trabalhar com Terraform e não reescrever tudo para isso.
Terei prazer em receber solicitações, problemas, estrelas.

Programa demonstrativo
Terraformer - Infraestrutura para codificar

Fonte: habr.com

Adicionar um comentário