Flux Operator. Практичний кейс GitOps: Ephemeral Environments
Друзі, на тему GitOps, інфраструктури як код (IaC) та автоматизації процесу розробки, хочу запропонувати вам практичний кейс, який доволі затребуваний сьогодні.
На цю тему ми навіть проводили хакатон на курсі DevOps та Kubernetes. Практичний інтенсив+ — «Aвтоматичне розгортання Preview Environments за допомогою ChatOps.» І якщо раніше ми робили для цього окрему кастомну автоматизацію, наприклад, пайплайн (pipeline) із скриптами або chatbot, то сьогодні таку функціональність додано до Flux: відкриваєш Pull Request або створюєш нову feature branch і GitOps інструменти розгорнуть необхідну інфраструктуру автоматично.
Автоматизація розгортання preview environments
Preview environments — це тестові середовища, які автоматично створюються для кожного pull request. Це дозволяє розробникам перевіряти свої зміни в ізольованому середовищі, не впливаючи на основну систему. Раніше для цього потрібно було створювати окрему автоматизацію, але зараз такий функціонал вбудований в сучасні GitOps інструменти.
Система працює наступним чином: коли розробник створює pull request, автоматично створюється нове середовище з його змінами. Після завершення перевірки та мержу (merge) pull request, середовище автоматично видаляється. Це значно прискорює процес розробки та тестування.
Я підготував детальний покроковий план в окремому репозиторії, з яким ви можете працювати самостійно. А зараз пропоную огляд нової функціональності самого рішення Ephemeral Environments, яке вже після першого виконання ви можете продавати на співбесідах. Я буду фокусуватися тільки на важливих деталях, але буде трохи коду.
Ключові компоненти
Flux Operator — це GitOps оператор для Kubernetes, який автоматизує процес розгортання додатків. Він відстежує зміни в Git-репозиторії та автоматично застосовує їх до кластера.
Основна перевага Flux — це автоматизація життєвого циклу додатків. Коли в репозиторії з’являються нові зміни, Flux автоматично розгортає їх в кластері. Це дозволяє підтримувати консистентність між кодом в репозиторії та станом кластера.
Gateway API — це новий стандарт для маршрутизації в Kubernetes, який замінює традиційний Ingress. Він надає більш гнучкі та потужні можливості для маршрутизації трафіку на рівнях L4-L7.
У нашому кейсі Gateway API використовується разом з Envoy Proxy для маршрутизації трафіку до preview environments. Це дозволяє створювати унікальні URL для кожного pull request та автоматично налаштовувати маршрутизацію.
OCI Registry — це універсальне сховище для різних типів артефактів. На відміну від традиційних container registries, він може зберігати не тільки контейнери, але й інші типи артефактів, такі як Helm-чарти або Terraform-код.
У нашому кейсі OCI Registry використовується для зберігання всіх артефактів, необхідних для розгортання. Він інтегрований з CI/CD, що дозволяє автоматично пушити (push) нові версії артефактів при кожному коміті (commit).
Процес розгортання
Перший крок — готуємо робоче середовище з усіма необхідними інструментами.
Я використовую GitHub Codespaces, OpenTofu, K9S. Це дозволяє ефективно управляти демо кластером та розгортати додатки.
# Install OpenTofu curl -fsSL https://get.opentofu.org/install-opentofu.sh | sh -s -- --install-method standalone # Install K9S for cluster management curl -sS https://webi.sh/k9s | sh
Kubernetes, Flux та Gateway API
Наступний крок — встановлення та налаштування Flux Operator та Gateway API. Flux оператор встановлюється за допомогою helm_release, а його конфігурація зберігається в OCI репозиторії.
Приклад інфраструктурного коду (повний вихідний код можна знайти в репо):
# ========================================== # Bootstrap Flux Operator # ========================================== resource "helm_release" "flux_operator" { depends_on = [kind_cluster.this] name = "flux-operator" namespace = "flux-system" repository = "oci://ghcr.io/controlplaneio-fluxcd/charts" chart = "flux-operator" create_namespace = true } # ========================================== # Bootstrap Flux Instance # ========================================== resource "helm_release" "flux_instance" { depends_on = [helm_release.flux_operator] name = "flux-instance" namespace = "flux-system" repository = "oci://ghcr.io/controlplaneio-fluxcd/charts" chart = "flux-instance" set { name = "distribution.version" value = "=2.5.x" } } # ========================================== # Bootstrap Envoy Gateway # ========================================== resource "helm_release" "envoy_gateway" { depends_on = [kind_cluster.this] name = "eg" namespace = "envoy-gateway-system" repository = "oci://docker.io/envoyproxy" chart = "gateway-helm" version = "v1.3.2" create_namespace = true }
Далі — налаштування базової інфраструктури. Для демонстрації використовується KinD кластер, який дозволяє запустити Kubernetes локально. GITHUB_TOKEN нам знадобиться для відслідковування змін та роботи з приватними репозиторіями.
# Navigate to bootstrap directory cd bootstrap # Initialize OpenTofu tofu init # Set up GitHub authentication # You will be prompted to enter your GitHub token securely export TF_VAR_github_token="$GITHUB_TOKEN" # Apply the infrastructure configuration tofu apply
OpenTofu створить наш демо кластер та встановить всі необхідні компоненти. Але ключові налаштування саме для Ephemeral Environments я виніс окремими файлами для наглядності.
Конфігурація Gateway API налаштовується разом з Envoy Proxy для маршрутизації трафіку.
Створимо необхідні ресурси: Gateway Class, Gateway. Це дозволяє налаштувати маршрутизацію для preview environments (вихідний код).
# Install Gateway API components k apply -f ../gatewayapi # Verify services k get svc
Опціонально для KinD встановимо Load Balancer.
В даному випадку кластер не в інфраструктурі клауд провайдера, тому адресу отримати немає де. Але ми скористаємося проектом який реалізує локальний сервіс лоад балансера — cloud-provider-kind надає agnostic рішення для всіх функцій Kubernetes, які залежать від хмарного провайдера.
Встановимо та запустимо cloud-provider-kind і отримаємо зовнішню адресу для лоад балансера. Це буде адреса локального інтерфейса на нашому github codespaces, яку ми за необхідністю можемо зробити доступною в паблік (як? ngrok).
wget https://github.com/kubernetes-sigs/cloud-provider-kind/releases/download/v0.6.0/cloud-provider-kind_0.6.0_linux_amd64.tar.gz tar -xvzf cloud-provider-kind_0.6.0_linux_amd64.tar.gz -C /go/bin /go/bin/cloud-provider-kind >/dev/null 2>&1 &
Deploy Application Components
Так, з інфраструктурою розібралися. Розгорнемо реліз. Це може бути будь-який аплікейшен, але в даному випадку зверніть увагу, ми налаштували HelmRelease який зберігається в OCI реєстрі, тобто хелм чарт як образ контейнеру.
--- apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: app-kbot namespace: flux-system spec: interval: 1m releaseName: app-kbot targetNamespace: default chartRef: kind: OCIRepository name: app-kbot namespace: flux-system --- apiVersion: source.toolkit.fluxcd.io/v1beta2 kind: OCIRepository metadata: name: app-kbot namespace: flux-system spec: interval: 1m url: oci://ghcr.io/den-vasyliev/charts/kbot ref: semver: ">2.2.0"
Це аплікація, що містить темплейти для deployment, service, HttpRoute для gateway api, та розширений github workflow для Pull Requests. Workflow збирає образ контейнера для тестування feature branches та окремо для релізу.
В результаті два артефакти: фінальний образ контейнеру та helm пакет.
Розгорнемо реліз. Буде створено ресурси helmRelease та OCIRepository. Flux миттєво підхватить конфігурацію і створить deployment в неймспейсі default. Також створено новий для нас обʼєкт — це httproute. В термінології gateway api це інструкція як маршрутизувати трафік для цього сервісу.
# Deploy release configuration k apply -f ../release
Verify Deployment
Для перевірки розгортання ви можете перевірити IP-адресу LoadBalancer і протестувати запитом:
# Get LoadBalancer IP LB_IP=$(kubectl get svc -o jsonpath='{.items[?(@.metadata.name matches "envoy-envoy-gateway.*")].status.loadBalancer.ingress[0].ip}' -n envoy-gateway-system) # Test the main endpoint curl $LB_IP -HHost:kbot.example.com
Реліз готовий та доступний. Можемо рахувати prod підняли. Тобто зараз будь-яка зміна версії пакету автоматично буде виїзжати в prod.
Preview Environment
Але перед тим як нова версія дійде до «проду», нам треба налаштувати preview середовище для перевірки, валідації та тестів.
Підготуємо оператор до використання Preview Environment. Спочатку ми створимо спеціальний неймспейс app-preview, в якому будуть розгорнуті всі додаткі для GitHub Pull Requests. Ми також створимо сервісний акаунт для Flux, який обмежить права доступу до неймспейс app-preview та надасть доступ до CRD у API-групі Kubernetes.
# Deploy preview configuration k apply -f ../preview # Create GitHub authentication secret in preview namespace kubectl create secret generic github-auth \ --from-literal=username=git \ --from-literal=password=${GITHUB_TOKEN} \ -n app-preview
Конфігурація Ephemeral Environments це два ресурси:
ResourceSetInputProvider — який налаштовує Flux Operator який репозиторій сканувати на наявність PR, позначених для preview. В даному випадку — це репозиторій нашої аплікації
apiVersion: fluxcd.controlplane.io/v1 kind: ResourceSetInputProvider metadata: name: app-pull-requests-kbot namespace: app-preview annotations: fluxcd.controlplane.io/reconcileEvery: "1m" spec: type: GitHubPullRequest url: https://github.com/den-vasyliev/kbot-src secretRef: name: github-auth defaultValues: chart: "./helm"
Та ресурс ResourceSet — який отримає вхідні дані від ResourceSetInputProvider та може містити всі необхідні сервіси, залежності та компоненти, необхідні для запуску та тестування аплікації. Такий собі sandbox або Preview Environment.
apiVersion: fluxcd.controlplane.io/v1 kind: ResourceSet metadata: name: app-kbot-preview namespace: app-preview spec: serviceAccountName: flux inputsFrom: - apiVersion: fluxcd.controlplane.io/v1 kind: ResourceSetInputProvider name: app-pull-requests-kbot resources: - apiVersion: source.toolkit.fluxcd.io/v1 kind: GitRepository metadata: name: app-<< inputs.id >> namespace: app-preview spec: provider: generic # or 'github' if using GitHub App interval: 1m url: https://github.com/den-vasyliev/kbot-src ref: commit: << inputs.sha >> secretRef: name: github-auth - apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: app-<< inputs.id >> namespace: app-preview annotations: event.toolkit.fluxcd.io/preview-url: "https://quietly-just-ferret.ngrok-free.app/<< inputs.branch >>" event.toolkit.fluxcd.io/branch: << inputs.branch | quote >> event.toolkit.fluxcd.io/author: << inputs.author | quote >> spec: serviceAccountName: flux interval: 1m releaseName: app-<< inputs.id >> chart: spec: chart: << inputs.chart >> reconcileStrategy: Revision sourceRef: kind: GitRepository name: app-<< inputs.id >> values: gateway: path: /pr-<< inputs.id >> image: tag: << inputs.sha >>
Наведений ResouceSet згенерує Flux GitRepository і HelmRelease для кожного відкритого PR.
Номер PR, переданий як* << inputs.id >>*, використовується як суфікс імені для об’єктів Flux, а також використовується для створення імені хоста, з якого можна отримати доступ до аплікації.
Останній SHA комміту передається як << inputs.sha >>, SHA використовується для встановлення тегу у значеннях релізу helm.
Також ми визначаємо який формат URL генерувати для нотифікацій, коли preview буде розгорнуто, ми отримаємо унікальну адресу — це може бути спеціальний домен та унікальний шлях, за яким розробник зможе отримати ексклюзивний доступ.
event.toolkit.fluxcd.io/preview-url: "https://quietly-just-ferret.ngrok-free.app/<< inputs.branch >>"
Все готово — розгортаємо preview
Перейдемо в репозиторій та внесемо довільні зміни, наприклад у версію хелм чарту: appVersion 2.2.5.
Коміт зробимо в нову фічебренчу, назву залишу автоматично згенеровану. Після цього відкриємо Pull Request
Це запустить пайплайн GitHub Actions — перевіремо процес зборки артефакту.
Якщо заглянемо у workflow: пайплайн складається з декількох стандартних кроків по екстракту версій і хешів комітів для тегів створеного контейнер іміджу, і по завершенню, ми очікуємо на контейнер імідж зібраний та запушений у контейнер реєстр спеціально під PR-41.
Також автоматично було створено маршрут для gateway з номером PR в назві — який також використовується як унікальний шлях PathPrefix.
Давайте перевіримо цей шлях за допомогою запиту curl. Додамо до адреси лоадбалансеру /pr і номер Pull Request.
# Test preview endpoint # Note: use your PR number e.g. 41 curl $LB_IP/pr-41 -HHost:kbot.example.com
Отримали відповідь із версією та коротким комітом, що збігається з комітом в Pull Request:
Змержимо PullRequest, cтворимо новий реліз для останнього мержа. Для цього зробимо тег для нової версії, згенеруємо реліз ноутс та запаблішемо реліз.
Пайплайн добіг до кінця, повернемося до терміналу та почекаємо коли flux проведе реконсіляцію (reconcilation) helmrelease, адже в реєстрі зʼявиться нова версія хелм чарту, а в свою чергу там буде посилання на нову версію іміджу, Flux затягне та розгорне нову версію аплікації.
В результаті перевіримо як preview автоматично буде видалено, а prod оновиться на нову версію. Як ми побачимо — pod оновився і піднявся, можемо перевірити версії релізів: версія повинна бути 2.2.5, і співпадати з версією іміджу.
Готовий кейс
Цей кейс представляє собою повний цикл розробки, від створення pull request до розгортання в продакшн. Він включає всі необхідні компоненти для автоматизації процесу розробки: CI/CD пайплайни, preview environments, маршрутизацію та нотифікації.
Кейс можна використати як приклад на співбесідах, демонструючи знання сучасних інструментів та підходів та автоматизації. Також може служити основою для створення подібних систем в реальних проектах.
PS. Завершивши статтю, ще раз зрозумів чому я пишу відоси, а не лонгріди... і записав відео для слухачів курсу DevOps та Kubernetes. Практичний інтенсив+
2 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарів