Flux Operator. Практичний кейс GitOps: Ephemeral Environments

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

Друзі, на тему 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. Практичний інтенсив+

👍ПодобаєтьсяСподобалось7
До обраногоВ обраному3
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Гарний кейс. Зазначу, що іноді немає потреби створювати preview environment на зміни в репозиторії, наприклад достатньо тестів у пайплайні. У такому випадку можна створювати енв лише для pull request із зазначеним лейблом.

Підписатись на коментарі