Vanilla Kubernetes

Treći deo: Produkcione operacije, otpornost i enterprise integracije
GitOps, upravljanje promenama i konfiguracioni drift u Kubernetes-u
XI. Upravljanje platformom i interoperabilnost
49. GitOps, upravljanje promenama i konfiguracioni drift – od izvora istine do dokaza primene

U prethodnim lekcijama uvedeni su inventar, kontrolisani metapodaci i admission politike. Oni omogućavaju da platforma zna šta postoji i da odbije objekat koji krši definisana pravila. Ipak, ni inventar ni admission kontrola ne odgovaraju sami na pitanja ko je odobrio promenu, koja je tačno verzija konfiguracije trebalo da bude primenjena, da li je primena zaista završena i šta se događa kada neko naknadno ručno izmeni živi objekat. GitOps povezuje te tačke u operativni tok: željeno stanje je deklarativno, verzionisano i pregledano, agent ga preuzima iz odobrenog izvora, poredi sa stvarnim stanjem i kontinuirano rekonsiliše razliku.

GitOps nije sinonim za „YAML u Git-u”, niti Git commit sam po sebi dokazuje uspešnu produkcionu promenu. Commit dokazuje šta je zapisano u repozitorijumu; status kontrolera dokazuje koju je reviziju obradio; Kubernetes status, događaji, metrički signali i testovi dokazuju da je workload postao zdrav; audit i change zapis povezuju identitet, odobrenje, vreme i posledicu. Tek njihovom korelacijom nastaje dokaz primene koji može da posluži administratoru, vlasniku usluge, revizoru i incident timu.

GitOps kao operativni model, a ne samo alat

OpenGitOps principi opisuju željeno stanje kao deklarativno, verzionisano i nepromenljivo u smislu istorije, automatski preuzeto i kontinuirano rekonsilisano. Git je najčešći sistem za verzionisanje, ali suština nije u nazivu proizvoda: neophodni su pregledljiva istorija, jednoznačna revizija, kontrola pristupa i agent koji neprekidno poredi željeno i stvarno stanje. Deklarativni zapis govori kakvo stanje treba da postoji, dok kontroler odlučuje koje korake mora da preduzme da ga dostigne.

Klasičan push CI/CD tok često daje udaljenom izvršiocu mrežni pristup i kredencijale za klaster, pa pipeline neposredno poziva kubectl, Helm ili API. GitOps pull model smešta kontroler u klaster ili u kontrolnu ravan sa dozvoljenim pristupom klasteru. Kontroler preuzima odobrenu reviziju izvora i primenjuje je svojim ServiceAccount identitetom. Time se smanjuje potreba da svaki CI runner poseduje produkcione kredencijale, ali se rizik ne uklanja: GitOps kontroler postaje privilegovana komponenta čiji RBAC, mrežna putanja, repozitorijumski kredencijali, image provenance, logovi i upgrade lifecycle zahtevaju strogu zaštitu.

Sloj Autoritativni podatak Dokaz Tipična greška
Git ili drugi verzionisani izvor Odobreno željeno stanje Commit ID, potpis, pull request i odobrenja Neproverena ili pogrešna deklaracija
GitOps source kontroler Preuzeta revizija i artefakt Observed revision ili digest i Ready uslov Autentikacija, DNS, TLS ili nedostupna grana
Reconciliation kontroler Renderovani skup objekata Status, inventory, događaji i controller log Render, admission, RBAC ili apply konflikt
Kubernetes API i workload kontroleri Živo i ostvareno stanje generation, observedGeneration, conditions, replike i događaji Objekat je prihvaćen, ali workload nije zdrav
Observability i poslovni test Operativni ishod promene SLO, alarmi, logovi, trag zahteva i sintetički test Tehnički sync je uspešan, ali usluga ne radi ispravno

GitOps zato ne zamenjuje upravljanje promenama. On automatizuje i dokazuje deo toka od odobrene deklaracije do rekonsilijacije. Procena rizika, segregacija dužnosti, vreme promene, komunikacija, poslovno odobrenje, test povratka i odluka da se promena zaustavi ostaju organizacione odgovornosti. Za niskorizične standardne promene tok može biti potpuno automatizovan; za promene kontrolne ravni, storage klase, mrežne politike, CRD šeme ili masovno brisanje potreban je stroži prag odobrenja i često fazna primena.

Izvor istine, granice vlasništva i struktura repozitorijuma

„Git je izvor istine” mora biti precizirana tvrdnja. Git je izvor željenog stanja samo za polja i objekte koje je organizacija poverila GitOps toku. Kubernetes kontroleri legitimno dopunjuju status, admission može podrazumevati ili mutirati pojedina polja, autoscaler menja broj replika, operator upravlja podređenim resursima, a secrets sistem može materijalizovati Secret iz spoljnog trezora. Ako se ne definišu granice vlasništva, GitOps alat može pokušati da vrati legitimnu promenu drugog kontrolera ili da sakrije pravi drift pravilom koje ignoriše previše polja.

Server-Side Apply beleži vlasništvo nad poljima u metadata.managedFields. Field manager ne predstavlja nužno čoveka; to je identitet klijenta ili kontrolera koji upravlja određenim poljima. Konflikt je važan signal da dva aktera pokušavaju da poseduju isto polje. Opcija za prisilno preuzimanje konflikta ne koristi se kao rutinska prečica: najpre se utvrđuje očekivani vlasnik i posledica. managedFields je tehnički dokaz vlasništva nad poljima, ali nije zamena za Git istoriju, audit zapis niti organizaciono odobrenje.

Repozitorijum se može organizovati po klasteru, okruženju, aplikaciji ili kombinovanom modelu. Bazni manifesti i Kustomize overlays smanjuju dupliranje, ali previše slojeva otežava odgovor na pitanje šta će stvarno biti primenjeno. Helm daje parametrizaciju i paketni lifecycle, ali chart verzija, values i zavisnosti moraju zajedno biti zaključani. Produkcioni tok treba da renderuje konačni izlaz u proveri pull request-a, izvrši validaciju šeme i politika, prikaže semantički diff i poveže promenu sa vlasnikom i change zapisom.

platform-config/
├── apps/
│   └── inventory-api/
│       ├── base/
│       │   ├── deployment.yaml
│       │   ├── service.yaml
│       │   └── kustomization.yaml
│       └── overlays/
│           ├── test/
│           └── production/
├── clusters/
│   └── vk8s-prod-01/
│       ├── flux-system/
│       └── applications.yaml
├── policies/
└── schemas/

Razdvajanje aplikacionog koda i deployment konfiguracije u različite repozitorijume može ojačati segregaciju dužnosti, ali uvodi koordinaciju verzija. Monorepo olakšava atomsku promenu više komponenti, ali povećava blast radius pogrešnog odobrenja i opterećenje kontrolera. Ne postoji univerzalna struktura: odluka zavisi od broja klastera, timova, režima pristupa, potrebe za atomskim promenama i sposobnosti alata da skalira. Bez obzira na model, putanja i scope jedne GitOps aplikacije ne treba da joj daju administrativnu vlast nad nepovezanim tenantima.

Od zahteva za promenom do produkcione rekonsilijacije

Kontrolisana promena počinje radnim nalogom ili issue zapisom koji opisuje cilj, vlasnika, obim, rizik, zavisnosti, očekivani rezultat, provere i rollback kriterijum. Autor zatim menja deklaraciju u grani. Automatizovane provere potvrđuju sintaksu, Kubernetes šemu, renderovanje Kustomize ili Helm sadržaja, organizacione politike, zabranjene tajne, potpis ili poreklo artefakta i razliku prema prethodnoj odobrenoj reviziji. Reviewer ne odobrava samo činjenicu da je pipeline zelen; procenjuje semantiku promene i blast radius.

  1. Planiranje: identifikovati resurse, zavisnosti, SLO, prozor promene i kriterijum prekida.
  2. Predlog: napraviti malu, razumljivu izmenu sa nepromenljivom image referencom, po mogućnosti digest-om.
  3. Pre-merge validacija: renderovati konačne manifeste, izvršiti schema i policy provere i pregledati diff.
  4. Odobrenje i merge: primeniti pravila zaštićene grane, CODEOWNERS ili ekvivalent i segregaciju dužnosti.
  5. Preuzimanje: source kontroler potvrđuje novu reviziju ili digest i objavljuje artefakt.
  6. Rekonsilijacija: kontroler poredi deklaraciju sa klasterom, proverava zavisnosti, primenjuje promenu i po konfiguraciji uklanja objekte koji više nisu deklarisani.
  7. Validacija: proveravaju se GitOps status, Kubernetes rollout, događaji, alarmi, metrički i poslovni signali.
  8. Dokumentovanje: change zapis dobija commit, primenjenu reviziju, vreme, rezultate, odstupanja i odluku o zatvaranju ili rollback-u.

Merge i deployment ne moraju biti isti trenutak. Organizacija može koristiti ručnu promociju revizije između okruženja, pull request koji menja production overlay, vremenske sync prozore ili progresivnu isporuku. Važno je da se ne uvodi skrivena, neverzionisana promena parametra u korisničkom interfejsu alata. Efektivna konfiguracija mora biti rekonstruisana iz odobrenih izvora.

Rekonsilijacija, intervali, zavisnosti i redosled

Rekonsilijacija je ponovljiv kontrolni ciklus. Kontroler čita izvor, gradi ili renderuje objekte, poredi željeno sa živim stanjem i pokušava da razliku ukloni. Dobar kontroler je idempotentan: ponavljanje iste revizije ne proizvodi novu neželjenu promenu. Interval određuje maksimalnu uobičajenu latenciju detekcije nove revizije i drift-a, ali kraći interval nije besplatan. Veći broj objekata i klastera povećava Git, CPU, memorijsko i API opterećenje; agresivno osvežavanje može pogoršati incident kada je zavisni sistem nestabilan.

Webhook može ubrzati obaveštenje o novoj reviziji, ali periodična rekonsilijacija i dalje ostaje sigurnosna mreža. Redosled resursa ne treba zasnivati na vremenskim pauzama. Namespace, CRD, operator, konfiguracija, workload i post-deployment test imaju različite zavisnosti. Flux Kustomization podržava eksplicitne zavisnosti i health checks, dok Argo CD koristi sync faze, waves i hooks. Mehanizmi nisu međusobno identični, pa se konfiguracija mora proveriti prema verziji izabranog proizvoda.

Objekat koji je API server prihvatio nije nužno spreman. Ready=True na GitOps objektu obično znači da je kontroler uspešno završio svoj definisani ciklus, ali dokaz poslovne dostupnosti traži i Deployment uslove, dostupne replike, Service endpoint-e, aplikacione probe, metrike grešaka i sintetički zahtev. Za migraciju baze ili promenu CRD šeme rollback može biti složen ili nemoguć prostim vraćanjem manifesta; takve promene zahtevaju unapred projektovanu kompatibilnost i recovery plan.

Konfiguracioni drift: vrste, uzroci i politika reakcije

Konfiguracioni drift je razlika između očekivanog i stvarnog stanja, ali nije svaka razlika incident. Drift može nastati ručnim kubectl edit ili patch postupkom, drugim automatizacionim alatom, admission mutacijom, podrazumevanjem API servera, autoscaling-om, operatorom, promenom spoljne zavisnosti ili greškom u renderovanju. Prvo pitanje zato nije „kako odmah vratiti Git”, već „ko je legitimni vlasnik polja i da li razlika ugrožava uslugu ili bezbednost”.

Vrsta razlike Primer Preporučena reakcija
Nedozvoljeni drift Ručno promenjena image verzija ili uklonjena NetworkPolicy Sačuvati dokaze, proceniti incident i rekonsilisati odobreno stanje
Hitna ovlašćena promena Privremeno skaliranje tokom incidenta Vremenski ograničiti, evidentirati, zatim odmah backport-ovati u Git ili vratiti stanje
Očekivana kontrolerska promena HPA menja spec.replicas Jasno dodeliti vlasništvo i ne deklarisati konkurentsku statičku vrednost
Normalizacija ili defaulting API server dodaje podrazumevano polje Koristiti semantičko poređenje i konfiguraciju alata, ne tekstualni diff sirovog YAML-a
Namerno ignorisana razlika Rotirajući CA bundle kojim upravlja namenski kontroler Ignorisati samo preciznu putanju uz vlasnika, razlog, rok i test
Izvorni drift Promenljivi image tag sada pokazuje na drugi digest Koristiti nepromenljive verzije ili digest i kontrolisanu automatizovanu nadogradnju

Automatski self-heal smanjuje vreme odstupanja, ali može poništiti ručnu akciju incident tima pre nego što se prikupe dokazi ili može ući u petlju sa drugim kontrolerom. Alarmiranje bez automatske korekcije daje više kontrole, ali produžava izloženost. Kritični bezbednosni resursi mogu zahtevati brzu korekciju, dok se za StatefulSet, CRD ili namespace brisanje često zahteva ručna potvrda. Pruning je posebno rizičan: uklanjanje deklaracije može obrisati živi objekat i, zavisno od vrste i finalizer-a, njegove podatke ili zavisne resurse.

Ignore pravila moraju biti minimalna. Ignorisanje celog spec ili svih razlika za neku vrstu može pretvoriti GitOps status u lažno zelen signal. Svako pravilo treba da ima konkretan JSON path ili polje, vlasnika drugog kontrolera, dokumentovan razlog, datum revizije i negativan test koji potvrđuje da važna promena i dalje biva detektovana.

Flux i Argo CD: zajednički princip, različit operativni model

Flux i Argo CD su popularne GitOps implementacije, ali njihovi API objekti, statusi, CLI komande i podrazumevano ponašanje nisu zamenljivi. Flux je skup kontrolera i Kubernetes custom resursa: izvori, Kustomization i HelmRelease objekti predstavljaju delove toka. Argo CD grupiše resurse u Application model, nudi izražen aplikacioni pogled i razlikuje sync i health status. Izbor se ne zasniva samo na korisničkom interfejsu, već na modelu tenancy-ja, RBAC-u, načinu promocije, podržanim izvorima, high-availability zahtevu, integraciji identiteta i operativnom znanju tima.

Aspekt Flux Argo CD
Osnovni model Komponovani source i reconciliation CRD objekti Application i AppProject objekti sa aplikacionim prikazom
Drift korekcija Kustomization kontinuirano rekonsiliše; suspend pauzira korekciju Automated sync i selfHeal određuju automatsku korekciju
Uklanjanje objekata prune na Kustomization objektu Automated prune ili ručni sync sa prune; moguća potvrda za kritične resurse
Dokaz revizije Source artifact revision/digest i status Kustomization objekta Application sync revision, history, sync i health status
Pauziranje spec.suspend ili Flux CLI suspend/resume Promena sync politike ili odgovarajuća operativna kontrola aplikacije

Licenca i podrška takođe su odvojene odluke. Open-source projekat, komercijalna distribucija, managed usluga i vendor paket mogu imati različite release cadence, podržane verzije Kubernetes-a, high-availability obrasce, bezbednosne zakrpe i SLA. Produkcioni standard mora da navede tačnu verziju instalirane implementacije i njenu dokumentaciju; primer iz ove lekcije nije zamena za compatibility matrix konkretnog izdanja.

Bezbednost GitOps lanca snabdevanja

GitOps repozitorijum je upravljačka površina. Korisnik koji može da izmeni Deployment može promeniti image ili pokrenuti privilegovan workload; korisnik koji može da izmeni RBAC, admission konfiguraciju ili samu GitOps instalaciju može pokušati da proširi vlast. Zaštićene grane, obavezni review, CODEOWNERS, višefaktorska autentikacija, kratkotrajni kredencijali, potpisivanje commit-a ili artefakta i nezavisna policy provera smanjuju rizik, ali samo ako se pravila ne mogu zaobići alternativnom granom ili direktnom promenom živog klastera.

Admission policy iz prethodne lekcije ostaje zaštitna granica čak i kada je izvor odobren. Git review može propustiti grešku ili kompromitovani nalog može uneti zlonamernu deklaraciju. API server treba da odbije nedozvoljen privileged režim, pogrešan registry, nepostojeće obavezne labels ili kršenje namespace pravila. GitOps kontroler tada prijavljuje neuspeh; trajna korekcija je ispravka izvora, ne slabljenje politike samo da bi status postao zelen.

Dokaz primene i sledljivost promene

Dokaz primene nije screenshot zelenog ekrana. Minimalni dokazni paket sadrži identifikator promene, commit ili artefakt digest, identitet odobravalaca, GitOps objekat i njegovu obrađenu reviziju, početak i kraj rekonsilijacije, listu obuhvaćenih resursa, Kubernetes rollout i health rezultate, relevantne alarme i logove, kao i rollback odluku. Dokazi treba da budu mašinski čitljivi gde je moguće, vremenski usklađeni i čuvani prema politici revizije bez tajni i nekontrolisanih kompletnih manifesta.

# Read-only: Flux status i obrađena revizija
flux get sources git -A
flux get kustomizations -A
kubectl get kustomization inventory-api -n flux-system \
  -o jsonpath='{.status.lastAppliedRevision}{"\n"}{range .status.conditions[*]}{.type}={.status}:{.reason}{"\n"}{end}'

# Read-only: Kubernetes dokaz ostvarenog stanja
kubectl rollout status deployment/inventory-api -n gitops-demo --timeout=180s
kubectl get deployment inventory-api -n gitops-demo \
  -o jsonpath='{.metadata.generation}{" "}{.status.observedGeneration}{" "}{.status.availableReplicas}{"\n"}'
kubectl events -n gitops-demo \
  --for=deployment/inventory-api --types=Warning

Polja statusa zavise od verzije GitOps CRD-a. Skripta ne sme pretpostaviti da status postoji pre prve rekonsilijacije, niti tumačiti odsustvo Warning događaja kao dokaz zdravlja. Događaji imaju ograničeno zadržavanje; za istorijsku analizu potrebni su centralni logovi i metrički sistem. Najjači dokaz povezuje isti commit sa statusom kontrolera, audit zahtevima field manager-a i poslovnim testom nakon rollout-a.

Rollback, roll-forward i hitne promene

GitOps rollback je nova deklarativna promena koja vraća poznato dobro stanje: najčešće git revert problematičnog commit-a ili promocija prethodno potvrđene verzije. Prepisivanje istorije zaštićene grane i ručno vraćanje samo živog objekta razaraju sledljivost. Revert ne garantuje oporavak podataka. Ako je promenjena nekompatibilna baza, PVC sadržaj, CRD storage schema ili spoljni servis, potrebno je posebno rollback ili roll-forward uputstvo.

Roll-forward je često bezbedniji kada je uzrok jasan i korekcija mala, naročito ako bi povratak binarne verzije bio nekompatibilan sa migriranim podacima. Odluka se zasniva na vremenu oporavka, stanju podataka, blast radius-u i testiranom postupku, a ne na preferenciji alata. GitOps kontroler se može privremeno suspendovati da ne poništava forenzičku ili hitnu akciju, ali suspenzija stvara period bez automatske korekcije i mora imati vlasnika, razlog, alarm i rok za nastavak.

Break-glass promena mora biti izuzetak sa jakom autentikacijom, vremenski ograničenim pravom i audit tragom. Pre state-changing komande prikupljaju se revision, diff, status, događaji i managed fields. Nakon stabilizacije promena se unosi u Git ili se živo stanje vraća odobrenoj reviziji; zatim se kontroler nastavlja i potvrđuje se odsustvo drift-a. „Popravi sada, dokumentuj nikada” nije incident response, već stvaranje sledećeg incidenta.

Observability, dostupnost i oporavak GitOps kontrolne petlje

GitOps je deo produkcione kontrolne ravni. Prate se dostupnost kontrolera, trajanje i stopa neuspešnih rekonsilijacija, starost poslednje uspešne revizije, red čekanja, API throttling, source fetch greške, količina OutOfSync ili NotReady objekata i broj suspendovanih resursa. Alarm treba da razlikuje novu neuspešnu promenu od globalnog gubitka pristupa repozitorijumu ili API serveru. Jedan neuspešan workload ima drugačiji blast radius od svih source objekata koji više ne mogu da preuzmu reviziju.

Kontroleri treba da imaju odgovarajuće resource requests, više replika kada implementacija i arhitektura to podržavaju, PodDisruptionBudget, anti-affinity ili topology spread i testiran upgrade postupak. Više replika ne znači nužno paralelnu primenu iste promene: leader election i interna arhitektura proizvoda određuju ponašanje. Gubitak Git servera obično ne zaustavlja već pokrenute workload-e, ali sprečava nove promene i može sprečiti korekciju drift-a. Gubitak GitOps namespace-a ne sme značiti gubitak izvora istine; bootstrap konfiguracija i kredencijali moraju imati testiran recovery tok.

Backup repozitorijuma, zaštita grana i retention istorije čuvaju deklaraciju. Etcd backup iz lekcije 46 čuva živo stanje klastera, ali nije zamena za Git niti obrnuto. Oporavak novog klastera zahteva bootstrap kontrolera, bezbedno vraćanje pristupa izvorima, redosled platformskih zavisnosti, proveru nepromenljivih artefakata i kontrolisanu rekonsilijaciju. Automatski prune se tokom DR provere ne uključuje nepromišljeno pre nego što se potvrde scope i kompletnost izvora.

Praktikum: Flux tok od odobrene revizije do detekcije i korekcije drift-a

Cilj i kontekst.

Laboratorija gradi mali, proverljiv GitOps tok za aplikaciju inventory-api. Čitalac će pripremiti repozitorijum, validirati i objaviti deklaraciju, povezati postojeću Flux instalaciju sa izvorom, dokazati primenjenu reviziju, bezbedno izazvati metadata drift, posmatrati self-heal, simulirati neispravnu promenu, izvršiti rollback kroz Git i sastaviti dokazni paket. Ne instalira se Flux naslepo u produkciju; bootstrap i credentials model zavise od izabranog Git provajdera i bezbednosnog standarda.

Topologija.

Administratorska stanica
  ├── git, kubectl, flux CLI i pristup repozitorijumu
  └── kubeconfig za laboratorijski klaster
             │
             ▼
Git repozitorijum ──pull──► source-controller
                              │ artefakt/revizija
                              ▼
                         kustomize-controller
                              │ Server-Side Apply
                              ▼
                 namespace gitops-demo + Deployment + Service

Preduslovi, privilegije i rizik.

Vežba 1: početna procena i priprema deklarativnog izvora

Prvo se izvršavaju samo read-only provere. flux check proverava preduslove i instalirane komponente; naredne komande potvrđuju CRD verzije i stanje kontrolera. Ako Flux nije instaliran ili nije kompatibilan sa klasterom, vežba se prekida i koristi se zvanični installation odnosno bootstrap postupak koji odgovara konkretnom Git provajderu.

flux check
kubectl api-resources --api-group=source.toolkit.fluxcd.io
kubectl api-resources --api-group=kustomize.toolkit.fluxcd.io
kubectl get deployments,pods -n flux-system
kubectl get crd gitrepositories.source.toolkit.fluxcd.io \
  kustomizations.kustomize.toolkit.fluxcd.io

U praznom lokalnom direktorijumu repozitorijuma prave se putanje apps/inventory-api/base i clusters/vk8s-lab-01. Sledeći fajlovi predstavljaju minimalni workload. Image je zaključan na konkretan tag samo radi čitljivosti laboratorije; produkcioni standard treba da koristi organizaciono odobren image i digest.

# apps/inventory-api/base/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: gitops-demo
  labels:
    tashizza.example/environment: laboratory
    tashizza.example/managed-by: flux
---
# apps/inventory-api/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inventory-api
  namespace: gitops-demo
  labels:
    app.kubernetes.io/name: inventory-api
    app.kubernetes.io/managed-by: flux
    tashizza.example/change-record: CHG-LAB-0049
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: inventory-api
  template:
    metadata:
      labels:
        app.kubernetes.io/name: inventory-api
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: web
          image: nginxinc/nginx-unprivileged:1.27.5-alpine
          ports:
            - name: http
              containerPort: 8080
          readinessProbe:
            httpGet:
              path: /
              port: http
            initialDelaySeconds: 2
            periodSeconds: 5
          resources:
            requests:
              cpu: 25m
              memory: 32Mi
            limits:
              cpu: 200m
              memory: 128Mi
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsNonRoot: true
            capabilities:
              drop: ["ALL"]
---
# apps/inventory-api/base/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: inventory-api
  namespace: gitops-demo
spec:
  selector:
    app.kubernetes.io/name: inventory-api
  ports:
    - name: http
      port: 80
      targetPort: http

Kustomize datoteka navodi sve resurse. Relativna putanja iz cluster overlay-a ka base sadržaju mora odgovarati stvarnoj strukturi repozitorijuma.

# apps/inventory-api/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - namespace.yaml
  - deployment.yaml
  - service.yaml

# clusters/vk8s-lab-01/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../apps/inventory-api/base

Pre commit-a lokalno se renderuje konačni sadržaj, a server-side dry-run šalje objekte admission lancu bez čuvanja. Ova provera je read-like po nameri, ali zahteva API prava za operacije koje dry-run simulira. kubectl diff može vratiti izlazni kod 1 kada razlika postoji; to nije isto što i greška izvršenja.

kubectl kustomize clusters/vk8s-lab-01 > 49-rendered.yaml
kubectl apply --server-side --dry-run=server \
  --field-manager=gitops-preflight -f 49-rendered.yaml
kubectl diff --server-side \
  --field-manager=gitops-preflight -f 49-rendered.yaml || test "$?" -eq 1

git status --short
git add apps/inventory-api clusters/vk8s-lab-01
git commit -m "CHG-LAB-0049 add inventory-api GitOps baseline"
git rev-parse HEAD

Posle review-a i odobrenja grana se šalje u udaljeni repozitorijum komandom git push. Uspeh ove vežbe je čist render, uspešan server dry-run i commit ID koji se može povezati sa change zapisom. Greška no matches for kind znači da CRD ili API verzija nedostaje; admission odbijanje se ispravlja u manifestu, ne zaobilazi u klasteru.

Vežba 2: povezivanje izvora i kontrolisana prva primena

Sledeća dva manifesta menjaju stanje klastera. Pre primene zamenjuju se URL i branch. GitRepository preuzima izvor na definisanom intervalu, a Flux Kustomization renderuje putanju, čeka health Deployment-a i održava inventory. prune: true je namerno uključen da bi laboratorija prikazala potpun lifecycle; u produkciji odluka zahteva procenu posledica brisanja. Primer koristi neprivilegovanu varijantu NGINX image-a koja sluša na portu 8080; pre produkcione upotrebe verzija se proverava u odobrenom registry-ju i zaključava digest-om.

# 49-flux-source.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: tashizza-platform-config
  namespace: flux-system
spec:
  interval: 1m
  url: https://git.example.invalid/platform/platform-config.git
  ref:
    branch: main
---
# 49-flux-kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: inventory-api
  namespace: flux-system
spec:
  interval: 2m
  retryInterval: 30s
  timeout: 3m
  path: ./clusters/vk8s-lab-01
  prune: true
  wait: true
  sourceRef:
    kind: GitRepository
    name: tashizza-platform-config
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: inventory-api
      namespace: gitops-demo

Nakon zamene placeholder-a prvo se radi server dry-run, pa tek onda primena. Ručna komanda flux reconcile menja status zahtevom za neposrednu rekonsilijaciju; koristi se u laboratoriji da se ne čeka interval, ali nije dokaz sama po sebi.

kubectl apply --server-side --dry-run=server \
  --field-manager=gitops-bootstrap \
  -f 49-flux-source.yaml -f 49-flux-kustomization.yaml

kubectl apply --server-side \
  --field-manager=gitops-bootstrap \
  -f 49-flux-source.yaml -f 49-flux-kustomization.yaml

flux reconcile source git tashizza-platform-config \
  -n flux-system --with-source
flux reconcile kustomization inventory-api \
  -n flux-system --with-source

flux get sources git -n flux-system
flux get kustomizations -n flux-system
kubectl wait kustomization/inventory-api -n flux-system \
  --for=condition=ready --timeout=180s

Validacija mora pokazati Ready=True, reviziju koja odgovara objavljenom commit-u i zdrav Deployment sa dve dostupne replike. Service mora imati EndpointSlice endpoint-e. Ako source nije Ready, prvo se proveravaju URL, branch, DNS, TLS i credential Secret; ako je source zdrav, a Kustomization nije, proveravaju se render, admission, RBAC i workload health.

kubectl rollout status deployment/inventory-api \
  -n gitops-demo --timeout=180s
kubectl get deployment,pods,service,endpointslice -n gitops-demo -o wide
kubectl get kustomization inventory-api -n flux-system \
  -o jsonpath='{.status.lastAppliedRevision}{"\n"}{range .status.conditions[*]}{.type}={.status}:{.reason}:{.message}{"\n"}{end}'
kubectl get deployment inventory-api -n gitops-demo \
  -o yaml --show-managed-fields

Vežba 3: bezbedna simulacija drift-a i dokaz self-heal ponašanja

Drift se izaziva promenom nefunkcionalne label vrednosti na Deployment objektu, ne selector-a, image-a, securityContext-a ili storage-a. Pre izmene čuvaju se revizija, originalna vrednost i field managers. Komanda kubectl label menja živi objekat i koristi se samo u ovoj izolovanoj vežbi.

mkdir -p 49-evidence
date -u +%Y-%m-%dT%H:%M:%SZ > 49-evidence/drift-start-utc.txt
git rev-parse HEAD > 49-evidence/expected-git-commit.txt
kubectl get kustomization inventory-api -n flux-system -o yaml \
  > 49-evidence/kustomization-before-drift.yaml
kubectl get deployment inventory-api -n gitops-demo -o yaml \
  --show-managed-fields > 49-evidence/deployment-before-drift.yaml

# Menja stanje samo u laboratoriji
kubectl label deployment inventory-api -n gitops-demo \
  tashizza.example/change-record=UNAPPROVED-LIVE-EDIT --overwrite

# Read-only dokaz neposrednog drift-a
kubectl get deployment inventory-api -n gitops-demo \
  -o jsonpath='{.metadata.labels.tashizza\.example/change-record}{"\n"}'

Ne primenjuje se dodatna korekcija. Čeka se najmanje jedan definisani reconciliation interval ili se, radi deterministične laboratorije, eksplicitno traži rekonsilijacija. Zatim se proverava da je vrednost vraćena na CHG-LAB-0049 i da workload nije imao prekid.

flux reconcile kustomization inventory-api \
  -n flux-system --with-source

kubectl get deployment inventory-api -n gitops-demo \
  -o jsonpath='{.metadata.labels.tashizza\.example/change-record}{"\n"}'
kubectl rollout status deployment/inventory-api \
  -n gitops-demo --timeout=180s
kubectl get events -n flux-system --sort-by=.metadata.creationTimestamp | tail -n 30
kubectl logs -n flux-system deployment/kustomize-controller \
  --since=10m --all-containers=true | grep -E 'inventory-api|drift|configured|reconciliation' || true

Kriterijum završetka je vraćena deklarisana label, nepromenjena Git revizija i zdrav Deployment. Ako drift ostane, proveravaju se spec.suspend, Ready status, interval, inventory, scope putanje i controller log. Ako se vrednost stalno menja napred–nazad, traži se drugi field manager ili automatizacija; ne skraćuje se interval da bi se prikrila borba kontrolera.

Vežba 4: neuspešna deklarativna promena, dijagnostika i Git rollback

U produkcionom overlay-u menja se samo image tag na namerno nepostojeću laboratorijsku vrednost nginxinc/nginx-unprivileged:1.27.5-alpine-does-not-exist. Promena nije destruktivna za podatke, ali može učiniti nove podove nedostupnim. Deployment rolling update obično zadržava deo starih replika, zavisno od strategije i raspoloživih resursa. Pre vežbe potvrđuje se da nema aktivnog incidenta.

sed -i 's#nginxinc/nginx-unprivileged:1.27.5-alpine#nginxinc/nginx-unprivileged:1.27.5-alpine-does-not-exist#' \
  apps/inventory-api/base/deployment.yaml

kubectl kustomize clusters/vk8s-lab-01 > 49-rendered-bad-image.yaml
kubectl apply --server-side --dry-run=server \
  --field-manager=gitops-preflight -f 49-rendered-bad-image.yaml

git add apps/inventory-api/base/deployment.yaml
git commit -m "CHG-LAB-0049 simulate unavailable image"
BAD_COMMIT="$(git rev-parse HEAD)"
git push

Napomena: sed -i menja lokalni fajl; pre izvršenja proverava se da se očekivani originalni string pojavljuje tačno jednom. Server-side dry-run ne proverava da image zaista postoji u registry-ju, pa će validan manifest biti prihvaćen. To je nameran dokaz granice konfiguracione validacije.

flux reconcile kustomization inventory-api \
  -n flux-system --with-source || true

kubectl get kustomization inventory-api -n flux-system -o yaml
kubectl get deployment,replicaset,pods -n gitops-demo -o wide
kubectl describe deployment inventory-api -n gitops-demo
kubectl events -n gitops-demo --types=Warning
kubectl get pods -n gitops-demo \
  -l app.kubernetes.io/name=inventory-api \
  -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\t"}{range .status.containerStatuses[*]}{.state.waiting.reason}{"\n"}{end}{end}'

Simptom je Kustomization koji ne dostiže Ready ili Deployment koji ne završava rollout. Obim je samo inventory-api; neposredni uzrok je ErrImagePull ili ImagePullBackOff; osnovni uzrok je odobrena, ali nepostojeća image referenca koju pre-merge provera nije verifikovala. Privremeno zaobilazno rešenje može biti zadržavanje starih spremnih replika, ali trajna korekcija je vraćanje poznatog image-a i dodavanje registry/provenance provere u pipeline.

Rollback se radi novim revert commit-om, čime se istorija čuva. Ne koristi se git reset --hard niti force push. Nakon slanja revert-a zahteva se nova rekonsilijacija i validiraju i GitOps i workload sloj.

git revert --no-edit "$BAD_COMMIT"
ROLLBACK_COMMIT="$(git rev-parse HEAD)"
git push

flux reconcile kustomization inventory-api \
  -n flux-system --with-source
kubectl wait kustomization/inventory-api -n flux-system \
  --for=condition=ready --timeout=180s
kubectl rollout status deployment/inventory-api \
  -n gitops-demo --timeout=180s

kubectl get deployment inventory-api -n gitops-demo \
  -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}{.status.availableReplicas}{"\n"}'
printf '%s\n' "$BAD_COMMIT" > 49-evidence/failed-commit.txt
printf '%s\n' "$ROLLBACK_COMMIT" > 49-evidence/rollback-commit.txt

Uspeh je obrađena rollback revizija, vraćen image nginxinc/nginx-unprivileged:1.27.5-alpine, dve dostupne replike, stabilni EndpointSlice objekti i odsustvo novih Warning događaja nakon oporavka. Ako se stari podovi ne vraćaju, proveravaju se node kapacitet, registry dostupnost i ReplicaSet događaji; ne pretpostavlja se da je svaki simptom posledica Git-a.

Vežba 5: kontrolisana suspenzija, nastavak i dokazni paket

Suspenzija je state-changing postupak za održavanje ili incident. Pre nje se beleže razlog, vlasnik i maksimalno trajanje. Dok je Kustomization suspendovan, nova source revizija se ne primenjuje i drift korekcija je pauzirana. Workload nastavlja da radi u poslednjem stanju, ali zaštita rekonsilijacije više nije aktivna.

# Menja stanje GitOps kontrolne petlje
flux suspend kustomization inventory-api -n flux-system

# Read-only potvrda suspenzije
kubectl get kustomization inventory-api -n flux-system \
  -o jsonpath='{.spec.suspend}{"\n"}'

# Menja stanje: nastavak i čekanje rekonsilijacije
flux resume kustomization inventory-api -n flux-system
kubectl wait kustomization/inventory-api -n flux-system \
  --for=condition=ready --timeout=180s

Za dokazni paket prikupljaju se samo potrebna polja i poslednji relevantni događaji. Controller log može sadržati URL repozitorijuma i tehničke detalje, pa se pre deljenja rediguju osetljive vrednosti. Kompletni Secret objekti i credential podaci se nikada ne izvoze.

date -u +%Y-%m-%dT%H:%M:%SZ > 49-evidence/completed-utc.txt
git log --show-signature -5 --oneline \
  > 49-evidence/git-history.txt 2>&1
flux get sources git -n flux-system \
  > 49-evidence/flux-sources.txt
flux get kustomizations -n flux-system \
  > 49-evidence/flux-kustomizations.txt
kubectl get kustomization inventory-api -n flux-system -o yaml \
  > 49-evidence/kustomization-final.yaml
kubectl get deployment,replicaset,pods,service,endpointslice \
  -n gitops-demo -o wide > 49-evidence/workload-final.txt
kubectl get events -n gitops-demo --sort-by=.metadata.creationTimestamp \
  > 49-evidence/events-final.txt

tar -czf 49-gitops-evidence.tar.gz 49-evidence
sha256sum 49-gitops-evidence.tar.gz

Kriterijum završetka praktikuma je dokaziva veza između odobrenog Git commit-a, lastAppliedRevision vrednosti, zdravog Deployment-a, korekcije ručnog drift-a i uspešnog revert commit-a. Arhiva se čuva prema laboratorijskoj politici, ne šalje nekontrolisano i ne predstavlja zamenu za centralni audit i observability sistem.

Rollback laboratorije i bezbedan cleanup

Brisanje Flux Kustomization objekta dok je prune: true može imati različite posledice zavisno od finalization i deletion policy ponašanja konkretne verzije. Zbog toga se cleanup ne izvodi naslepo. Najpre se suspenduje rekonsilijacija, čita inventory i potvrđuje da sadrži samo objekte ove vežbe. Zatim se eksplicitno brišu aplikacioni resursi i GitOps objekti. Komande su destruktivne i dozvoljene samo u namenskom laboratorijskom okruženju.

flux suspend kustomization inventory-api -n flux-system
kubectl get kustomization inventory-api -n flux-system -o yaml
kubectl get all -n gitops-demo

# Destruktivno: izvršiti tek nakon potvrde scope-a
kubectl delete kustomization inventory-api -n flux-system
kubectl delete gitrepository tashizza-platform-config -n flux-system
kubectl delete namespace gitops-demo

rm -f 49-flux-source.yaml 49-flux-kustomization.yaml \
  49-rendered.yaml 49-rendered-bad-image.yaml \
  49-gitops-evidence.tar.gz

Lokalni Git repozitorijum i udaljena grana se ne brišu automatski, jer predstavljaju dokaz promene. Njihovo arhiviranje ili uklanjanje radi se prema pravilima vlasnika repozitorijuma. Ako je korišćen credential Secret, rotira se ili uklanja samo nakon potvrde da ga ne koristi drugi source objekat.

Tipične greške i sistematična dijagnostika

Redosled dijagnostike ostaje od najmanje invazivnog ka rizičnijem: change i Git istorija; source i reconciliation status; događaji; workload stanje; controller logovi i metrike; managed fields i audit; tek zatim suspenzija, ručna rekonsilijacija ili korekcija. Svaka state-changing intervencija mora imati hipotezu, vlasnika, očekivani rezultat i način vraćanja.

Administratorske prakse

Završna kontrolna lista

Zaključak

GitOps uvodi disciplinovanu vezu između deklarativnog izvora istine i živog Kubernetes stanja. Njegova najveća vrednost nije automatski apply, već ponovljiva rekonsilijacija sa verzionisanom namerom, pregledom, jasnim vlasništvom i dokazima. Administrator mora da razlikuje reviziju izvora, uspeh kontrolera, prihvatanje API objekta, health workload-a i poslovni ishod; nijedan od tih signala sam ne dokazuje kompletnu promenu.

Konfiguracioni drift je istovremeno tehnički simptom i pitanje upravljanja. Nekada je nedozvoljena ručna promena, nekada legitiman rad autoscaler-a ili operatora, a nekada posledica defaulting-a. Bez modela vlasništva nad poljima, preciznih ignore pravila i audit korelacije automatski self-heal može prikriti incident ili proizvesti borbu kontrolera. Bez self-heal-a odstupanje može trajati predugo. Odgovoran izbor zato povezuje kritičnost resursa, posledicu korekcije, potrebu za forenzikom i mogućnost bezbednog rollback-a.

Praktikum je pokazao potpun tok: render i preflight validaciju, Flux source i Kustomization objekte, dokaz revizije, bezbednu simulaciju drift-a, granicu server dry-run provere, dijagnostiku nepostojećeg image-a, revert bez prepisivanja istorije, suspend/resume i prikupljanje dokaza. Ovo znanje priprema čitaoca za sledeću lekciju o interoperabilnosti: principi deklarativnog stanja, politika, artefakata, identiteta i dokaza ostaju primenljivi kada se workload prenosi na OpenShift, Tanzu ili cloud Kubernetes platformu, iako se konkretni kontroleri i podržani modeli razlikuju.

← Prethodna lekcija Povratak na sadržaj Sledeća lekcija →