Разбираемся с Custom Tooling в Argo CD


    Спустя некоторое время после написания первой статьи, где я ловко управлялся с jsonnet и гитлабом, я понял что пайплайны это конечно хорошо, но излишне сложно и неудобно.


    В большинстве случаев требуется типовая задача: "сгенерировать YAML и положить его в Kubernetes". Собственно, с чем Argo CD замечательно и справляется.


    Argo CD позволяет подключить Git-репозиторий и синкать его состояние в Kubernetes. По умолчанию есть поддержка нескольких видов приложений: Kustomize, Helm чарты, Ksonnet, голый Jsonnet или просто директории с YAML/JSON манифестами.


    Большинству пользователей этого набора будет достаточно, но не всем. Для того чтобы удовлетворить потребности всех и каждого в Argo CD имеется возможность использовать custom tooling.


    В первую очередь интересует возможность добавления поддержки qbec и git-crypt, которые с полна были рассмотренны в предыдущей статье.




    Прежде чем приступить к конфигурации, нужно сначала разобраться с тем как именно Argo CD работает.


    Для каждого добавленного приложения он имеет две фазы:


    • init — начальная подготовка перед деплоем, здесь может быть всё что угодно: скачивание зависимостей, распаковка секретов и другое.
    • generate — выполнение непосредственно команды генерации манифестов, вывод должен быть валидным YAML stream, это именно то, что будет применено в кластер.

    Примечательно то, что Argo применяет этот подход для любого типа приложений, в том числе и для Helm. То есть в Argo CD Helm не занимается деплоем релизов в кластер, а используется только для генерации манифестов.


    Со своей стороны Argo умеет нативно обрабатывать Helm-хуки, что позволяет не нарушать логики применения релизов.




    QBEC


    Qbec позволяет удобно описывать приложения с помощью jsonnet, а кроме того имеет возможность рендерить Helm-чарты, а так как Argo CD умеет нормально обрабатывать Helm-хуки, то использование этой возможности с Argo CD позволяет добиться ещё более корректных результатов.


    Для того чтобы добавить поддержку qbec в argocd нужно две вещи:


    • в конфиге Argo CD дожен быть определен ваш custom plugin и команды для генерации манифестов.
    • нужные бинарники должны быть доступны в образе argocd-repo-server.

    Первая задача решается довольно просто:


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

    (команда init не используется)


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

    Для добавления бинарников предлагается собрать новый образ, или использовать трюк с init-контейнером:


    # 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)"

    Теперь посмотрим как будет выглядеть манифест нашего приложения:


    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: examples/test-app
        targetRevision: fix-example
        plugin: 
          env: 
            - name: ENVIRONMENT
              value: dev
          name: qbec
        repoURL: https://github.com/kvaps/qbec
      syncPolicy: 
        automated: 
          prune: true

    В переменной ENVIRONMENT мы передаём имя окружения для которого нужно выполнять генерацию манифестов.


    применим и посмотрим что у нас получилось:



    приложение задеплоилось, отлично!




    git-crypt


    Git-crypt позволяет настроить прозрачное шифрование репозитория. Это простой и безопасный способ хранить конфиденциальные данные прямо в git.


    С имплементацией git-crypt оказалось сложнее.


    Теоретически мы могли бы выполнять git-crypt unlock на init-стадии нашего custom-плагина, но это не очень удобно, так как не позволило бы использовать нативные методы деплоя. Например в случае Helm и Jsonnet, мы теряем гибкий GUI-интерфейс который позволяет упростить настройку приложения (values-файлы и прочее).


    Именно по этому хотелось выполнять распечатывание репозитория еще на более ранней стадии, при клонировании.


    Так как на данный момент Argo CD не предоставляет возможности для описания каких-либо хуков для синхронизации репозитория, пришлось обойти это ограничение хитрым шелл скриптом-обёрткой, который заменяет собой команду 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 выполняет git fetch каждый раз перед операцией деплоя. Именно на эту команду мы и повесим выполнение git-crypt unlock для разблокировки репозитория.


    для тестов можете использовать мой docker-образ в котором уже есть всё необходимое:


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

    Теперь нам нужно подумать о том, как Argo будет расшифровывать наши репозитории. А именно сгенерировать gpg-ключ для него:


    $ kubectl exec -ti deploy/argocd-repo-server -- bash
    
    $ printf "%s\n" \
        "%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'

    Сохраним имя ключа 8CB8B24F50B4797D для дальнейших шагов. Экспортируем сам ключ:


    $ 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] YOUR NAME <YOUR EMAIL@example.com>
    sub   rsa3072 2020-09-04 [E]
    
    $ gpg --armor --export-secret-keys 8CB8B24F50B4797D

    И добавим его в виде отдельного секрета:


    # 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

    Единственное что нам осталось, это пробросить его в контейнер argocd-repo-server, для этого отредактируем deployment:


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

    И заменим существующий gpg-keys volume на projected, где и укажем наш секрет:


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

    Argo CD автоматически подгружает gpg-ключи из этой директории при старте контейнера, таким образом он загрузит и наш приватный ключ.


    проверим:


    $ 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 (ArgoCD key signing key) <noreply@argoproj.io>
    
    sec   rsa3072 2020-09-03 [SC]
          9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D
    uid           [ultimate] YOUR NAME <YOUR EMAIL@example.com>
    ssb   rsa3072 2020-09-03 [E]

    Отлично, ключ загружен! Теперь нам достаточно добавить Argo CD в наш репозиторий в качестве коллаборатора и он сможет автоматически расшифровывать его на лету.


    Импортируем ключ на локальный компьютер:


    $ GNUPGHOME=/app/config/gpg/keys gpg --armor --export 8CB8B24F50B4797D > 8CB8B24F50B4797D.pem
    $ gpg --import 8CB8B24F50B4797D.pem

    Настроим уровень доверия:


    $ gpg --edit-key 8CB8B24F50B4797D
    trust
    5

    Добавим argo в качестве коллаборатора в наш проект:


    $ git-crypt add-gpg-user 8CB8B24F50B4797D



    Ссылки по теме:


    Похожие публикации

    Средняя зарплата в IT

    113 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 5 503 анкет, за 2-ое пол. 2020 года Узнать свою зарплату
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 2

      0

      Очень круто — спасибо — но… почему не fluxcd?
      И вместо git-crypt ( с которым вроде как можно случайно промахнуться) они же предлагают sops...

        0
        Очень круто — спасибо — но… почему не fluxcd?

        Flux крутой, не не даёт такой гибкости как Argo CD.


        Кроме того, мне очень импонирует идея Argo не позволять утилитам выполнять деплой самостоятельно, а только генерацию манифестов.


        Таким образом Argo следит за создаваемыми ресурсами, а так же отображает их текущее состояние в красивой web-панельке.


        И вместо git-crypt ( с которым вроде как можно случайно промахнуться) они же предлагают sops...

        Почему не sops, сложилось исторически. Но по сути sops и git-crypt выполняют одинаковую работу. Разница в том, что sops поддерживает JSON и YAML и шифрует данные в них выборочно, а git-crypt шифрует файлы целиком вне зависимости от их формата.


        Что значит "случайно промахнуться"?

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое