Compreendendo o Custom Tooling no Argo CD

Compreendendo o Custom Tooling no Argo CD

Depois de algum tempo escrevendo o primeiro artigo, onde lidei habilidosamente com jsonnet e GitLab, percebi que os pipelines são bons, mas excessivamente complexos e inconvenientes.

Na maioria dos casos, há uma tarefa padrão: "gerar YAML e colocá-lo no Kubernetes". Na verdade, é exatamente isso que o Argo CD faz maravilhosamente bem.

O Argo CD permite conectar um repositório Git e sincronizar seu estado no Kubernetes. Por padrão, há suporte para vários tipos de aplicativos: Kustomize, Helm charts, Ksonnet, Jsonnet puro ou simplesmente diretórios com manifests YAML/JSON.

A maioria dos usuários desse conjunto encontrará o suficiente, mas não todos. Para atender às necessidades de todos, o Argo CD oferece a possibilidade de usar ferramentas personalizadas.

Primeiramente, interessa a adição de suporte para qbec e git-crypt, que foram discutidos em detalhe no artigo anterior.

Antes de começar a configuração, é necessário entender como o Argo CD funciona.

Para cada aplicativo adicionado, ele possui duas fases:

  • init — preparação inicial antes da implantação, onde pode haver qualquer coisa: download de dependências, descompactação de segredos, entre outros.
  • gerar — execução da própria comando de geração de manifests, a saída deve ser um stream YAML válido, que é exatamente o que será aplicado no cluster.

É notável que o Argo aplica essa abordagem para qualquer tipo de aplicativo, incluindo Helm. Ou seja, no Argo CD, o Helm não é usado para implantar releases no cluster, mas apenas para gerar manifests.

Por sua vez, o Argo pode processar hooks do Helm nativamente, o que permite não quebrar a lógica de aplicação dos releases.

QBEC

O Qbec permite descrever aplicativos de forma conveniente usando jsonnet, além de renderizar Helm charts, e dado que o Argo CD lida bem com hooks do Helm, usar essa funcionalidade com o Argo CD permite obter resultados ainda mais precisos.

Para adicionar suporte ao qbec no argocd, são necessárias duas coisas:

  • No config do Argo CD, deve ser definido seu plugin personalizado e os comandos para gerar os manifests.
  • Os binários necessários devem estar disponíveis na imagem argocd-repo-server.

A primeira tarefa é resolvida de forma bastante simples:

# cm.yaml
data:
  configManagementPlugins: |
    - name: qbec
      generate:
        command: [sh, -xc]
        args: ['qbec show "$ENVIRONMENT" -S --force:k8s-namespace "$ARGOCD_APP_NAMESPACE"']

(o comando init não é utilizado)

$ kubectl -n argocd patch cm/argocd-cm -p "$(cat cm.yaml)"

Para adicionar os binários, é sugerido construir uma nova imagem, ou usar um truque com o init-container:

# deploy.yaml
spec:
  template:
    spec:
      # 1. Define an emptyDir volume which will hold the custom binaries
      volumes:
      - name: custom-tools
        emptyDir: {}
      # 2. Use an init container to download/copy custom binaries into the emptyDir
      initContainers:
      - name: download-tools
        image: alpine:3.12
        command: [sh, -c]
        args:
        - wget -qO- https://github.com/splunk/qbec/releases/download/v0.12.2/qbec-linux-amd64.tar.gz | tar -xvzf - -C /custom-tools/
        volumeMounts:
        - mountPath: /custom-tools
          name: custom-tools
      # 3. Volume mount the custom binary to the bin directory (overriding the existing version)
      containers:
      - name: argocd-repo-server
        volumeMounts:
        - mountPath: /usr/local/bin/qbec
          name: custom-tools
          subPath: qbec
        - mountPath: /usr/local/bin/jsonnet-qbec
          name: custom-tools
          subPath: jsonnet-qbec

$ kubectl -n argocd patch deploy/argocd-repo-server -p "$(cat deploy.yaml)"

Agora vamos ver como ficará o manifesto da nossa aplicação:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: qbec-app
  namespace: argocd
spec:
  destination: 
    namespace: default
    server: https://kubernetes.default.svc
  project: default
  source: 
    path: qbec-app
    plugin: 
      env: 
        - name: ENVIRONMENT
          value: default
      name: qbec
    repoURL: https://github.com/kvaps/argocd-play
  syncPolicy: 
    automated: 
      prune: true

Na variável ENVIRONMENT nós passamos o nome do ambiente para o qual precisamos gerar os manifests.

aplicaremos e veremos o que conseguimos:

Compreendendo o Custom Tooling no Argo CD

a aplicação foi implantada, ótimo!

git-crypt

O Git-crypt permite configurar a criptografia transparente do repositório. Esta é uma maneira simples e segura de armazenar dados confidenciais diretamente no git.

A implementação do git-crypt acabou sendo mais complicada.

Teoricamente, poderíamos executar git-crypt unlock na fase init do nosso plugin customizado, mas isso não seria muito conveniente, pois não permitiria o uso de métodos nativos de implantação. Por exemplo, no caso do Helm e do Jsonnet, perdemos a interface gráfica flexível que facilita a configuração da aplicação (arquivos values e outros).

É por isso que gostaríamos de realizar a extração do repositório ainda em uma fase anterior, durante o clone.

Como atualmente o Argo CD não fornece a possibilidade de descrever quaisquer ganchos para sincronização do repositório, foi necessário contornar essa limitação com um shell script intermediário que substitui o comando git:

#!/bin/sh
$(dirname $0)/git.bin "$@"
ec=$?
[ "$1" = fetch ] && [ -d .git-crypt ] || exit $ec
GNUPGHOME=/app/config/gpg/keys git-crypt unlock 2>/dev/null
exit $ec

O Argo CD executa git fetch toda vez antes da operação de implantação. É nesse comando que vamos adicionar a execução git-crypt unlock para desbloquear o repositório.

para testes você pode usar minha imagem docker na qual já está tudo necessário:

$ kubectl -n argocd set image deploy/argocd-repo-server argocd-repo-server=docker.io/kvaps/argocd-git-crypt:v1.7.3

Agora precisamos pensar em como o Argo vai descriptografar nossos repositórios. Ou seja, gerar uma chave gpg para isso:

$ kubectl exec -ti deploy/argocd-repo-server -- bash

$ printf "%sn" 
    "%no-protection" 
    "Key-Type: default" 
    "Subkey-Type: default" 
    "Name-Real: SEU NOME" 
    "Name-Email: SEU EMAIL@example.com" 
    "Expire-Date: 0" 
    > genkey-batch 

$ gpg --batch --gen-key genkey-batch
gpg: ATENÇÃO: a propriedade do diretório 'home' é insegura 'home/argocd/.gnupg'
gpg: keybox 'home/argocd/.gnupg/pubring.kbx' criada
gpg: home/argocd/.gnupg/trustdb.gpg: trustdb criada
gpg: chave 8CB8B24F50B4797D marcada como ultimamente confiável
gpg: diretório 'home/argocd/.gnupg/openpgp-revocs.d' criado
gpg: certificado de revogação armazenado como 'home/argocd/.gnupg/openpgp-revocs.d/9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D.rev'

Vamos salvar o nome da chave 8CB8B24F50B4797D para os próximos passos. Vamos exportar a chave:

$ gpg --list-keys
gpg: WARNING: unsafe ownership on homedir '/home/argocd/.gnupg'
/home/argocd/.gnupg/pubring.kbx
-------------------------------
pub   rsa3072 2020-09-04 [SC]
      9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D
uid           [ultimate] SEU NOME 
sub   rsa3072 2020-09-04 [E]

$ gpg --armor --export-secret-keys 8CB8B24F50B4797D

E vamos adicioná-la como um segredo separado:

# argocd-gpg-keys-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: argocd-gpg-keys-secret
  namespace: argocd
stringData:
  8CB8B24F50B4797D: |-
    -----BEGIN PGP PRIVATE KEY BLOCK-----

    lQVYBF9Q8KUBDACuS4p0ctXoakPLqE99YLmdixfF/QIvXVIG5uBXClWhWMuo+D0c
    ZfeyC5GvH7XPUKz1cLMqL6o/u9oHJVUmrvN/g2Mnm365nTGw1M56AfATS9IBp0HH
    O/fbfiH6aMWmPrW8XIA0icoOAdP+bPcBqM4HRo4ssbRS9y/i
    =yj11
    -----END PGP PRIVATE KEY BLOCK-----

$ kubectl apply -f argocd-gpg-keys-secret.yaml

A única coisa que nos resta é passar isso para o container argocd-repo-server, para isso vamos editar o deployment:

$ kubectl -n argocd edit deploy/argocd-repo-server

E substituir o existente gpg-keys volume por projected, onde indicaremos nosso segredo:

   spec:
     template:
       spec:
         volumes:
         - name: gpg-keys
           projected:
             defaultMode: 420
             sources:
             - secret:
                 name: argocd-gpg-keys-secret
             - configMap:
                 name: argocd-gpg-keys-cm

O Argo CD carrega automaticamente as chaves gpg deste diretório ao iniciar o container, assim ele carregará nossa chave privada.

vamos verificar:

$ kubectl -n argocd exec -ti deploy/argocd-repo-server -- bash
$ GNUPGHOME=/app/config/gpg/keys gpg --list-secret-keys
gpg: WARNING: unsafe ownership on homedir '/app/config/gpg/keys'
/app/config/gpg/keys/pubring.kbx
--------------------------------
sec   rsa2048 2020-09-05 [SC] [expires: 2021-03-04]
      ED6285A3B1A50B6F1D9C955E5E8B1B16D47FFC28
uid           [ultimate] Anon Ymous (Chave de assinatura do ArgoCD) 

sec   rsa3072 2020-09-03 [SC]
      9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D
uid           [ultimate] SEU NOME 
ssb   rsa3072 2020-09-03 [E]

Ótimo, a chave foi carregada! Agora apenas precisamos adicionar o Argo CD ao nosso repositório como colaborador, e ele poderá descriptografá-la automaticamente.

Vamos importar a chave para o computador local:

$ gpg --armor --export-secret 8CB8B24F50B4797D > 8CB8B24F50B4797D.pem
$ gpg --import 8CB8B24F50B4797D.pem

Vamos configurar o nível de confiança:

$ gpg --edit-key 8CB8B24F50B4797D
trust
5

Vamos adicionar argo como colaborador ao nosso projeto:

$ git-crypt add-gpg-user 8CB8B24F50B4797D

Links relacionados:

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster