Спустя некоторое время после написания первой статьи, где я ловко управлялся с 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.yamldata: 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.yamlspec: 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/v1alpha1kind: Applicationmetadata: name: qbec-app namespace: argocdspec: 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 $ecGNUPGHOME=/app/config/gpg/keys git-crypt unlock 2>/dev/nullexit $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-batchgpg: WARNING: unsafe ownership on homedir '/home/argocd/.gnupg'gpg: keybox '/home/argocd/.gnupg/pubring.kbx' createdgpg: /home/argocd/.gnupg/trustdb.gpg: trustdb createdgpg: key 8CB8B24F50B4797D marked as ultimately trustedgpg: directory '/home/argocd/.gnupg/openpgp-revocs.d' createdgpg: revocation certificate stored as '/home/argocd/.gnupg/openpgp-revocs.d/9A1FF8CAA917CE876E2562FC8CB8B24F50B4797D.rev'
Сохраним имя ключа
8CB8B24F50B4797D
для дальнейших
шагов. Экспортируем сам ключ:
$ gpg --list-keysgpg: WARNING: unsafe ownership on homedir '/home/argocd/.gnupg'/home/argocd/.gnupg/pubring.kbx-------------------------------pub rsa3072 2020-09-04 [SC] 9A1FF8CAA917CE876E2562FC8CB8B24F50B4797Duid [ultimate] YOUR NAME <YOUR EMAIL@example.com>sub rsa3072 2020-09-04 [E]$ gpg --armor --export-secret-keys 8CB8B24F50B4797D
И добавим его в виде отдельного секрета:
# argocd-gpg-keys-secret.yamlapiVersion: v1kind: Secretmetadata: name: argocd-gpg-keys-secret namespace: argocdstringData: 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-keysgpg: 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] ED6285A3B1A50B6F1D9C955E5E8B1B16D47FFC28uid [ultimate] Anon Ymous (ArgoCD key signing key) <noreply@argoproj.io>sec rsa3072 2020-09-03 [SC] 9A1FF8CAA917CE876E2562FC8CB8B24F50B4797Duid [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 8CB8B24F50B4797Dtrust5
Добавим argo в качестве коллаборатора в наш проект:
$ git-crypt add-gpg-user 8CB8B24F50B4797D
Ссылки по теме: