GitOps na prática com ArgoCD

Você já ouviu o ditado: cão de dois donos ou passa fome ou come de mais? A Infraestrutura das empresas é mantida por vários donos; pessoas com experiências diversas, capazes de resolver problemas de inúmeras maneiras. Agora, como garantir que a nossa estrutura não vai “morrer de fome” ou manter um padrão mínimo de conformidade? Existem várias boas práticas que o mercado recomenda. Uma delas é a adoção de GitOps, implementado por uma das mais famosas ferramentas: O ArgoCD. Hoje nós vamos aprender o que é GitOps na prática com ArgoCD.

E para começar, vamos entender o que são alguns conceitos, começando pelos famosos manifestos.

O que são manifestos?

Você provavelmente já se deparou com eles, mas não sabia do que se tratavam; ou nunca refletiu a respeito do nome que carregam. Para começar a abrir nossa mente, observe o yaml à seguir:

apiVersion: v1
kind: Namespace
metadata:
  name: monitoring

Agora me responda:

  • Algum verbo foi utilizado?
  • O yaml acima está implementando algum algoritmo?
  • Existe alguma condicional no conteúdo?

Manifestos são assim: Eles não descrevem nem o como e nem o porquê. Eles apenas descrevem como as coisas devem ser. E nós, ou as ferramentas que usamos, por sua vez, é que temos todo o trabalho de planejar e executar as mudanças no ambiente, refletindo o que foi expresso no manifesto. Pense neles como “decretos de vossa majestade”: A vontade real foi expressa. A gente que lute.

Para você, que ficou curioso, o manifesto acima apenas diz ao kubernetes: “Deve existir um namespace e o nome dele é monitoring“. Só faltou um “Cumpra-se e faça-se cumprir”.

O que é GitOps?

Sua majestade mudou de ideia e emitiu novo decreto. Como notificar todos os seus súditos que a vontade real mudou e que a realidade precisa ser alterada para corresponder aos desígnios da égide real? Várias pessoas do Reino tem em mãos cópias de vários decretos. Como saber qual foi a última expressão da vontade do trono?

apiVersion: v1
kind: Namespace
metadata:
  name: robespierre

É aqui que GitOps entra.

Este conceito determina que a fonte da verdade deve ser o repositório onde o estado do ambiente está versionado. E toda vez que um novo commit for adicionado ao repositório, o estado do ambiente precisa corresponder a essas modificações. Essa conciliação é feita automaticamente, por meio de ferramentas que escutam essas mudanças e as aplicam no ambiente.

Por exemplo: Não há nada que nos diga, se considerarmos apenas este manifesto, se estamos renomeando o namespace monitoring para robespierre ou se estamos criando um novo namespace chamado robespierre (inquilinos da Bastilha que se cuidem!). É parte desse processo de conciliação entender, de acordo com as mudanças sofridas pelos manifestos, o que precisa ser feito no ambiente.

Vantagens do GitOps

  1. Auditoria: a simples adoção de versionamento, já traz consigo a auditoria e rastreabilidade. Não é necessário ferramentas de logs robustas e etc. Só fazer o blame do commit; fazer o diff com a versão anterior e procurar pelos aprovadores/as do PR.
  2. Diminui o número de usuários com acesso privilegiado: Idealmente apenas a ferramenta de GitOps precisa ter acesso para modificar o ambiente, exceto apenas alguns poucos – e poderosos – membros da corte. Assim você diminui a “superfície do estrago” e a preocupação com governança de acesso.
  3. Ambiente sem “Drift”: Nada de “oh, meu deus! É o Braia”. Se alguém modificar manualmente o seu ambiente, as ferramentas de GitOps identificam a mudança e voltam o ambiente para o estado anterior, assegurando a fonte de verdade única;
  4. Previsibilidade e reprodução: Se o seu node pool pegar fogo, ou se quiser compartilhar a sua infra com um amigo, basta instalar a ferramenta, vincular o projeto e em instantes o cluster estará com a mesma configuração anterior.
  5. Única fonte de verdade: Essa pra mim é a principal vantagem, e não apenas porque é ela quem viabiliza todas as anteriores. Eu já passei por cenários em que precisava consultar pessoas para recuperar um determinado histórico. Pessoas esquecem, mudam de trabalho, se confundem. Uma única fonte de verdade, além de deixar tudo mais simples, aumenta a confiabilidade. É o cão com um dono só.

Mas como revoluções não tem apenas um lado positivo?

Desvantagens do GitOps

  1. Menor flexibilidade para mudanças: O sistema está fora do ar. A probe de healthcheck está errada e um mero path no deployment é o suficiente para tudo voltar pro ar. Idealmente, com GitOps você não pode fazer atualizações manuais (zero drift, lembra?). E dependendo de como for o seu processo git, “seguir a cartilha” pode fazer com que a mudança demore para ser executada, representando um possível impacto financeiro.
  2. Aumento no custo de Debug: GitOps adiciona algumas camadas de falha ao seu processo. Então, quando um pod não entrar no ar, você deve se perguntar: Alguém aprovou o PR? O Git está disponível? A aplicação está OutOfSync? Tem algum problema na ordem de execução dos scripts?
  3. Gestão de segredos: Segredos no Kubernetes são um problema difícil de resolver. E fica ainda mais impossível se você versiona certificados, senhas, e qualquer outro segredo no código. Você vai precisar de algum CRD para fazer essa gestão de senhas por você. Coloco como uma desvantagem porque sempre há a possibilidade de digitar o kubectl criando a secret e ter amnésia cinco minutos depois.

Além do Git, que outra ferramenta poderia nos ajudar a implementar todos esses conceitos? Vamos conhecer o ArgoCD.

O que é o ArgoCD?

Agora que temos os manifestos do nosso cluster versionados, precisamos que uma ferramenta aplique esses manifestos automaticamente sempre que o repositório for atualizado. E é exatamente isso que o ArgoCD faz. Nele você consegue definir projetos, que por sua vez possuem aplicações. E as aplicações também podem possuir outras aplicações (o já famoso app-of-apps).

Só que o ArgoCD faz muito mais do que apenas sincronizar repositórios. Se não fosse assim, um simples hook no git já seria suficiente. Por isso, eu recomendo que você dê uma olhada na documentação para descobrir todo o potencial da ferramenta.

Disclaimer

Eu gosto muito de sempre poder fornecer pra vocês, código que se aproximem do mundo real. No entanto, nem sempre isso será verdade quando falamos de DevOps. Ambientes produtivos exigem alguns recursos que eu não tenho à disposição e/ou que são impossíveis de fazer em um home lab.

Por isso, antes de pensar em executar os scripts em produção, reveja cada um e considere fortemente as questões de segurança. Embora eu esteja usando SSL gerado por um cert-manager, os manifestos à seguir estão longe de atenderem os requisitos de segurança exigidos em um ambiente real e produtivo.

Instalando o ArgoCD

Instalar o ArgoCD é trivial:

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Aguarde os pods estabilizarem e o ArgoCD estará disponível. Use o comando abaixo para aguardar o argocd-server estar disponível.

kubectl wait pods --timeout=120s --for=condition=Ready -n argocd -l app.kubernetes.io/name=argocd-server

Para descobrir a senha inicial do sistema, verifique o valor da secret:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

Quando você instala o ArgoCD, além dos manifestos mais comuns, uma série de novas CRDs são adicionadas ao kubernetes, permitindo que você aplique manifestos como o abaixo no seu cluster:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cluster-bootstrap
  namespace: argocd
spec:
  project: default
  source:
    repoURL: git@github.com:blogdoft/k3s-apps.git
    targetRevision: HEAD
    path: bootstrap
    directory:
      recurse: true
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Para acessar, você ainda vai precisar de um proxy para o serviço. Ou, pode ser esperto e configurar um ingress para acessar direto do navegador, sem a necessidade de proxy.

---
#Need to configure argocd to server.insecure: "true"
#https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#traefik-v22
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cmd-params-cm
  namespace: argocd
  labels:
    app.kubernetes.io/name: argocd-cmd-params-cm
    app.kubernetes.io/part-of: argocd
data:
  server.insecure: "true"
  # Removed server.basehref and server.rootpath to serve from root
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-ingress
  namespace: argocd
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"
spec:
  ingressClassName: traefik
  rules:
  - host: argocd.home.arpa
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: argocd-server
            port:
              name: http

Considere que estou utilizando Traefik como ingress e tenho um cert-manager para controle e geração de certificados. Se quiser uma opção via http, altere para:

    traefik.ingress.kubernetes.io/router.entrypoints: web
    traefik.ingress.kubernetes.io/router.tls: "false"

Como você alterou um ConfigMap, vai ser obrigado a reiniciar os serviços também.

kubectl -n argocd rollout restart deploy argocd-server

Aguarde todos os deployments ficarem ready outra vez e está pronto!

É realmente simples assim instalar o ArgoCD.

Deployando aplicações com ArgoCD

Antes do primeiro deploy, você precisa entender alguns conceitos:

  • AppProject: Define um agrupamento, estabelecendo limites e permissões para as aplicações vinculadas ao projeto. Você pode dizer, por exemplo, quais repositórios podem ser acessados, quais endpoints podem ser criados e até mesmo que tipo de artefatos k8s podem ser manipulados.
  • Application: É um deployable no kubernetes. Nele você define tudo o que precisa para que uma aplicação seja entregue: repositório dos manifestos, endereço do helm, namespace, se deve ser “drift proof” ou não, se deve ser atualizada automaticamente ou não.
  • App of Apps: É idêntico ao Application, com a diferença que ele não entrega nada no ambiente de fato. Apenas agrupa outras aplicações, facilitando processos que deveriam ocorrer em lote.

Uma palavra sobre conciliação

Um ponto importante sobre o Application: Lembra do nosso exemplo inicial, em que a simples leitura do manifesto não seria suficiente para saber se é uma adição ou renomeação? O recurso Application fornece esse tipo de contexto para o ArgoCD durante a conciliação de um novo commit do seu repositório.

Porém preciso destacar um ponto de atenção importante: De fato, não há possibilidade de renomear recursos no kubernetes. Se você renomear um namespace, o que provavelmente irá acontecer é o ArgoCD apagar o namespace atual e criar um novo. Pode imaginar o estrago que isso faria no seu ambiente? Por isso tome muito cuidado com as modificações que você faz. Sempre revise bem os manifestos e pense estrategicamente antes de aplicar uma alteração destrutiva.

Você pode criar AppProjects, Applications e até App of Apps através da interface ou do CLI do ArgoCD. Mas a forma mais indicada é através de manifestos. Vamos dizer que estamos fazendo o deploy dos componentes de segurança do nosso cluster. Vamos instalar o KeyCloak e o OpenBao.

Criando um AppProject no ArgoCD

Vamos dar uma olhada no manifesto que cria um AppProject

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: security
  namespace: argocd
  annotations:
    argocd.argoproj.io/sync-wave: "10"
spec:
  description: Segurança e identidade (Keycloak/OpenBao/etc.)
  sourceRepos:
    - git@github.com:blogdoft/k3s-apps.git
  destinations:
    - server: https://kubernetes.default.svc
      namespace: keycloak
    - server: https://kubernetes.default.svc
      namespace: openbao
  clusterResourceWhitelist:
    - group: "*"
      kind: "*"
  namespaceResourceWhitelist:
    - group: "*"
      kind: "*"

A maior parte dos campos é auto-explicativa. Quero chamar a atenção para alguns apenas:

  • sourceRepos: Define quais repositórios podem ser utilizados dentro do project;
  • destinations: Você pode criar opções para deploy em diferentes clusters (dev/stg/prd);
  • clusterResourceWhiteList: Diz quais recursos você pode manipular nas suas aplicações.

Para maiores detalhes, consulte a documentação.

Agora vejamos como seria o deploy de uma aplicação

Criando uma Application no ArgoCD

Observe o manifesto à seguir:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: keycloak
  namespace: argocd
  annotations:
    argocd.argoproj.io/sync-wave: "30"
spec:
  project: security
  source:
    repoURL: git@github.com:blogdoft/k3s-apps.git
    path: artifacts/security/keycloak/manifests
    targetRevision: HEAD
  destination:
    server: https://kubernetes.default.svc
    namespace: keycloak
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      enabled: true
    syncOptions:
      - CreateNamespace=true

Nesse manifesto, estou definindo como será a aplicação keycloak. Na linha 9, por exemplo, digo que ela irá pertencer ao AppProject security, ficando, portanto, restrita ao que for definido nesse projeto. Perceba, também, que a propriedade source é levemente diferente da anterior. Aqui eu defino um repositório, mas também defino um caminho de pasta e qual a branch/commit do ArgoCD precisa observar as mudanças.

As linhas 17 em diante definem o comportamento do ArgoCD para quando ele identificar mudanças. As três opções, estando como true dá todo o controle de gestão ao ArgoCD. Se um recurso sumir do repositório, o ArgoCD irá destruí-lo no cluster (prune), se alguma modificação manual for feita, o ArgoCD deverá trazer o cluster para o estado desejado (selfHeal) e quando modificações forem feitas no repositório, elas devem ser aplicadas pelo ArgoCD (enabled).

O caminho artifacts/security/keycloak/manifests no repostório git@github.com:blogdoft/k3s-apps.git aponta para uma pasta cheia de manifestos do k3s

Eu posso usar Helm no ArgoCD?

Sim, o ArgoCD dá suporte a configurações por helms. E por um lado é bastante positivo isso, já que você mantém menos arquivos versionados. Entretanto, nem sempre o .values de um helm é suficientemente poderoso para permitir todas as personalizações demandadas. Ou ainda, por um processo de auditoria, você precisa identificar o que foi alterado entre as diversas versões do helm.

Por conta desses pontos, eu prefiro fazer um “unpack” do helm. E quando atualizar, eu consigo ver pelo diff do git, o que foi realmente modificado.

Eu posso ter execuções mais dinâmicas?

Além de manifestos puros e Helm, o ArgoCD também oferece suporte para Kustomize – uma “versão nativa” de helm no k8s – além de plugins que podem te ajudar a adicionar maior inteligência ao ArgoCD. Eu entendo a vontade de automatizar algumas coisas. Penso, por exemplo, que poderia ser uma boa para aplicar as secrets no cluster, por exemplo (spoiler: Não é).

Agora pense aqui comigo: Por mais que uma automação jure que irá garantir idempotência na geração dos scripts, a ideia do GitOps é ter o repositório como fonte de verdade. Se existirem intermediários entre o repositório e o cluster modificando os manifestos, concorda que o git deixou de ser a origem única do estado o seu cluster? É como se você estivesse jogando no lixo uma das principais vantagens do GitOps. Por isso, nem tudo que pode ser feito, deve ser feito. Pense bem.

Colocando pra rodar

Está com a ansiedade lá no alto, não é?

A documentação do ArgoCD já disponibiliza um pequeno projeto “Olá Mundo” para você fazer o deploy. No entanto, se você quiser brincar comigo, eu estou compartilhando o meu repositório também. Lá você vai instalar o cert-manager, flagr, kafbat.ui, keycloak, longhorn, openbao e rancher. Combinando com scripts, eu consigo levantar todo o meu cluster em menos de dez minutos. https://github.com/blogdoft/k3s-apps/tree/main

Enquanto escrevo esse artigo, ainda não resolvi o problema de carga de secrets. Por isso, entre os scripts que levantam o meu cluster, há alguns arquivos de ambiente de onde são extraídas todas as minhas secrets.

O que eu estou achando do ArgoCD?

Alguém pode dizer que ter o ArgoCD em um Home Lab é over engineering. Mas cá para nós, ter um kubernetes rodando em casa já é um over engineering, não acha?

Eu gostei bastante. Dava um certo trabalho levantar todas as aplicações manualmente no meu pequeno cluster. Só de usar o ArgoCD, consegui reduzir o trabalho de horas para minutos. Com certeza a ferramenta ajudou nesse processo, mas o simples fato de me educar a commitar todas as alterações, já trouxe alguma estabilidade para o meu ambiente.

Ainda quero avançar em alguns pontos na configuração dele. Seria ótimo se ele utilizasse o keycloak como SSO, por exemplo. Também espero contornar cenários de “quem veio primeiro”. Afinal, é o ArgoCD que instala o meu Keycloak. E as secrets precisam estar no openbao – que também é “mantido” pelo ArgoCD. Enfim… Alimentar o cachorro corretamente, enquanto vive a revolução francesa não deve ter sido fácil.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.