ArgoCD помогает деплоить приложения в Kubernetes, используя GitOps подход, т.е. когда приложения, конфиги, манифесты и тому подобные данных хранятся в Git-репозитории.
Поддерживает работу с «голыми» манифестами Kubernetes,
ArgoCD запускает свой контроллер в Kubernetes-кластере, и отслеживает изменения в Git-репозиториях, синхронизируя приложения в кластере с их манифестами в репозитории.
Из особых вкусностей — SSO с SAML, что позволит интегрировать ArgoCD с нашей Okta, возможность деплоить на несколько кластеров, поддержка Kubernetes RBAC, шикарный WebUI и наличие CLI, интеграция с вебхуками Github, GitLab, etc, плюс Prometehus-метрики из коробки и
Планируем использовать его для деплоя Helm-чартов вместо Jenkins, см. Helm: пошаговое создание чарта и деплоймента из Jenkins.
По GitOps и ArgoCD есть очень толковый доклад от Igor Borodin на XPDays вот
И стоит почитать о недостатках GitOps в посте
Компоненты
ArgoCD состоит из трёх компонентов — API-сервер, Repository Server и Application Controller.
- API-сервер (pod: argocd-server): отвечает за управление всем приложением, вызов всех операций, управление данными доступа, которые хранятся в виде Kubernetes Secrets, аутентификацию и прочее
- Repository Server (pod: argocd-repo-server): хранит локальные копии данных из Git-репозиториев проектов и генерирует Kubernetes-манифесты
- Application Controller (pod: argocd-application-controller): мониторит приложения в Kubernetes, и сравнивает их состояние с тем, которое описано в репозитории, плюс отвечает за вызов PreSync, Sync, PostSync хуков
Установка ArgoCD CLI
В macOS:
В Linux — из Github:
Проверяем:
Запуск ArgoCD в Kubernetes
Ну и запустим ArgoCD. Тут всё просто — используем готовый манифест, который создаст CRD, ServiceAccount-ы, RBAC-роли и биндинги, ConfigMaps, Secrets, Services и Deployments.
Хотя вообще должен быть готовый Helm-чарт — но пока сделаем так, как описано в
Проще запускать в неймспейсе argocd, который предлагает сам ArgoCD в документации, но мы простых путей не ищем, поэтому — создаём свой namespace:
Деплоим ресурсы:
Редактируем Sevrice argcd-server — меняем ему тип на LoadBalancer, что бы получить доступ к WebUI из мира:
Находим его URL:
Пароль ArgoCD генерируется во время установки, и по дефолту задан равным имени пода — получаем его:
Логинимся через CLI, на ошибку сертификата пока внимания не обращаем:
Меняем пароль:
Открываем WebUI, снова игнорируем ошибку сертификата — сейчас всё настроим. Логинимся:
LoadBalancer, SSL и DNS
Окей — всё запустилось, настроим нормальное имя и SSL.
AWS ALB и ELB не поддерживают gRPC, см.
Сертификат получаем в
Качаем файл манифеста:
Находим Service argocd-server:
--- apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/component: server app.kubernetes.io/name: argocd-server app.kubernetes.io/part-of: argocd name: argocd-server spec: ports: - name: http port: 80 protocol: TCP targetPort: 8080 - name: https port: 443 protocol: TCP targetPort: 8080 selector: app.kubernetes.io/name: argocd-server
В annotations добавляем service.beta.kubernetes.io/aws-load-balancer-ssl-cert
, в spec.type
— тип LoadBalancer
, и ограничиваем доступ через loadBalancerSourceRanges
:
--- apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/component: server app.kubernetes.io/name: argocd-server app.kubernetes.io/part-of: argocd name: argocd-server annotations: service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-east-1:534***385:certificate/ddaf55b0-***-53d57c5ca706" spec: type: LoadBalancer loadBalancerSourceRanges: - "31.***.***.117/32" - "194.***.***.24/29" ports: - name: http port: 80 protocol: TCP targetPort: 8080 - name: https port: 443 protocol: TCP targetPort: 8080 selector: app.kubernetes.io/name: argocd-server
Деплоим:
Проверяем ELB SSL:
Создаём DNS:
Открываем URL — и ловим ERR_TOO_MANY_REDIRECTS:
ArgoCD SSL: ERR_TOO_MANY_REDIRECTS
Гуглим, находим
Возвращаемся к install.yaml
, в Deployment
argocd-server добавляем --insecure
:
--- apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubernetes.io/component: server app.kubernetes.io/name: argocd-server app.kubernetes.io/part-of: argocd name: argocd-server spec: selector: matchLabels: app.kubernetes.io/name: argocd-server template: metadata: labels: app.kubernetes.io/name: argocd-server spec: containers: - command: - argocd-server - --staticassets - /shared/app - --insecure ...
Снова деплоим, и проверяем:
Окей — тут готово.
ArgoCD: деплой из Github
Ну и не будем далеко уходить от гайда — задеплоим тестовое приложение. Helm-чарт будет в следующей части.
Кликаем New App, указываем имя и Project == default:
В Git указваем URL
В Destination — https://kubernetes.default.svc и default namespace, жмём Create:
Вроде бы создало, но почему в Sync Status — Unknown?
Что-то пошло не так:
Пробуем sync
— и тоже не работает:
ArgocD: ComparisonError failed to load initial state of resource
Собственно, проще искать причину по ошибке «User «system:serviceaccount:dev-1-devops-argocd-ns:argocd-application-controller» cannot list resource «pods» in API group «» at the cluster scope«.
Проверяем ServiceAccount argocd-application-controller (пригодилось Kubernetes: ServiceAccounts, JWT-токены, аутентификация и RBAC-авторизация):
Да, наш User system:serviceaccount:dev1-devops-argocd-ns:argocd-application-controller
есть.
И этому ServiceAccount мапится ClusterRoleBinding argocd-application-controller:
Но прав на выполнение list pods
у этого ServiceAccount нет:
Хотя в ClusterRole все права есть:
--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/component: application-controller app.kubernetes.io/name: argocd-application-controller app.kubernetes.io/part-of: argocd name: argocd-application-controller rules: - apiGroups: - '*' resources: - '*' verbs: - '*' - nonResourceURLs: - '*' verbs: - '*'
Проверяем ClusterRoleBinding ещё раз, теперь с выводом всего через -o yaml
:
namespace: argocd
— «Ага, вот эти ребята!» (c)
Находим две ClusterRoleBinding в install.yaml
— argocd-application-controller и argocd-server, меняем неймспейс:
--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/component: application-controller app.kubernetes.io/name: argocd-application-controller app.kubernetes.io/part-of: argocd name: argocd-application-controller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: argocd-application-controller subjects: - kind: ServiceAccount name: argocd-application-controller namespace: dev-1-devops-argocd-ns --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/component: server app.kubernetes.io/name: argocd-server app.kubernetes.io/part-of: argocd name: argocd-server roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: argocd-server subjects: - kind: ServiceAccount name: argocd-server namespace: dev-1-devops-argocd-ns
Собственно, вот, почему в начале говорил, что проще делать в дефолтном нейспейсе — если деплоить в кастомный, то придётся тут задавать неймспейсы. Но у нас свои naming convention для неймспейсов, стараемся их соблюдать.
Хотя тут ещё зависит от того, как деплоить сам ArgoCD — на каждый кластер свою копию, или делать центральный инстанс ArgoCD — и с него деплоить на разные кластера. Плюс, если делать через Helm-чарт — там наверняка можно в параметрах указывать.
Передеплоиваем, проверяем:
Пробуем ещё раз sync
:
Работает:
И логи пода:
Следующий шаг — разобраться с деплоем Helm-чартов, и как прикрутить работу с Helm Secrets — там придётся или билдить кастомный Docker-образ с ArgoCD, в котором будет установлен Helm-плагин secrets — или делать через Kubernetes InitContainers — варианты есть. Посмотрим, как проще.