Разбираемся с 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: qbec-app     plugin:        env:          - name: ENVIRONMENT           value: default       name: qbec     repoURL: https://github.com/kvaps/argocd-play   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:              defaultMode: 420              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 в наш репозиторий в качестве коллаборатора и он сможет автоматически расшифровывать его на лету.

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

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

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

$ gpg --edit-key 8CB8B24F50B4797D trust 5

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

$ git-crypt add-gpg-user 8CB8B24F50B4797D


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

ссылка на оригинал статьи https://habr.com/ru/post/517966/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *