
Спустя некоторое время после написания первой статьи, где я ловко управлялся с 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
Ссылки по теме:
