Wir befassen uns mit Custom Tooling in Argo CD

Wir befassen uns mit Custom Tooling in Argo CD

Nach einiger Zeit nach dem Schreiben des ersten Artikels, in dem ich geschickt mit Jsonnet und GitLab umging, wurde mir klar, dass Pipelines zwar gut sind, aber übermäßig komplex und unbequem.

In den meisten Fällen wird eine Standardaufgabe benötigt: "YAML generieren und in Kubernetes ablegen". Genau das bewältigt Argo CD hervorragend.

Argo CD ermöglicht die Anbindung an ein Git-Repository und synchronisiert dessen Zustand in Kubernetes. Standardmäßig werden mehrere Arten von Anwendungen unterstützt: Kustomize, Helm-Charts, Ksonnet, reines Jsonnet oder einfach Verzeichnisse mit YAML/JSON-Manifests.

Für die meisten Nutzer dieses Sets sollte das ausreichend sein, aber nicht für alle. Um die Bedürfnisse aller zufrieden zu stellen, bietet Argo CD die Möglichkeit, benutzerdefinierte Tools zu verwenden.

Zunächst interessiert die Möglichkeit, Unterstützung hinzuzufügen für qbec und git-crypt, die in dem vorherigen Artikel ausführlich behandelt wurden.

Bevor Sie mit der Konfiguration beginnen, müssen Sie zuerst verstehen, wie Argo CD genau funktioniert.

Für jede hinzugefügte Anwendung gibt es zwei Phasen:

  • init — die anfängliche Vorbereitung vor dem Deploy, hier kann alles Mögliche sein: Herunterladen von Abhängigkeiten, Entpacken von Geheimnissen und anderes.
  • generieren — das Ausführen des eigentlichen Befehls zur Generierung von Manifests, die Ausgabe muss ein gültiger YAML-Datenstrom sein, das ist genau das, was im Cluster angewendet wird.

Bemerkenswert ist, dass Argo diesen Ansatz für jeden Anwendungsfall anwendet, auch für Helm. Das bedeutet, dass Argo CD Helm nicht für das Deployen von Releases im Cluster verwendet, sondern nur zur Generierung von Manifests.

Argo kann von sich aus Helm-Hooks nativ verarbeiten, was es ermöglicht, die Anwendungslogik von Releases nicht zu stören.

QBEC

Qbec ermöglicht es, Anwendungen bequem mit Jsonnet zu beschreiben und bietet außerdem die Möglichkeit, Helm-Charts zu rendern. Da Argo CD Helm-Hooks ordentlich verarbeitet, erlaubt die Nutzung dieser Funktion in Argo CD noch genauere Ergebnisse.

Um die Unterstützung für qbec in Argo CD hinzuzufügen, sind zwei Dinge notwendig:

  • In der Konfigurationsdatei von Argo CD muss Ihr benutzerdefinierter Plugin und die Befehle zur Generierung von Manifests definiert sein.
  • Die benötigten Binaries müssen im Image verfügbar sein argocd-repo-server.

Die erste Aufgabe lässt sich recht einfach lösen:

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

(der Befehl init wird nicht verwendet)

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

Um die Binaries hinzuzufügen, wird empfohlen, ein neues Image zu erstellen, oder verwenden den Trick mit dem 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)"

Jetzt schauen wir uns an, wie das Manifest unserer Anwendung aussehen wird:

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

In der Variablen ENVIRONMENT geben wir den Namen der Umgebung an, für die die Generierung der Manifeste durchgeführt werden soll.

wenden wir an und schauen uns an, was wir erreicht haben:

Wir befassen uns mit Custom Tooling in Argo CD

Die Anwendung wurde bereitgestellt, großartig!

git-crypt

Git-crypt ermöglicht es, die transparente Verschlüsselung des Repositories zu konfigurieren. Dies ist eine einfache und sichere Methode, um vertrauliche Daten direkt in Git zu speichern.

Die Implementierung von git-crypt erwies sich als schwieriger.

Theoretisch könnten wir git-crypt unlock in der Init-Phase unseres benutzerdefinierten Plugins ausführen, aber das wäre nicht sehr praktisch, da es uns nicht erlauben würde, native Bereitstellungsmethoden zu verwenden. Beispielsweise bei Helm und Jsonnet verlieren wir die flexible GUI, die die Konfiguration der Anwendung erleichtert (values-Dateien usw.).

Genau aus diesem Grund wollten wir die Entschlüsselung des Repositories bereits in einer früheren Phase, beim Klonen, durchführen.

Da Argo CD bislang keine Möglichkeit bietet, Hooks für die Synchronisierung des Repositories zu definieren, mussten wir dieses Limit mit einem cleveren Shell-Skript umgehen, das den Befehl git ersetzt:

#!/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 führt git fetch bei jedem Bereitstellungsvorgang aus. Auf diesen Befehl werden wir die Ausführung anbringen git-crypt unlock zum Entsperren des Repositories.

Für Tests kannst du mein Docker-Image verwenden in dem bereits alles Notwendige enthalten ist:

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

Jetzt müssen wir darüber nachdenken, wie Argo unsere Repositories entschlüsseln wird. Nämlich, einen gpg-Schlüssel für ihn zu generieren:

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

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

$ gpg --batch --gen-key genkey-batch
gpg: WARNUNG: unsichere Eigentümerschaft im Homedir ' /home/argocd/.gnupg'
gpg: keybox '/home/argocd/.gnupg/pubring.kbx' erstellt
gpg: '/home/argocd/.gnupg/trustdb.gpg': trustdb erstellt
gpg: Schlüssel 8CB8B24F50B4797D als letztendlich vertrauenswürdig markiert
gpg: Verzeichnis '/home/argocd/.gnupg/openpgp-revocs.d' erstellt
gpg: Widerrufszertifikat als '/home/argocd/.gnupg/openpgp-revocs.d/9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D.rev' gespeichert

Wir speichern den Namen des Schlüssels 8CB8B24F50B4797D für die nächsten Schritte. Wir exportieren den Schlüssel:

$ gpg --list-keys
gpg: WARNUNG: unsichere Eigentümerschaft im Homedir '\/home\/argocd\/.gnupg'
\/home\/argocd\/.gnupg\/pubring.kbx
-------------------------------
pub   rsa3072 2020-09-04 [SC]
      9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D
uid           [ultimate] DEIN NAME <DEINE EMAIL@example.com>
sub   rsa3072 2020-09-04 [E]

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

Und wir fügen ihn als separaten geheimen Schlüssel hinzu:

# 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

Das Einzige, was uns bleibt, ist, ihn in den Container durchzureichen argocd-repo-server, dafür werden wir das Deployment bearbeiten:

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

Und wir ersetzen das bestehende gpg-keys Volumen durch projected, wo wir unseren geheimen Schlüssel angeben:

   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 lädt automatisch die gpg-Schlüssel aus diesem Verzeichnis beim Start des Containers, sodass er auch unseren privaten Schlüssel laden wird.

Lass uns überprüfen:

$ kubectl -n argocd exec -ti deploy\/argocd-repo-server -- bash
$ GNUPGHOME=\/app\/config\/gpg\/keys gpg --list-secret-keys
gpg: WARNUNG: unsichere Eigentümerschaft im Homedir '\/app\/config\/gpg\/keys'
\/app\/config\/gpg\/keys\/pubring.kbx
--------------------------------
sec   rsa2048 2020-09-05 [SC] [läuft ab: 2021-03-04]
      ED6285A3B1A50B6F1D9C955E5E8B1B16D47FFC28
uid           [ultimate] Anon Ymous (ArgoCD Schlüssel-Signierschlüssel) <noreply@argoproj.io>

sec   rsa3072 2020-09-03 [SC]
      9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D
uid           [ultimate] DEIN NAME <DEINE EMAIL@example.com>
ssb   rsa3072 2020-09-03 [E]

Großartig, der Schlüssel wurde geladen! Jetzt müssen wir nur noch Argo CD als Mitwirkenden in unser Repository hinzufügen, und es kann ihn automatisch im Flug entschlüsseln.

Importiere den Schlüssel auf den lokalen Computer:

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

Lass uns das Vertrauensniveau einstellen:

$ gpg --edit-key 8CB8B24F50B4797D
trust
5

Fügen wir argo als Mitwirkenden in unser Projekt hinzu:

$ git-crypt add-gpg-user 8CB8B24F50B4797D

Thematische Links:

Quelle: habr.com

60GB SSD 8Gb DDR4