Produkty Poradenství O nás Blog Kontakt English
arrow_back Zpět na blog

Přestaňte bourat dům kvůli výměně nábytku: Proč je GitOps lepší než push-based deployment

Přestaňte bourat dům kvůli výměně nábytku: Proč je GitOps lepší než push-based deployment

Chcete nasadit novou verzi API. Změna jednoho řádku: posunout image tag z v1.4.2 na v1.4.3. S GitOps setupem pushnete do Gitu a za 30 sekund je cluster srovnaný. S push-based přístupem, který stále vidím v produkci — Helm charty publikované Terraformem — spustíte pipeline, která naplánuje celou infrastrukturu, vyhodnotí každý resource, čeká na schválení a pak aplikuje změnu. To je jako bourat dům kvůli výměně nábytku.

A přesto push-based deployment přes Terraform zůstává pozoruhodně populární. Manažeři ho mají rádi, protože vidí tlačítko “Deploy” v CI/CD rozhraní. Inženýři ho používají ze setrvačnosti, protože Terraform už spravuje cluster. Ale cena je reálná — v délce pipeline, v blast radius, v provázanosti a v operační odolnosti.

Jak funguje push-based deployment

Typický push-based setup vypadá takto:

sequenceDiagram participant Dev as Vývojář participant CI as CI/CD Pipeline participant TF as Terraform participant K8s as Kubernetes Cluster Dev->>CI: Merge PR / Klik na "Deploy" CI->>TF: terraform plan Note over TF: Vyhodnocuje VŠECHNY resources:
VPC, DNS, databáze,
Helm releasy, secrety... TF->>TF: Plan: 1 ke změně CI->>CI: Čekání na manuální schválení CI->>TF: terraform apply TF->>K8s: helm upgrade my-api Note over K8s: Image aktualizován na v1.4.3

Terraform vlastní všechno — GKE cluster, VPC, Cloud SQL instanci, DNS záznamy a Helm releasy. Pro jakoukoli změnu musíte spustit celou pipeline. I když se změnil jen image tag, Terraform musí:

  1. Inicializovat — stáhnout providery, moduly a state soubor
  2. Naplánovat — vyhodnotit každý resource ve statu oproti reálnému světu
  3. Čekat — někdo klikne na “Approve” (protože infrastrukturní změny přeci neaplikujete automaticky, že?)
  4. Aplikovat — provést změnu

Pro středně velkou infrastrukturu to trvá 5-15 minut. Pro velké setupy se stovkami resources to může být 30+. To všechno kvůli aktualizaci jednoho container tagu.

Jak funguje GitOps (pull-based)

S Flux CD cluster sleduje váš Git repozitář a průběžně srovnává skutečný stav s požadovaným:

sequenceDiagram participant Dev as Vývojář participant Git as Git Repozitář participant Flux as Flux CD (v clusteru) participant K8s as Kubernetes Cluster Dev->>Git: Push: image tag → v1.4.3 Note over Flux: Detekuje změnu
(polling nebo webhook) Flux->>Git: Pull nejnovějších manifestů Flux->>K8s: Aplikuje diff: aktualizace image tagu Note over K8s: Image aktualizován na v1.4.3 Flux->>Flux: Reconciliace dokončena ✓

Žádná spuštěná pipeline. Žádné přehodnocování infrastruktury. Žádné manuální schvalování pro už zrevidovaný Git commit. Flux viděl změnu v Gitu, spočítal diff oproti clusteru a aplikoval jen to, co se změnilo. Celý cyklus trvá 30 sekund až 2 minuty.

Skutečná cena push-based deploymentu

1. Všechno je provázané

Když Terraform spravuje infrastrukturu i deployment aplikací, sdílejí state soubor, pipeline a blast radius. Bug v Helm chart šabloně může zablokovat kritickou změnu VPC. Timeout databázové migrace může zabránit nesouvisejícímu deploymentu aplikace. Všechno jde přes jedno úzké hrdlo.

graph TD subgraph "Push: Jedna pipeline" P[Běh pipeline] --> VPC[VPC/Síť] P --> DB[Cloud SQL] P --> DNS[DNS záznamy] P --> GKE[GKE Cluster] P --> H1[Helm: API] P --> H2[Helm: Frontend] P --> H3[Helm: Worker] end subgraph "GitOps: Oddělené zodpovědnosti" TF[Terraform] --> VPC2[VPC/Síť] TF --> DB2[Cloud SQL] TF --> DNS2[DNS záznamy] TF --> GKE2[GKE Cluster] Flux[Flux CD] --> K1[API] Flux --> K2[Frontend] Flux --> K3[Worker] end style P fill:#e53935,color:#fff style TF fill:#2e7d32,color:#fff style Flux fill:#1565c0,color:#fff

S GitOps Terraform spravuje infrastrukturu, která se mění zřídka (sítě, clustery, databáze), a Flux spravuje workloady, které se mění často (aplikace, konfigurace). Každý má svůj vlastní životní cyklus, svou kadenci, svou failure doménu.

2. Žádné self-healing

Push-based deployment je typu vystřel a zapomeň. Terraform aplikuje změnu a odejde. Pokud někdo spustí kubectl delete deployment my-api nebo výpadek nodu způsobí přeplánování podů se zastaralou konfigurací, Terraform to neví a je mu to jedno — stav kontroluje jen když ho spustíte znovu.

Flux průběžně reconciluje. Každých pár minut porovnává stav clusteru s Git repozitářem a opravuje jakýkoli drift. Někdo ručně zmenšil váš deployment na 1 repliku? Flux to vrátí. Někdo aplikoval hotfix přímo přes kubectl? Flux to přepíše tím, co je v Gitu. Git repozitář je jediný zdroj pravdy a cluster je jeho odrazem.

Tohle není teoretický benefit. V produkci jsme viděli:

  • Vývojáře, který přes kubectl apply nasadil debug konfiguraci, která se nikdy nevrátila — Flux ji zachytil v příštím reconciliačním cyklu
  • Chybnou CI/CD konfiguraci, která nasadila starý image tag — Flux se vrátil k verzi deklarované v Gitu během minut
  • Výměnu nodu, která nastartovala pody s cachovanou starou konfigurací — Flux znovu aplikoval správné manifesty

3. Pomalá zpětná vazba

S push-based deploymentem vypadá zpětnovazební smyčka takto:

  1. Merge PR → 2. CI buildí image → 3. CI spustí Terraform → 4. Terraform plánuje (5 min) → 5. Schválení (?) → 6. Terraform aplikuje (3 min) → 7. Deployment hotový

Celkem: 10-20 minut, za předpokladu žádné fronty a žádného schvalovacího bottlenecku.

S GitOps:

  1. Merge PR → 2. CI buildí image → 3. CI aktualizuje Git manifest → 4. Flux reconciluje (30 sek)

Celkem: čas CI buildu plus 30 sekund. Samotný deployment je prakticky okamžitý.

4. Iluze “klikni pro deploy”

Manažeři často preferují push-based deployment, protože nabízí viditelný kontrolní bod: tlačítko v Jenkinsu, manuální schválení v GitHub Actions, “Run Pipeline” v GitLabu. Cítí se jako kontrola.

Ale co to tlačítko vlastně kontroluje? Kontroluje kdy se změna aplikuje — ne co se aplikuje. To “co” už bylo rozhodnuto, když byl PR mergnutý. Schvalovací krok je kontrola Terraform plánu, který říká “1 resource ke změně: helm_release.my_api” — což vám neřekne nic o tom, jestli je nový image tag bezpečný k nasazení. Skutečná kontrola proběhla během PR.

GitOps nahrazuje tuto divadelní kontrolu skutečnou kontrolou: Git historií. Každá změna je commit. Každý commit je kontrolovatelný, vratitelný a auditovatelný. Chcete vrátit zpět? git revert. Chcete vědět, kdo co nasadil a kdy? git log. Chcete schvalovací bránu? Použijte branch protection a povinné reviewery na GitOps repozitáři.

Tlačítko “Deploy” je bezpečnostní deka. Git log je záchranná síť.

5. State soubor: zamčený bucket, na který vývojáři nemají přístup

Terraform state soubory jsou pro deployment aplikací přítěží. Obsahují kompletní stav každého spravovaného resource — VPC ID, databázová hesla, IAM bindingy — takže přirozeně je state bucket zamčený. Vývojáři k němu nemají přístup. A neměli by mít. Ten state soubor obsahuje produkční secrets celé infrastruktury.

Ale když Helm releasy žijí ve stejném state souboru, právě jste udělali z deploymentu aplikací privilegovanou infrastrukturní operaci. Vývojář, který chce nasadit svou službu, nemůže lokálně spustit terraform plan pro ladění neúspěšného deploymentu. Nemůže inspektovat state, aby pochopil, proč si Terraform myslí, že Helm release je v určitém stavu. Je odříznut od vlastní deployment pipeline bezpečnostní hranicí, která byla navržena pro infrastrukturu, ne pro aplikace.

Výsledek: vývojáři zakládají tikety s žádostí, aby platformní tým “spustil pipeline” nebo “zkontroloval, proč je deployment zaseknutý.” Platformní tým se stává deployment bottleneckem — ne proto, že by chtěl, ale protože ho k tomu architektura nutí.

A když se něco pokazí, pokazí se to způsoby, které je těžké odladit zvenčí:

  • Terraform “ví”, že Helm release je na verzi X, ale cluster má verzi Y, protože někdo ručně spustil helm upgrade. Příští terraform plan ukáže matoucí diff — nebo tiše naplánuje návrat release do zastaralého stavu.
  • State soubor je zamčený, protože předchozí běh pipeline vypršel. Nikdo nemůže nasadit nic, dokud někdo s přístupem k bucketu nespustí terraform force-unlock — což samo vyžaduje infrastrukturní credentials.
  • Helm release je ve statu Terraformu označený jako “failed” po timeoutu, ale pody ve skutečnosti běží v pořádku. Terraform chce release vytvořit znovu od nuly. To je to bourání domu znovu.

Flux nemá žádný state soubor. Jeho stav je Git repozitář. Vývojáři mají plný přístup. Není co zamknout, není co poškodit, není co force-unlockovat ve 2 ráno.

6. Helm releasy zaseknuté v očistci

Tohle si zaslouží vlastní sekci, protože je to nejčastější hašení požárů v push-based setupech. Helm udržuje svůj vlastní release state jako Kubernetes Secrety v clusteru. Terraform udržuje samostatný pohled na tento stav ve svém state souboru. Když se tyto dva pohledy rozejdou — a rozejdou se — vstupujete do Helm očistce.

Vypadá to takto:

Text
Error: UPGRADE FAILED: another operation (install/upgrade/rollback)
is in progress

Předchozí helm upgrade vypršel (třeba readiness proba trvala příliš dlouho, třeba cluster byl pod zátěží). Helm označil release jako pending-upgrade. Terraform s tím neumí pracovat. Pipeline selže. Každý následující běh pipeline selže se stejnou chybou.

Oprava? Někdo s přístupem ke clusteru musí ručně spustit:

Bash
# Varianta A: Vrátit se na poslední úspěšný release
helm rollback my-api -n production

# Varianta B: Pokud i rollback selže, nukleární varianta
kubectl delete secret -n production -l name=my-api,owner=helm
# Pak znovu spustit pipeline a doufat

Tohle je hašení infrastrukturních požárů kvůli tomu, co měl být rutinní deployment aplikace. A vyžaduje to kubectl přístup k produkčnímu clusteru — přesně to, od čeho měl push-based deployment abstrahovat.

S Flux je zaseknutý HelmRelease samo-opravitelný. Flux opakuje s exponenciálním backoffem, a pokud je release skutečně rozbitý, opravíte manifest v Gitu a Flux opravu aplikuje. Žádný ruční helm rollback, žádné mazání secretů, žádná panika “kdo má kubectl přístup do produkce?” Pokud potřebujete zasáhnout, flux suspend a flux resume vám dají čistou kontrolu bez toho, abyste se dotýkali interního stavu Helmu.

7. Helm je pro operátory, ne pro vaše aplikace

Tady je nepopulární názor: většina týmů by neměla psát Helm charty pro vlastní aplikace.

Helm je package manager. Existuje proto, aby třetí strany mohly distribuovat komplexní, konfigurovatelný software — Nginx ingress controller s 200 konfiguračními možnostmi, Prometheus stack s desítkami vzájemně závislých komponent, databázový operátor s vlastními CRD. Helmův šablonovací engine ({{ .Values.replicaCount }}) dává smysl, když neznáte cílové prostředí.

Ale vy své prostředí znáte. Aplikaci jste napsali vy. Víte, kolik replik potřebuje, jaké porty vystavuje, jaké proměnné prostředí čte. Zabalit jednoduchý Deployment + Service + Ingress do Helm chartu přidává šablonovací vrstvu, která:

  • Zakrývá, co se skutečně nasazuje. Výstup helm template je to, co dorazí do clusteru, ale nikdo ho nečte. Vývojáři editují values.yaml a doufají, že šablony udělají správnou věc.
  • Vytváří indirection bez benefitu. Vaše templates/deployment.yaml je Go šablona, která se vykreslí do… Deploymentu. Mohli jste rovnou napsat Deployment přímo.
  • Dělá diffy nečitelné. PR, který mění Helm hodnotu, ukáže jednořádkový diff ve values.yaml. Revieweři nevidí skutečnou změnu manifestu bez lokálního spuštění helm template.
  • Přidává ceremonii balíčkování a verzování. Chart.yaml, verze chartů, chart repozitáře nebo OCI registry — samá ceremonie pro software, který má přesně jednoho spotřebitele: váš vlastní cluster.

Porovnejte to s plain Kustomize, který Flux používá nativně:

YAML
# kustomization.yaml — co vidíte, to se aplikuje
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
  - ingress.yaml
images:
  - name: my-api
    newTag: v1.4.3
YAML
# deployment.yaml — plain Kubernetes, žádné šablonování
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-api
  template:
    metadata:
      labels:
        app: my-api
    spec:
      containers:
        - name: my-api
          image: my-api  # tag nastavený v kustomization.yaml
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 100m
              memory: 128Mi

Žádné šablony. Žádné values soubory. Žádné {{ if .Values.ingress.enabled }}. Manifesty jsou reálné Kubernetes YAML, které můžete přímo kubectl apply pro ladění. Kustomize řeší environment-specifické overlaye (dev/staging/prod) přes patche, ne přes šablonovací jazyk.

Použijte Helm pro: ingress controllery, cert-manager, monitoring stacky, databázové operátory — software třetích stran s komplexními konfiguračními maticemi.

Použijte Kustomize pro: vaše vlastní aplikace — kde kontrolujete zdrojový kód, konfiguraci i cílové prostředí.

Když Terraform spravuje helm_release resources pro vaše aplikace, platíte daň složitosti Helmu a Terraformu a jejich synchronizace stavu. S Flux + Kustomize píšete plain YAML a pushujete do Gitu.

8. Canary deploymenty a progressive delivery

Tady push-based model úplně selhává. Zkuste implementovat canary deployment s Terraformem a Helmem. Museli byste:

  1. Nasadit canary verzi vedle stabilní verze (druhý helm_release?)
  2. Přesměrovat procento trafficu na canary (modifikovat Istio/Linkerd VirtualService… přes Terraform?)
  3. Monitorovat chybovost a latenci canary (jak? Terraform nesleduje metriky)
  4. Postupně zvyšovat traffic pokud je zdravý, rollbacknout pokud ne (Terraform nemá tento koncept)
  5. Promovat canary na stabilní verzi a odstranit starou

Nic z toho není práce Terraformu. Terraform aplikuje požadovaný stav a odejde. Nemá zpětnovazební smyčku, nemá analýzu metrik, nemá progressive rollout. Skončili byste stavbou custom pipeline s desítkami kroků, sleep timery a curl příkazy na Prometheus — křehký Rube Goldbergův stroj.

Flagger — součást ekosystému Flux — byl pro tohle přímo stvořen. Je to Kubernetes operátor, který automatizuje progressive delivery: canary releasy, A/B testování a blue/green deploymenty. Integruje se s Istio, Linkerd, Contour, Nginx a dalšími service meshi a ingress controllery.

Takhle vypadá canary deployment s Flaggerem:

YAML
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: my-api
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-api
  service:
    port: 8080
  analysis:
    # Spustit canary analýzu každých 60 sekund
    interval: 60s
    # Maximální počet neúspěšných kontrol před rollbackem
    threshold: 5
    # Kroky canary traffic weight: 5% → 10% → 20% → 50% → 100%
    maxWeight: 50
    stepWeight: 10
    metrics:
      - name: request-success-rate
        thresholdRange:
          min: 99
        interval: 60s
      - name: request-duration
        thresholdRange:
          max: 500
        interval: 60s

Když pushnete nový image tag do Gitu:

sequenceDiagram participant Git as Git Repozitář participant Flux as Flux CD participant Flagger as Flagger participant Mesh as Service Mesh participant Prom as Prometheus Git->>Flux: Detekován nový image tag Flux->>Flagger: Deployment aktualizován Flagger->>Mesh: Směrovat 5% trafficu na canary loop Každých 60 sekund Flagger->>Prom: Kontrola success rate, latence alt Metriky zdravé Flagger->>Mesh: Zvýšit canary váhu (+10%) else Metriky zhoršené Flagger->>Mesh: Směrovat 100% na stabilní Flagger->>Flagger: Rollback canary ✗ end end Flagger->>Mesh: Promovat canary na stabilní ✓

Flagger sleduje reálné traffic metriky z Promethea. Pokud má canary verze vyšší chybovost nebo pomalejší odezvy, automaticky rollbackne — bez lidského zásahu, bez “kdo hlídá dashboard.” Pokud je canary zdravý přes všechny váhové kroky, promuje ho a stará verze se odstraní.

Tohle je typ deployment sofistikace, kterou Kubernetes ekosystém umožňuje nativně. Není to přilepené — je to součástí reconciliačního modelu. Flux detekuje změnu v Gitu, Flagger řídí progressive rollout, service mesh přesměrovává traffic, Prometheus poskytuje zpětnovazební signál. Každá komponenta dělá to, pro co byla navržena.

Zkuste to nacpat do terraform apply.

Kdy push-based dává smysl

Abychom byli féroví, push-based deployment není špatný ve všech kontextech:

  • Non-Kubernetes cíle — deployment na VM, Lambda funkce nebo managed služby, které nemají pull-based reconciler
  • Jednorázové provisioning — počáteční nastavení clusteru, vytvoření databáze, konfigurace sítě (Terraform je na tohle výborný)
  • Prostředí bez perzistentních agentů — efemérní testovací prostředí, která CI vytváří a ničí

Problém není v používání Terraformu — je v používání Terraformu pro průběžný deployment aplikací do Kubernetes. Terraform je nástroj pro provisioning infrastruktury. Flux je deployment reconciler. Řeší různé problémy.

Správné rozdělení

Architektura, která funguje:

graph LR subgraph "Terraform (mění se měsíčně)" A[GKE Cluster] --> B[VPC / Subnety] A --> C[Cloud SQL] A --> D[DNS Zóny] A --> E[IAM / Service Accounts] A --> F[Instalace Flux Operátoru] end subgraph "Flux CD (mění se denně)" G[Aplikace] --> H[Kustomize Overlaye] G --> I[ConfigMapy] G --> J[Secrety přes SOPS] G --> K[Ingress pravidla] G --> L[Flagger Canaries] end F -.->|instaluje| G style A fill:#2e7d32,color:#fff style G fill:#1565c0,color:#fff

Terraform staví dům. Sítě, clustery, databáze, IAM a samotný Flux Operátor. Tyhle věci se mění zřídka — třeba měsíčně. 15minutový Terraform plan je přijatelný, když upravujete VPC peering nebo měníte velikost databáze.

Flux přestavuje nábytek. Deploymenty aplikací, aktualizace konfigurace, rotace secretů, změny škálování. Tyhle věci se mění denně. 30sekundová reconciliační smyčka není jen přijatelná — je očekávaná.

Terraform nainstaluje Flux. Flux přebírá od toho bodu. Předání je čisté: Terraform vytvoří FluxInstance CRD (jak je popsáno v našem článku o Flux Operátoru), a Flux začne reconcilovat cluster z GitOps repozitáře.

Časté námitky

“Ale my už všechno spravujeme Terraformem”

To je důvod ke změně, ne důvod zůstat. Terraform resource helm_release byl navržen pro instalaci cluster add-onů (ingress controllery, cert-manager), ne pro správu životního cyklu aplikací. Používat ho pro denní deploymenty znamená, že jste z infrastrukturního nástroje udělali deployment pipeline — a dostali to nejhorší z obou světů.

“GitOps znamená, že ztratíme přehled”

Právě naopak. terraform plan vám dává přehled když ho spustíte. Flux vám dává přehled průběžně. Vestavěné webové rozhraní Flux Operátoru ukazuje real-time stav synchronizace, historii reconciliací a zdraví resources. V kombinaci se Slack notifikacemi při selhání synchronizace získáte lepší observabilitu než CI/CD dashboard.

“A co schvalovací brány?”

Git má schvalovací brány už desítky let — říká se jim pull request reviews. Vyžadujte dva schvalovatele na vašem GitOps repozitáři. Přidejte branch protection. Použijte CODEOWNERS. Je to granulárnější než brána “klikni pro schválení Terraform plánu”, protože revieweři vidí skutečný diff manifestu, ne výstup Terraform plánu.

“Vývojáři musí rozumět Kubernetes manifestům”

Už rozumí — nebo by měli. Ať manifesty aplikuje Terraform nebo Flux, někdo je píše. Rozdíl je v tom, že s GitOps vývojáři vlastní celý životní cyklus: napsat manifest, odeslat PR, nechat ho zrevidovat, mergnout a sledovat deployment. Žádné čekání, až platformní tým “spustí pipeline.”

Jak začít

Pokud aktuálně používáte Terraform + Helm pro deployment aplikací a chcete migrovat na GitOps:

  1. Ponechte Terraform pro infrastrukturu. VPC, clustery, databáze, DNS — Terraform je správný nástroj.
  2. Nainstalujte Flux přes Terraform. Použijte Flux Operátor, jak je popsáno v našem předchozím článku. To je most.
  3. Přesouvejte jednu aplikaci najednou. Odstraňte helm_release z Terraformu, přidejte ekvivalentní HelmRelease do vašeho GitOps repozitáře. Ověřte, že Flux reconciluje.
  4. Smažte Helm releasy ze statu Terraformu. terraform state rm helm_release.my_api. Nespouštějte terraform destroy — to by smazalo skutečný release.
  5. Opakujte, dokud Terraform nespravuje jen infrastrukturu a Flux všechny workloady.

Migrace je inkrementální. Nemusíte přesunout všechno najednou. Ale každá přesunutá aplikace je o jeden důvod méně spouštět 15minutovou Terraform pipeline kvůli jednořádkové změně image tagu.

Přestaňte bourat dům. Prostě přestavte nábytek.


Titulní foto: Tamas Szabo na Unsplash.

Další z blogu