Em uma nova companhia aérea. Uma aeromoça entra na cabine de passageiros: "Você está em nossa nova companhia aérea. No nariz da aeronave, temos uma sala de cinema. Na parte traseira - um salão de máquinas caça-níqueis. No convés inferior - uma piscina. No andar superior - uma sauna. Agora, senhores, apertem os cintos, e com todas essas coisas desnecessárias, vamos tentar decolar.
Olá, meu nome é Andrii. Eu tenho trabalhado na indústria de TI durante a maior parte da minha vida. Estou muito interessado na evolução da engenharia de gerenciamento de configuração de infraestrutura. Nos últimos 8 anos, estive envolvido com DevOps .
Uma das novas tendências populares é o conceito de GitOps , introduzido em 2017 por Alexis Richardson, CEO da Weaveworks. A Weaveworks é uma grande empresa adulta que, em 2020, arrecadou mais de 36 milhões em investimentos para desenvolver seu GitOps.
Meu artigo anterior discutiu uma história de sucesso de redução de custos sobre como mudamos do Elastic Stack para o Grafana . Agora, vou tentar falar sobre os desafios não óbvios que podem esperar por você ao adotar esse conceito. Resumindo, o GitOps não é uma "bala de prata". Você provavelmente acabará se reorganizando com muitas soluções alternativas complicadas. Eu mesmo estive nessa estrada e quero mostrar a você os problemas mais frustrantes que você não consegue ver ao ler outros artigos sobre GitOps.
Vamos mergulhar de cabeça!
O conceito mais promissor de construção de infraestrutura hoje é a infraestrutura imutável. Sua ideia principal é dividir a infraestrutura em duas partes fundamentalmente diferentes: Stateless e Stateful.
A parte sem estado da infraestrutura é imutável e idempotente. Não acumula estado (não armazena dados) nem altera seu funcionamento em função do estado acumulado. As instâncias da parte Stateless podem conter alguns artefatos básicos, scripts e montagens. Via de regra, eu os crio a partir de imagens base em ambientes de nuvem/virtualizados. Eles são frágeis e efêmeros: entrego novas versões de aplicativos recriando instâncias a partir de novas imagens base.
Os dados persistentes são armazenados na parte Stateful. Pode ser realizado pelo esquema clássico com servidores dedicados ou por alguns mecanismos de nuvem (DBaaS, objeto ou armazenamento em bloco).
Para tornar esse “zoológico” gerenciável e funcionar corretamente, precisamos da colaboração entre as equipes de engenharia e DevOps, bem como pipelines de entrega totalmente automatizados.
Extreme Programming é uma das metodologias de desenvolvimento ágil. Distingue-se por muitos loops de feedback, que permitem manter a sincronização com as necessidades do cliente.
Implementamos a automação de pipelines de entrega usando sistemas CI/CD. O termo CI (integração contínua) foi oferecido por Grady Booch em 1994 e, em 1997, Kent Beck e Ron Jeffries o introduziram na disciplina de programação extrema. No CI, precisamos integrar nossas mudanças sempre que possível no ramo de trabalho principal do nosso projeto.
Isso requer, primeiro, uma decomposição mais granular das tarefas: pequenas mudanças são mais atômicas e mais fáceis de rastrear, entender e integrar. Em segundo lugar, não podemos simplesmente mesclar código recém-escrito. Antes de mesclar ramos, devemos garantir que nada do que funcionou antes foi quebrado. Para fazer isso, o aplicativo deve pelo menos ser construído. Também é uma boa ideia cobrir o código com testes.
E esta é a tarefa realizada pelos sistemas CI, que avançaram muito no desenvolvimento e, em algum ponto no meio desse caminho, se transformaram em sistemas CI/CD.
O que é um CD? Martin Fowler distingue 2 definições de CD :
Entrega Contínua. É nessa hora que, com o auxílio das práticas de Integração Contínua e da cultura DevOps, você mantém a ramificação principal do seu projeto constantemente pronta para ser implantada em produção.
Implantação Contínua. É a Entrega Contínua onde tudo o que vai para o ramo principal é despejado no seu cluster, na sua produção.
Vamos mais longe.
Infelizmente, a infraestrutura imutável tem vários problemas. A maior parte deles é herdada do conceito de Infraestrutura como Código (IaC).
Em primeiro lugar, é um desvio de configuração. Este termo nasceu nos Puppet Labs (autores do conhecido Puppet SCM) e afirma que nem todas as alterações nos sistemas de destino são feitas com a ajuda do gerenciamento de configuração do sistema (SCM). Alguns são feitos manualmente, ignorando-os.
No processo de tais mudanças múltiplas, surge o desvio de configuração - a diferença entre a configuração descrita no SCM e o estado real das coisas.
Isso leva a uma espiral de medo de automação.
Quanto mais alterações manuais forem feitas, maior a probabilidade de que a execução de um script SCM interrompa as alterações não registradas. Quanto mais assustador for executá-lo, maior a probabilidade de novas edições manuais serem feitas.
Eventualmente, esse feedback positivo vicioso leva à formação de servidores floco de neve, que se tornaram tão inconsistentes que ninguém mais entende o que está dentro. Após as edições manuais, o nó se torna tão único quanto cada floco de neve individual em uma nevasca.
Essa deriva deixa os servidores em níveis mais altos dentro da infraestrutura imutável: agora podemos falar sobre GCP Project/AWS VPC/Kubernetes-cluster-snowflakes. Isso acontece porque a implementação de mudanças não é regulamentada na infraestrutura imutável. Além disso, ninguém sabe como fazê-lo corretamente.
E então o Weaveworks aparece e diz: "Pessoal, temos o que você precisa - GitOps". Para promover o GitOps, eles trouxeram um peso pesado como Kelsey Hightower, que criou o guia "Kubernetes the hard way" . Durante seu PR, ele transmite fortemente a mensagem: "Seja um homem, b ...! Pare de criar scripts e comece a enviar." E ele diz uma certa quantidade de besteiras de marketing bingo.
Na minha opinião, os benefícios mais interessantes foram:
E qualquer pessoa tentando descobrir o que é GitOps se depara com este slide de livro didático.
Em seguida, encontramos os princípios do GitOps, que se assemelham aos princípios IaC ligeiramente aumentados:
No entanto, esta é uma descrição esférica no vácuo, então continuamos nossa pesquisa. Encontramos o site GitOps.tech e nele vários esclarecimentos importantes.
Primeiro, aprendemos que o GitOps é um código semelhante a uma infraestrutura no Git com ferramentas de CD que o aplica automaticamente à infraestrutura.
Devemos ter pelo menos 2 repositórios dentro do GitOps:
Além disso, na ideologia GitOps, uma abordagem orientada a puxar é preferível a uma abordagem orientada a push. Isso é um pouco contrário à evolução dos sistemas SCM, desde os monstros Puppet e Chef até os leves Ansible e Terraform baseados em push.
E se o GitOps é principalmente uma história de kit de ferramentas, faz sentido pegar o conceito baseado em Flux do próprio Weaveworks e desconstruí-lo. Os autores da ideia devem ter feito uma implementação de referência.
O Flux agora está na versão 2 e consiste arquiteturalmente em controladores que funcionam dentro de um cluster:
Em seguida, vamos discutir o trabalho com Flux e Helm.
Vou descrever melhor o exemplo de implantação de um aplicativo usando o gerenciador de pacotes Helm no Flux 2.
Por que? De acordo com a Pesquisa CNCF 2021 , o gerenciador de pacotes HELM foi o aplicativo de embalagem mais popular, com uma participação de mais de 50%.
Infelizmente, não consegui encontrar dados mais atualizados, mas não acho que muita coisa mudou desde então.
Então, vamos percorrer a lógica básica de como o Flux 2 funciona com o Helm. Temos 2 repositórios: aplicação e infraestrutura.
Criamos um gráfico HELM e uma imagem docker do repositório do aplicativo e os adicionamos ao repositório do gráfico Helm e ao registro docker, respectivamente.
Em seguida, temos um cluster Kubernetes executando os controladores de fluxo.
Para implementar nosso aplicativo, preparamos um YAML descrevendo o recurso personalizado (CR) HelmRelease e o adicionamos ao repositório de infraestrutura.
Para ajudar o fluxo a obtê-lo, criamos um CR GitRepository no cluster Kubernetes. O controlador de origem o vê, vai para o git e o baixa.
Para implantar esse YAML em um cluster, descrevemos um recurso de personalização.
O controlador Kustomize o vê, vai para o controlador de origem, obtém o YAML e o implanta no cluster.
O controlador Helm vê que um CR HelmRelease apareceu no cluster e vai para o controlador Source para obter o gráfico HELM descrito.
Para que o controlador de origem forneça ao controlador HELM o gráfico solicitado, devemos criar um HelmRepository no cluster CR.
O Helm-controller obtém um gráfico do Source-controller, cria uma versão e a implanta no cluster. Em seguida, o Kubernetes cria os pods necessários, acessa o registro do docker e baixa as imagens correspondentes.
Assim, para lançar uma nova versão de nosso aplicativo, precisamos criar uma nova imagem, um novo arquivo HelmRelease e possivelmente um novo gráfico HELM. Em seguida, devemos colocá-los nos repositórios apropriados e esperar que os controladores do Flux repitam o trabalho na cadeia descrita acima.
E, para finalizar nosso trabalho, colocamos um controlador de notificação em algum lugar que nos notifica sobre o que pode ter dado errado.
Agora vamos discutir os recursos customizados com os quais o Flux opera.
O primeiro é o repositório Git. Aqui podemos especificar o endereço do repositório Git (linha 14) e o branch que ele examina (linha 10).
Assim, baixamos apenas um único branch, não o repositório inteiro. Mas! Como somos engenheiros responsáveis e tentamos aderir ao conceito Zero Trust, bloqueamos o acesso ao repositório, criamos um segredo com uma chave no cluster Kubernetes e entregamos ao Flux para que ele vá até lá (linha 12).
Em seguida é a Kustomização. Aqui, quero chamar sua atenção para o fato de que o controlador Kustomize do Flux e o Kustomize dos autores do Kubernetes são duas coisas diferentes. Não sei por que uma nomenclatura tão desorientadora foi escolhida, mas é importante não confundi-los.
Kustomization é uma maneira de implantar YAML (qualquer) de um repositório Git para um cluster. Aqui temos que especificar a fonte de onde colocamos (linha 12 - o nome do CR GitRepository descrito acima), o diretório de onde pegamos os YAMLs (linha 8) e podemos especificar o namespace de destino onde depositá-los (linha 13).
Em seguida é o lançamento do Helm.
Aqui podemos especificar o nome e a versão do gráfico (linhas 10,11). Aqui você especifica os valores das variáveis para que o Helm possa customizar a versão de ambiente para ambiente (linhas 15-19). Este é um recurso extremamente importante e necessário, pois seus ambientes podem diferir significativamente. Você também especifica a origem para obter o gráfico Helm (linhas 12, 13, 14). Nesse caso, é o repositório do Helm.
Mas! Como ainda somos engenheiros responsáveis, também temos acesso próximo ao repositório Helm e fornecemos ao Flux um segredo para chegar lá (linhas 7, 8).
Então, vamos fazer uma pequena lista de verificação para capturar o que acabamos de ver. Para começar a fazer GitOps, temos que escrever repentinamente vários scripts (lembramos que a infraestrutura imutável é toda sobre pipelines de entrega totalmente automatizados). Então, primeiro de tudo, temos que criar:
Ótimo, agora você tem uma lista de verificação para GitOps. Ir em frente.
Vamos ver o que obtemos com nosso lançamento do Helm em geral. É bastante evidente que o Git não pode ser a única fonte de verdade neste caso particular. Temos pelo menos 2 recursos, 2 artefatos fora do git, dos quais esta versão do Helm depende:
E podemos complicar ainda mais as coisas e especificar o intervalo de versões do gráfico Helm.
Nesse caso, o Flux monitorará e definirá novos gráficos Helm que aparecerem dentro desse intervalo. Além disso, o Source Controller que temos pode usar YAML como fonte, incluindo pacotes S3.
A partir daí, podemos manter os gráficos YAML e Helm.
Além disso, temos controladores de automação de imagem que podem ficar de olho em novas imagens no registro do Docker e editar o repositório de infraestrutura.
Mas não queremos operações de repositório de gráficos HELM ou operações de registro do Docker. Queremos ser o mais GitOps possível. Então, olhamos a documentação e corrigimos os processos para implantar nosso gráfico Helm do repositório GIT (escolhemos o repositório do aplicativo para armazená-lo).
Isso nos obriga a criar outro CR GitRepository para o repositório do aplicativo, uma conta para o Flux acessá-lo e criar um segredo com as chaves.
Ao mesmo tempo, não resolvemos o problema de uma dependência complicada na imagem do Docker de forma alguma.
Acho que chega por hoje. Na parte 2, contarei quais problemas essa bondade tem. Eu discutirei:
Espero que este artigo tenha sido útil para você!