Să ne ocupăm de Custom Tooling în Argo CD

Să ne ocupăm de Custom Tooling în Argo CD

După o vreme de la scrierea primului articol, în care m-am descurcat abil cu jsonnet și GitLab, am realizat că pipeline-urile sunt, desigur, bine, dar prea complicate și incomode.

În majoritatea cazurilor este necesară o sarcină tipică: "generați YAML și încărcați-l în Kubernetes". În esență, asta face Argo CD foarte bine.

Argo CD permite conectarea unui repository Git și sincronizarea stării acestuia în Kubernetes. Implicit, există suport pentru mai multe tipuri de aplicații: Kustomize, Helm charts, Ksonnet, jsonnet simplu sau doar directoare cu manifesturi YAML/JSON.

Majorității utilizatorilor din acest set le va fi suficient, dar nu tuturor. Pentru a satisface nevoile tuturor, Argo CD oferă posibilitatea de a utiliza uneltele personalizate.

În primul rând, ne interesează posibilitatea adăugării suportului qbec și git-crypt, care au fost pe deplin discutate în articolul precedent.

Înainte de a începe configurarea, trebuie mai întâi să înțelegem cum funcționează exact Argo CD.

Pentru fiecare aplicație adăugată, are două faze:

  • init — pregătirea inițială înainte de livrare, aici poate fi orice: descărcarea dependențelor, desfășurarea secretelor și altele.
  • generate — executarea directă a comenzii de generare a manifesturilor, rezultatul trebuie să fie un flux YAML valid, exact ceea ce va fi aplicat în cluster.

Este demn de menționat că Argo aplică această abordare pentru orice tip de aplicații, inclusiv pentru Helm. Asta înseamnă că în Argo CD, Helm nu se ocupă de livrarea versiunilor în cluster, ci este folosit doar pentru generarea manifesturilor.

Din partea sa, Argo știe să gestioneze nativ hooks-urile Helm, ceea ce permite menținerea logicii de aplicare a versiunilor.

QBEC

Qbec permite descrierea convenabilă a aplicațiilor folosind jsonnet și, în plus, are capacitatea de a reda graficele Helm, iar deoarece Argo CD știe să gestioneze corect hooks-urile Helm, utilizarea acestei funcționalități cu Argo CD permite obținerea rezultatelor corecte și mai precise.

Pentru a adăuga suport pentru qbec în argocd sunt necesare două lucruri:

  • în configurația Argo CD trebuie să fie definit pluginul personalizat și comenzile pentru generarea manifesturilor.
  • binarele necesare trebuie să fie disponibile în imaginea argocd-repo-server.

Prima sarcină se rezolvă destul de simplu:

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

(comanda init nu este utilizată)

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

Pentru a adăuga binarele se propune să construim o nouă imagine, sau să folosim tric cu 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)"

Acum să vedem cum va arăta manifestul aplicației noastre:

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

În variabila ENVIRONMENT noi transmitem numele mediului pentru care trebuie să generăm manifestele.

să aplicăm și să vedem ce am obținut:

Să ne ocupăm de Custom Tooling în Argo CD

aplicația a fost implementată, excelent!

git-crypt

Git-crypt permite configurarea criptării transparente a unui repository. Este o modalitate simplă și sigură de a stoca date confidențiale direct în git.

Implementarea git-crypt s-a dovedit a fi mai complicată.

Teoretic am putea executa git-crypt unlock în stadiul init al plugin-ului nostru personalizat, dar aceasta nu ar fi foarte convenabil, deoarece nu ar permite utilizarea metodelor native de implementare. De exemplu, în cazul Helm și Jsonnet, am pierde interfața GUI flexibilă care simplifică configurarea aplicației (fișiere valori și altele).

Exact de aceea am dorit să facem descărcarea repository-ului încă într-o etapă mai timpurie, la clonare.

Deoarece în prezent Argo CD nu oferă posibilitatea de a descrie orice hook-uri pentru sincronizarea repository-ului, a trebuit să ocolim această restricție cu un script shell inteligent care înlocuiește comanda 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

Argo CD execută git fetch de fiecare dată înaintea operațiunii de implementare. Exact pe această comandă vom atașa executarea git-crypt unlock pentru deblocarea repository-ului.

pentru teste puteți utiliza imaginea mea docker în care este deja tot ce aveți nevoie:

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

Acum trebuie să ne gândim la modul în care Argo va decripta repositoarele noastre. Adică să generăm o cheie gpg pentru el:

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

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

$ gpg --batch --gen-key genkey-batch
gpg: WARNING: unsafe ownership on homedir '/home/argocd/.gnupg'
gpg: keybox '/home/argocd/.gnupg/pubring.kbx' created
gpg: /home/argocd/.gnupg/trustdb.gpg: trustdb created
gpg: key 8CB8B24F50B4797D marked as ultimately trusted
gpg: directory '/home/argocd/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/argocd/.gnupg/openpgp-revocs.d/9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D.rev'

Să salvăm numele cheii 8CB8B24F50B4797D pentru pașii următori. Să exportăm cheia însăși:

$ 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] NUMELE DUMNEAVOASTRĂ <EMAILUL_DUMNEAVOASTRĂ@example.com>
sub   rsa3072 2020-09-04 [E]

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

Și îl vom adăuga ca un secret separat:

# 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

Singurul lucru care ne-a mai rămas este să-l transmităm în container argocd-repo-server, pentru aceasta vom edita deployment-ul:

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

Și vom înlocui existentul gpg-keys volume cu projected, unde vom specifica secretul nostru:

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

Argo CD încarcă automat cheile gpg din acest director la startul containerului, astfel va încărca și cheia noastră privată.

să verificăm:

$ 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 (Cheia de semnare ArgoCD) <noreply@argoproj.io>

sec   rsa3072 2020-09-03 [SC]
      9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D
uid           [ultimate] NUMELE DUMNEAVOASTRĂ <EMAILUL_DUMNEAVOASTRĂ@example.com>
ssb   rsa3072 2020-09-03 [E]

Excelent, cheia a fost încărcată! Acum trebuie doar să adăugăm Argo CD în repository-ul nostru ca colaborator și va putea să-l decripteze automat pe parcurs.

Importăm cheia pe computerul local:

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

Configurăm nivelul de încredere:

$ gpg --edit-key 8CB8B24F50B4797D
trust
5

Adăugăm argo ca colaborator în proiectul nostru:

$ git-crypt add-gpg-user 8CB8B24F50B4797D

Resurse relevante:

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster