Vanilla Kubernetes

Prvi deo: Temelji, arhitektura i izgradnja klastera
YAML manifesti – deklarativni opis Kubernetes resursa
III. Kubernetes API, kubectl i deklarativno upravljanje
14. YAML manifesti, apply, diff i delete – deklarativna promena, validacija i rollback

Kubernetes administrator ne upravlja klasterom samo izvršavanjem pojedinačnih komandi. U ozbiljnom okruženju stanje resursa opisuje se deklarativno, čuva u verzionisanom repozitorijumu, proverava pre primene i zatim kontrolisano prosleđuje Kubernetes API serveru. YAML manifest predstavlja čitljiv zapis željenog stanja jednog ili više Kubernetes objekata: administrator navodi šta treba da postoji, dok API server, admission mehanizmi, scheduler i odgovarajući kontroleri odlučuju kako će to stanje biti prihvaćeno i ostvareno.

Manifest nije skripta koja se izvršava red po red. Redosled polja kao što su metadata, spec i njihove unutrašnje osobine uglavnom nema izvršno značenje. Dokument se parsira u strukturirani objekat, proverava prema Kubernetes API šemi, autorizuje, eventualno menja kroz admission webhooks i čuva kao API resurs. Zbog toga sintaksno ispravan YAML nije nužno i validan Kubernetes manifest, a validan manifest ne mora automatski proizvesti funkcionalnu aplikaciju.

Deklarativni model i uloga YAML manifesta

U imperativnom radu administrator zadaje operaciju: „napravi Deployment”, „promeni broj replika” ili „izloži servis”. U deklarativnom radu opisuje krajnje stanje: Deployment treba da ima tri replike, određenu sliku kontejnera, port, resurse, provere zdravlja i skup oznaka. Kubernetes kontroleri zatim neprekidno porede željeno stanje iz polja spec sa stvarnim stanjem i preduzimaju korektivne akcije.

Deklarativni model omogućava ponovljivost, reviziju promena, automatizovanu validaciju, GitOps pristup i kontrolisani povratak na prethodnu verziju. Isti manifest može biti pregledan, testiran i primenjen kroz razvojno, testno i produkciono okruženje, uz odgovarajuće upravljanje razlikama. Manifest ipak nije kompletan sistem upravljanja konfiguracijom: ne rešava samostalno generisanje tajni, izbor vrednosti za različita okruženja, redosled složenih migracija baze podataka ili upravljanje zavisnostima između više aplikacija.

YAML je samo jedan format za predstavljanje Kubernetes API objekata. API server razmenjuje JSON, dok kubectl prihvata YAML i pretvara ga u odgovarajuću strukturu zahteva. JSON je validan podskup YAML-a, ali se YAML u administratorskom radu češće koristi zbog bolje čitljivosti i jednostavnijeg uređivanja višelinijskih vrednosti.

Obavezna polja Kubernetes objekta

Većina Kubernetes manifesta sadrži četiri osnovne celine: apiVersion, kind, metadata i spec. Tačna struktura zavisi od vrste resursa. Neki objekti, kao što je ConfigMap, nemaju klasično polje spec, već koriste polja poput data i binaryData.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: catalog-api
  namespace: catalog-prod
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: catalog-api
  template:
    metadata:
      labels:
        app.kubernetes.io/name: catalog-api
    spec:
      containers:
        - name: catalog-api
          image: registry.example.com/platform/catalog-api:1.4.2

Administrator ne treba da pogađa API verzije i dostupna polja. Podržane resurse proverava prema konkretnom klasteru:

kubectl api-resources
kubectl api-versions
kubectl explain deployment
kubectl explain deployment.spec.template.spec.containers
kubectl explain deployment.spec.strategy --recursive

Komanda kubectl explain koristi OpenAPI šemu koju objavljuje API server. Zato je pouzdanija od kopiranja starog primera sa interneta. Verzija kubectl klijenta treba da bude u podržanom rasponu u odnosu na verziju API servera, jer velike razlike mogu izazvati neusklađenost mogućnosti, podrazumevanih vrednosti i validacije.

Metadata, imena, namespace, labels i annotations

Polje metadata.name određuje stabilno ime objekta. Ime mora biti jedinstveno za istu vrstu resursa unutar odgovarajućeg namespace-a, odnosno na nivou klastera za cluster-scoped resurse. Alternativa je generateName, kada API server dodaje jedinstven sufiks, ali takav pristup nije pogodan za resurse koje drugi manifesti moraju predvidljivo referencirati.

Polje metadata.namespace mora odgovarati ciljnom okruženju. Izostavljanje ovog polja prepušta izbor namespace-a aktivnom kubeconfig kontekstu, što je rizično u automatizaciji. Produkcioni manifesti namespaced resursa zato uobičajeno eksplicitno navode namespace ili ga kontrolisano dodaju kroz alat za prilagođavanje konfiguracije.

Labels su kratki identifikacioni podaci namenjeni selekciji i grupisanju. Koriste ih Service selektori, Deployment selektori, NetworkPolicy pravila, upiti i brojni administrativni alati. Annotations čuvaju dodatne podatke koji nisu namenjeni selekciji: identifikator promene, vlasnika sistema, vezu ka dokumentaciji, kontrolni zbir ili instrukciju određenom kontroleru.

metadata:
  name: catalog-api
  namespace: catalog-prod
  labels:
    app.kubernetes.io/name: catalog-api
    app.kubernetes.io/instance: catalog-api-prod
    app.kubernetes.io/component: backend
    app.kubernetes.io/part-of: catalog-platform
    app.kubernetes.io/managed-by: kubectl
  annotations:
    change.example.com/ticket: CHG-2026-0715
    operations.example.com/runbook: catalog-api

Preporučene oznake sa prefiksom app.kubernetes.io nisu obavezne, ali olakšavaju standardizovano upravljanje. Organizacija treba da definiše sopstveni skup obaveznih oznaka, dozvoljene vrednosti i vlasništvo nad prefiksima. Prefiksi kubernetes.io i k8s.io rezervisani su za Kubernetes komponente i ne treba ih proizvoljno koristiti.

Spec, status i podaci kojima upravlja server

Polje spec obično predstavlja administratorsku nameru, dok status predstavlja trenutno stanje koje prijavljuju kontroleri. Administrator u izvornom manifestu u pravilu ne upisuje status. API server i kontroleri takođe dodaju polja kao što su metadata.uid, resourceVersion, generation, creationTimestamp i managedFields.

Zbog toga rezultat komande kubectl get deployment catalog-api -o yaml nije pogodan za direktno čuvanje kao novi izvorni manifest bez čišćenja. Takav izvoz sadrži stanje klastera, podrazumevane vrednosti i metapodatke konkurentnosti. Posebno je opasno ručno vraćati stari resourceVersion, jer API server može odbiti izmenu zbog konflikta.

Polje metadata.generation menja se kada se promeni željena specifikacija, dok kontroler kroz status.observedGeneration pokazuje koju generaciju je obradio. Ako je observedGeneration manji od generation, kontroler još nije obradio poslednju promenu ili ima problem. Sama činjenica da je kubectl apply vratio poruku configured zato nije dokaz da je aplikacija uspešno pokrenuta.

YAML sintaksa koja utiče na pouzdanost manifesta

YAML koristi uvlačenje razmacima za predstavljanje strukture. Tabulatori se ne smeju koristiti za uvlačenje. Dosledna praksa je dva razmaka po nivou. Mape predstavljaju parove ključ–vrednost, a liste se označavaju crticom. Greška u nivou uvlačenja može promeniti značenje dokumenta ili izazvati parsersku grešku.

spec:
  replicas: 3
  template:
    spec:
      containers:
        - name: catalog-api
          image: registry.k8s.io/e2e-test-images/agnhost:2.53
          args:
            - netexec
            - --http-port=8080
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP

Skalarne vrednosti mogu biti tekst, broj, logička vrednost ili null. Navodnici su preporučljivi kada vrednost može biti pogrešno protumačena, naročito za brojeve sa vodećim nulama, vrednosti nalik datumima i tekst true, false, null, yes ili no. Kubernetes alati koriste YAML biblioteku čije ponašanje ne mora u svim detaljima odgovarati očekivanjima iz YAML 1.2 specifikacije, pa eksplicitni navodnici smanjuju rizik.

data:
  LOG_LEVEL: "info"
  FEATURE_ENABLED: "false"
  RETRY_COUNT: "5"
  application.yaml: |
    server:
      port: 8080
    logging:
      level: info

Znak | čuva prelome redova višelinijskog teksta, dok > prelama redove u jednu logičku liniju, osim praznih redova. Komentari počinju znakom #, ali nisu deo Kubernetes API objekta i gube se kada se dokument pošalje serveru. Operativno važne informacije zato treba čuvati u annotations, dokumentaciji i sistemu za upravljanje promenama, a ne samo u YAML komentarima.

Više resursa u jednom fajlu i njihove zavisnosti

Jedan YAML fajl može sadržati više dokumenata razdvojenih linijom ---. To je korisno kada Namespace, ConfigMap, Deployment i Service čine jednu funkcionalnu celinu. Ipak, zajednički fajl ne uspostavlja transakciju: ako se prvi objekti uspešno kreiraju, a kasniji dokument ne prođe validaciju, već kreirani objekti ostaju u klasteru.

Kubernetes takođe ne garantuje aplikacioni redosled spremnosti samo zato što je redosled dokumenata naveden u fajlu. Deployment može biti prihvaćen odmah nakon ConfigMap-a, ali Pod neće postati funkcionalan dok svi potrebni resursi, image registry, mreža i storage nisu dostupni. Custom Resource se ne može kreirati pre nego što odgovarajući CustomResourceDefinition bude uspostavljen i prihvaćen.

Za složene implementacije administrator koristi jasno razdvojene faze, kubectl wait, pipeline kontrole, Kustomize, Helm ili GitOps kontroler. Izbor alata ne menja osnovnu obavezu: krajnji manifesti moraju odgovarati API šemi i politici konkretnog klastera.

Validacija pre primene

Provera treba da se obavi u više slojeva. Lokalni YAML linter može otkriti sintaksu i stil, ali ne poznaje nužno API šemu klastera. Klijentski dry-run obrađuje zahtev bez slanja na server, dok serverski dry-run šalje zahtev API serveru bez trajnog čuvanja. Serverski dry-run je vredniji jer uključuje autentikaciju, autorizaciju, API validaciju, podrazumevane vrednosti i admission obradu, pod uslovom da svi pozvani admission webhooks podržavaju dry-run.

kubectl apply --dry-run=client -f catalog-stack.yaml
kubectl apply --dry-run=server -f catalog-stack.yaml
kubectl diff -f catalog-stack.yaml

kubectl diff prikazuje razliku između postojećeg objekta i rezultata koji bi server formirao. Izlazni kod 0 znači da nema razlike, 1 da razlike postoje, a vrednost veća od 1 označava grešku. Automatizacija zato ne sme svaki nenulti kod tretirati kao neuspeh.

Validacija polja može se kontrolisati opcijom --validate=strict. Stroga validacija treba da bude podrazumevana u pipeline-u jer nepoznato ili duplirano polje često znači tipografsku grešku. Međutim, ni stroga API validacija ne može dokazati da je URL tačan, da registry sadrži sliku, da aplikacija pravilno sluša na portu ili da Service selektor pronalazi odgovarajuće Podove.

Apply semantika, vlasništvo nad poljima i konflikti

Komanda kubectl apply -f kreira objekat koji ne postoji ili izračunava izmenu postojećeg objekta. Ponovno slanje nepromenjene deklaracije ne treba da izazove novu funkcionalnu promenu. Rezultat ipak zavisi od apply mehanizma i od toga ko još menja ista polja: administrator, autoskaler, admission webhook, operator, Helm ili GitOps kontroler.

kubectl apply -f app.yaml
kubectl apply -f manifests/
kubectl apply -f -

Tradicionalni client-side apply računa trostrano poređenje između lokalnog manifesta, živog objekta i prethodne deklaracije sačuvane u anotaciji kubectl.kubernetes.io/last-applied-configuration. Objekat prvobitno napravljen drugim postupkom nema nužno pouzdanu poslednju deklaraciju, pa se prelazak pod deklarativno upravljanje planira i proverava kroz diff.

Server-Side Apply (SSA) izračunava spajanje na API serveru i beleži vlasništvo nad poljima u metadata.managedFields. Svaki upravljač koristi stabilan identitet preko --field-manager. Ako drugi manager poseduje polje koje zahtev menja, server prijavljuje konflikt. Opcija --force-conflicts prenosi vlasništvo i sme se koristiti samo kada je novi manager dokazano autoritativan.

kubectl apply --server-side \
  --field-manager=platform-admin \
  -f app.yaml

kubectl diff --server-side \
  --field-manager=platform-admin \
  -f app.yaml

kubectl get deployment catalog-api -n catalog-prod \
  -o jsonpath='{range .metadata.managedFields[*]}{.manager}{"\t"}{.operation}{"\t"}{.time}{"\n"}{end}'

Za automatizaciju je SSA često jasniji jer eksplicitno modeluje field ownership, ali migracija sa client-side apply-a zahteva testiranje. Ne treba menjati polja operatora direktno niti koristiti različit field manager pri svakom izvršavanju. Managed fields su dijagnostički trag, ali nisu zamena za audit log i poslovno odobrenje.

Direktna izmena komandom kubectl edit

kubectl edit preuzima aktuelnu reprezentaciju objekta, otvara je u editoru i nakon čuvanja šalje izmenu API serveru. Koristan je za malu, vremenski kritičnu i dokumentovanu intervenciju, ali nije deklarativni izvor istine: lokalni manifest i Git repozitorijum ostaju nepromenjeni, a GitOps kontroler može ručnu izmenu automatski poništiti.

export KUBE_EDITOR="vim"
kubectl get deployment catalog-api -n catalog-prod -o yaml \
  > change-records/catalog-api-before.yaml
kubectl edit deployment catalog-api -n catalog-prod

Snimak dobijen komandom get -o yaml sadrži serverska polja i služi kao dokaz prethodnog stanja, ne kao čist manifest za ponovno slanje. U editoru se ne menjaju status, uid, resourceVersion, creationTimestamp ni managedFields. Ako je objekat u međuvremenu izmenjen, ponovo se čita sveže stanje i prenosi samo nameravana promena.

Posle hitne intervencije administrator potvrđuje konkretno polje, stanje kontrolera i funkcionalni rezultat, a zatim istu odluku unosi u autoritativni manifest. Incident se ne zatvara dok se drift ne ukloni ili formalno prihvati.

Delete, zavisni objekti, finalizatori i bezbedno uklanjanje

kubectl delete šalje zahtev za uklanjanje objekta po imenu, manifestu ili selektoru. Brisanje po manifestu nije rollback: ono uklanja identifikovane objekte, ali ne vraća njihovu prethodnu specifikaciju. Pre brisanja proveravaju se kontekst, namespace, tačan skup pogođenih objekata, ownerReferences, finalizatori, persistent podaci i spoljne posledice operatora ili cloud kontrolera.

kubectl get deployment catalog-api -n catalog-prod \
  -o custom-columns=NAME:.metadata.name,UID:.metadata.uid,OWNERS:.metadata.ownerReferences[*].name,FINALIZERS:.metadata.finalizers

kubectl get pod -n catalog-prod -l app=catalog-api --show-labels
kubectl delete deployment catalog-api -n catalog-prod --cascade=background --wait=true

Podrazumevana politika --cascade=background dozvoljava da vlasnik nestane iz API-ja dok garbage collector u pozadini uklanja zavisne objekte. Sa foreground vlasnik ostaje u brisanju dok zavisni objekti ne budu uklonjeni, dok orphan ostavlja dependente bez vlasnika. Orphan može ostaviti aktivne resurse bez upravljača, a foreground može duže blokirati zahtev zbog zavisnosti ili finalizatora.

kubectl delete deployment catalog-api -n catalog-prod --cascade=foreground
kubectl delete replicaset catalog-api-example -n catalog-prod --cascade=orphan

Finalizer odlaže konačno uklanjanje dok odgovorni kontroler ne završi čišćenje. Objekat tada ima deletionTimestamp i ostaje vidljiv. Ručno uklanjanje finalizatora može ostaviti storage, mrežno pravilo ili cloud resurs bez vlasnika. Najpre se identifikuje finalizer, pregledaju stanje i logovi odgovornog kontrolera i otklanja osnovni uzrok.

Graceful termination daje aplikaciji vreme da završi zahteve i zatvori resurse. --grace-period=0 --force može ukloniti Pod zapis iz API-ja pre potvrde da je proces prestao na čvoru, pa nosi rizik duplog izvršavanja i gubitka podataka. Brisanje Poda kojim upravlja Deployment ili StatefulSet obično izaziva kreiranje zamene, a ne trajno smanjenje workload-a.

Rollback nije delete: izbor mehanizma oporavka

Rollback znači vraćanje sistema na prethodno provereno stanje. Za deklarativnu konfiguraciju najpouzdaniji postupak je vraćanje prethodnog odobrenog commita ili artefakta, zatim server-side dry-run, diff, apply i puna validacija. Deployment podržava kubectl rollout undo, ali taj mehanizam vraća samo Pod template; ne vraća Service, ConfigMap, Secret, PVC, RBAC, migraciju baze ili spoljnu zavisnost.

kubectl rollout history deployment/catalog-api -n catalog-prod
kubectl rollout undo deployment/catalog-api -n catalog-prod --to-revision=3
kubectl rollout status deployment/catalog-api -n catalog-prod --timeout=180s

Pre rollback-a čuvaju se diff, događaji, opis workload-a, trenutna slika i generacija kako se ne bi izgubili dokazi. Posle rollback-a proveravaju se observedGeneration, dostupne replike, EndpointSlice, logovi, metrički indikatori i poslovni smoke test. Ako je promena izmenila podatke ili šemu baze, infrastrukturni rollback može biti nedovoljan ili štetan.

Bezbednost i upravljanje osetljivim podacima

Manifest je često trajni zapis koji se kopira u repozitorijume, CI logove, artefakte i rezervne kopije. Tajne se zato ne smeju čuvati kao otvoren tekst u običnim manifestima. Kubernetes Secret sa poljem data koristi Base64 kodiranje, a ne šifrovanje. Svako ko može pročitati Secret iz API-ja ili repozitorijuma sa manifestom može dekodirati vrednost.

Produkciono rešenje može koristiti eksterni sistem za tajne, CSI integraciju, kontroler za sinhronizaciju tajni, sealed/encrypted manifest ili drugi organizaciono odobren mehanizam. Istovremeno treba uključiti enkripciju Kubernetes podataka u mirovanju, ograničiti RBAC pristup i sprečiti ispis tajni u CI logovima. Referenca na Secret može biti deo Deployment manifesta, ali sama poverljiva vrednost ne treba da bude ugrađena u javni ili nezaštićeni YAML.

Bezbednosni kontekst, zahtevi i ograničenja resursa, read-only root filesystem i zabrana eskalacije privilegija treba da budu deo standardnog aplikacionog obrasca kada ih aplikacija podržava. Manifest koji prolazi API validaciju i dalje može biti odbijen organizacionom admission politikom ako ne ispunjava Pod Security ili druga interna pravila.

Integrisani praktikum: deklarativna implementacija internog kataloškog servisa

Poslovni i tehnički kontekst. Platformski tim priprema referentni obrazac za mali interni HTTP servis. Cilj nije testiranje poslovne aplikacije, već dokaz da administrator ume da iz jednog kontrolisanog YAML fajla kreira Namespace, konfiguraciju, Deployment i Service, proveri server-side validaciju, utvrdi razliku pre promene, potvrdi funkcionalnost i bezbedno ukloni resurse.

Referentno okruženje. Koristi se Kubernetes klaster sa najmanje jednim schedulable worker čvorom, funkcionalnim mrežnim dodatkom i pristupom javnom registry-ju registry.k8s.io. Aktivni kubeconfig kontekst mora pokazivati na laboratorijski ili odobreni testni klaster. Fajlovi se čuvaju u direktorijumu ~/vanilla-k8s/lesson-14. Namespace je catalog-lab, Deployment i Service nose ime catalog-api, a ConfigMap ime catalog-api-config.

Potrebna prava. Korisnik mora imati pravo da pročita osnovno stanje klastera i da kreira, čita, menja i briše Namespace ili, u strože podeljenom okruženju, mora dobiti unapred kreiran namespace i odgovarajuća prava nad ConfigMap, Deployment, ReplicaSet, Pod i Service objektima. Minimalna prava proveravaju se komandom kubectl auth can-i; ClusterRoleBinding sa administratorskim pravima nije opravdan samo radi ovog zadatka.

  1. Potvrdite kontekst i pristup pre promene. Najveći operativni rizik nije YAML sintaksa već primena ispravnog manifesta na pogrešan klaster. Zabeležite aktivni kontekst, server i identitet koji kubeconfig koristi.
    mkdir -p ~/vanilla-k8s/lesson-14
    cd ~/vanilla-k8s/lesson-14
    
    kubectl config current-context
    kubectl config view --minify
    kubectl cluster-info
    kubectl get nodes
    Validacija: API server mora biti dostupan, a najmanje jedan worker čvor treba da bude u stanju Ready. Ako ime konteksta ili adresa servera ne odgovaraju odobrenom laboratorijskom klasteru, postupak se prekida pre bilo kakve izmene.
  2. Proverite najmanji potreban skup ovlašćenja. Sledeće provere ne menjaju klaster, već odgovaraju da li aktivni identitet ima potrebne dozvole.
    kubectl auth can-i create namespaces
    kubectl auth can-i create configmaps --namespace=catalog-lab
    kubectl auth can-i create deployments.apps --namespace=catalog-lab
    kubectl auth can-i create services --namespace=catalog-lab
    kubectl auth can-i delete namespaces
    Validacija: Za potpuni scenario odgovori treba da budu yes. Odgovor no nije tehnička greška manifesta, već ograničenje autorizacije. Administrator tada traži od vlasnika klastera da kreira namespace ili dodeli namensku Role i RoleBinding, umesto da zahteva trajni cluster-admin.
  3. Kreirajte povezani manifest. Fajl opisuje četiri resursa. ConfigMap sadrži bezopasnu konfiguraciju, Deployment pokreće dve replike testnog HTTP procesa, a Service bira Podove prema istoj stabilnoj oznaci. Probes koriste ugrađenu HTTP putanju /healthz.
    cat > catalog-stack.yaml <<'EOF'
    apiVersion: v1
    kind: Namespace
    metadata:
      name: catalog-lab
      labels:
        app.kubernetes.io/part-of: catalog-platform
        environment: lab
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: catalog-api-config
      namespace: catalog-lab
      labels:
        app.kubernetes.io/name: catalog-api
        app.kubernetes.io/part-of: catalog-platform
    data:
      ENVIRONMENT: "lab"
      LOG_LEVEL: "info"
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: catalog-api
      namespace: catalog-lab
      labels:
        app.kubernetes.io/name: catalog-api
        app.kubernetes.io/instance: catalog-api-lab
        app.kubernetes.io/component: backend
        app.kubernetes.io/part-of: catalog-platform
      annotations:
        change.example.com/ticket: "LAB-15"
    spec:
      replicas: 2
      revisionHistoryLimit: 3
      selector:
        matchLabels:
          app.kubernetes.io/name: catalog-api
          app.kubernetes.io/instance: catalog-api-lab
      template:
        metadata:
          labels:
            app.kubernetes.io/name: catalog-api
            app.kubernetes.io/instance: catalog-api-lab
            app.kubernetes.io/component: backend
            app.kubernetes.io/part-of: catalog-platform
        spec:
          containers:
            - name: catalog-api
              image: registry.k8s.io/e2e-test-images/agnhost:2.53
              imagePullPolicy: IfNotPresent
              args:
                - netexec
                - --http-port=8080
              envFrom:
                - configMapRef:
                    name: catalog-api-config
              ports:
                - name: http
                  containerPort: 8080
                  protocol: TCP
              readinessProbe:
                httpGet:
                  path: /healthz
                  port: http
                initialDelaySeconds: 2
                periodSeconds: 5
                timeoutSeconds: 2
                failureThreshold: 3
              livenessProbe:
                httpGet:
                  path: /healthz
                  port: http
                initialDelaySeconds: 10
                periodSeconds: 10
                timeoutSeconds: 2
                failureThreshold: 3
              resources:
                requests:
                  cpu: 20m
                  memory: 32Mi
                limits:
                  cpu: 200m
                  memory: 128Mi
              securityContext:
                allowPrivilegeEscalation: false
                capabilities:
                  drop:
                    - ALL
          terminationGracePeriodSeconds: 30
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: catalog-api
      namespace: catalog-lab
      labels:
        app.kubernetes.io/name: catalog-api
        app.kubernetes.io/part-of: catalog-platform
    spec:
      type: ClusterIP
      selector:
        app.kubernetes.io/name: catalog-api
        app.kubernetes.io/instance: catalog-api-lab
      ports:
        - name: http
          port: 80
          targetPort: http
          protocol: TCP
    EOF
    Validacija: Proverite da fajl postoji i pregledajte ga pre slanja. U realnom procesu pregled obavlja i drugi član tima kroz pull request.
    test -s catalog-stack.yaml
    sed -n '1,260p' catalog-stack.yaml
  4. Proverite sintaksu i serversku obradu bez trajne promene. Klijentski dry-run otkriva osnovne probleme, a serverski dry-run proverava manifest prema stvarnom API serveru i admission pravilima.
    kubectl apply --dry-run=client --validate=strict -f catalog-stack.yaml
    kubectl apply --dry-run=server --validate=strict -f catalog-stack.yaml
    Očekivani rezultat: Za svaki dokument prikazuje se created (dry run). Nijedan resurs ne sme ostati u klasteru.
    kubectl get namespace catalog-lab
    Validacija: Očekuje se NotFound. Ako serverski dry-run prijavi Forbidden, problem je RBAC. Ako prijavi nepoznato polje ili pogrešan tip, problem je API šema. Ako admission webhook odbije objekat, poruka treba da navede prekršenu politiku.
  5. Pregledajte planiranu razliku. Pošto resursi još ne postoje, diff ih prikazuje kao nove dokumente.
    kubectl diff -f catalog-stack.yaml
    Validacija: Izlazni kod 1 uz prikaz dodatih linija predstavlja očekivanu razliku, a ne neuspeh. Kod veći od 1 zahteva prekid i analizu greške. U CI sistemu ovo razlikovanje mora biti eksplicitno implementirano.
  6. Primenite odobreni manifest. Primena kreira namespace i namespaced resurse. Pošto postupak nije transakcija, izlaz svake stavke treba pregledati.
    kubectl apply --validate=strict -f catalog-stack.yaml
    Očekivani rezultat: Namespace, ConfigMap, Deployment i Service dobijaju status created. Odmah proverite da su objekti u ispravnom namespace-u.
    kubectl get namespace catalog-lab
    kubectl get configmap,deployment,replicaset,pod,service -n catalog-lab -o wide
  7. Sačekajte da Deployment ostvari željeno stanje. Prihvatanje manifesta nije isto što i završena implementacija. Rollout čeka da kontroler i kubelet pokrenu dovoljan broj spremnih Podova.
    kubectl rollout status deployment/catalog-api -n catalog-lab --timeout=120s
    kubectl wait --for=condition=Available deployment/catalog-api -n catalog-lab --timeout=120s
    Validacija: Deployment mora imati dve željene, dve ažurirane, dve dostupne i dve spremne replike.
    kubectl get deployment catalog-api -n catalog-lab
    kubectl get pods -n catalog-lab \
      -l app.kubernetes.io/name=catalog-api \
      -o custom-columns=NAME:.metadata.name,PHASE:.status.phase,READY:.status.containerStatuses[0].ready,RESTARTS:.status.containerStatuses[0].restartCount
  8. Proverite vezu labels–selector–endpoints. Service je funkcionalan samo ako njegov selektor pronalazi spremne Podove. Prazan EndpointSlice uz zdrave Podove najčešće ukazuje na neusklađene oznake ili pogrešan namespace.
    kubectl get service catalog-api -n catalog-lab -o yaml
    kubectl get endpointslice -n catalog-lab \
      -l kubernetes.io/service-name=catalog-api
    kubectl get pods -n catalog-lab \
      -l 'app.kubernetes.io/name=catalog-api,app.kubernetes.io/instance=catalog-api-lab' \
      --show-labels
    Validacija: EndpointSlice treba da sadrži dve adrese spremnih Podova i port 8080. Service port 80 treba da koristi imenovani targetPort: http, koji se razrešava na kontejnerski port 8080.
  9. Izvršite završnu funkcionalnu proveru. Port-forward je privremeni administratorski tunel i ne predstavlja produkcioni ingress. Pogodan je za kontrolisanu proveru ClusterIP servisa sa radne stanice.
    kubectl port-forward -n catalog-lab service/catalog-api 18080:80 >port-forward.log 2>&1 &
    PF_PID=$!
    sleep 3
    curl --fail --silent --show-error http://127.0.0.1:18080/healthz
    kill "$PF_PID"
    wait "$PF_PID" 2>/dev/null || true
    cat port-forward.log
    Očekivani rezultat: HTTP zahtev treba da završi izlaznim kodom 0 i vrati odgovor endpointa za zdravlje. Log port-forward.log služi za razlikovanje lokalnog konflikta porta, prekida tunela i greške povezivanja sa Podom.
  10. Izvršite negativni test stroge validacije. Napravite zaseban neispravan manifest sa tipografskom greškom replica umesto replicas. Ne menjajte odobreni fajl.
    cat > invalid-deployment.yaml <<'EOF'
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: invalid-catalog-api
      namespace: catalog-lab
    spec:
      replica: 2
      selector:
        matchLabels:
          app: invalid-catalog-api
      template:
        metadata:
          labels:
            app: invalid-catalog-api
        spec:
          containers:
            - name: web
              image: registry.k8s.io/e2e-test-images/agnhost:2.53
              args:
                - netexec
                - --http-port=8080
    EOF
    
    kubectl apply --dry-run=server --validate=strict -f invalid-deployment.yaml
    Validacija: API server treba da odbije objekat zbog nepoznatog polja. Proverite da resurs nije kreiran.
    kubectl get deployment invalid-catalog-api -n catalog-lab
    Očekuje se NotFound. Ovaj test pokazuje vrednost stroge validacije, ali ne dokazuje da će svaki semantički pogrešan manifest biti odbijen.
  11. Izmenite deklarativno stanje i pregledajte posledice. Promenite broj replika sa dve na tri u izvornom manifestu. Prvo pregledajte diff, a tek zatim primenite promenu.
    sed -i 's/replicas: 2/replicas: 3/' catalog-stack.yaml
    
    kubectl apply --dry-run=server --validate=strict -f catalog-stack.yaml
    kubectl diff -f catalog-stack.yaml
    kubectl apply -f catalog-stack.yaml
    kubectl rollout status deployment/catalog-api -n catalog-lab --timeout=120s
    Validacija: Diff treba da pokaže samo očekivanu promenu broja replika. Nakon primene Deployment mora imati tri dostupne replike, a EndpointSlice tri spremne adrese.
    kubectl get deployment catalog-api -n catalog-lab
    kubectl get pods -n catalog-lab -l app.kubernetes.io/name=catalog-api
    kubectl get endpointslice -n catalog-lab \
      -l kubernetes.io/service-name=catalog-api
  12. Simulirajte neuspešan rollout i izvedite deklarativni rollback. Sačuvajte dobru verziju manifesta, zatim u radnoj kopiji zamenite image nepostojećom oznakom. Ovo je laboratorijska simulacija bez gubitka podataka; ne izvodi se u produkcionom namespace-u.
    cp catalog-stack.yaml catalog-stack-good.yaml
    sed -i 's#agnhost:2.53#agnhost:nepostojeca-oznaka#' catalog-stack.yaml
    
    kubectl apply --dry-run=server --validate=strict -f catalog-stack.yaml
    kubectl diff -f catalog-stack.yaml
    kubectl apply -f catalog-stack.yaml
    kubectl rollout status deployment/catalog-api -n catalog-lab --timeout=60s
    Očekivani simptom: API prihvata sintaksno i semantički validan naziv slike, ali rollout ne završava. Novi Pod prelazi u ErrImagePull ili ImagePullBackOff. Ovo dokazuje granicu API validacije: postojanje image-a proverava kubelet tek tokom izvršavanja.
    kubectl get pods -n catalog-lab -o wide
    kubectl describe pods -n catalog-lab -l app.kubernetes.io/name=catalog-api
    kubectl get events -n catalog-lab --sort-by=.metadata.creationTimestamp
    Rollback: vratite odobreni manifest kao izvor istine, pregledajte obrnuti diff i ponovo ga primenite.
    mv catalog-stack-good.yaml catalog-stack.yaml
    kubectl apply --dry-run=server --validate=strict -f catalog-stack.yaml
    kubectl diff -f catalog-stack.yaml
    kubectl apply -f catalog-stack.yaml
    kubectl rollout status deployment/catalog-api -n catalog-lab --timeout=120s
    Kriterijum oporavka: Deployment ponovo koristi image agnhost:2.53, ima tri dostupne replike, broj restartovanja ne raste, EndpointSlice sadrži tri spremne adrese i HTTP test ponovo uspeva. U change zapisu ostaju simptom, dokaz uzroka, korektivna akcija i rezultat validacije.
  13. Pregledajte događaje i logove relevantne za troubleshooting. Aplikacioni stdout i stderr preuzimaju se kroz API, dok sistemski uzroci raspoređivanja i pokretanja često postoje u Events zapisima i opisima Podova.
    kubectl get events -n catalog-lab --sort-by=.metadata.creationTimestamp
    kubectl describe deployment catalog-api -n catalog-lab
    kubectl describe pods -n catalog-lab -l app.kubernetes.io/name=catalog-api
    kubectl logs -n catalog-lab \
      -l app.kubernetes.io/name=catalog-api \
      --all-containers=true \
      --prefix=true \
      --tail=50
    Tumačenje: FailedScheduling upućuje na kapacitet, taints, affinity ili ograničenja resursa; ErrImagePull i ImagePullBackOff na registry, naziv slike, mrežu ili kredencijale; neuspešna readiness provera ostavlja Pod pokrenutim ali ga uklanja iz spremnih endpointa; restartovanja uz CrashLoopBackOff zahtevaju pregled trenutnih i prethodnih logova komandom kubectl logs --previous.
  14. Dokumentujte prihvatanje i stanje promene. Sačuvajte izlaze koji dokazuju šta je primenjeno i kakvo je stanje ostvareno, ali ne izvozite tajne.
    kubectl get deployment catalog-api -n catalog-lab -o wide > acceptance-deployment.txt
    kubectl get service catalog-api -n catalog-lab -o wide > acceptance-service.txt
    kubectl get endpointslice -n catalog-lab \
      -l kubernetes.io/service-name=catalog-api \
      -o wide > acceptance-endpoints.txt
    kubectl get events -n catalog-lab \
      --sort-by=.metadata.creationTimestamp > acceptance-events.txt
    Merljivi kriterijumi prihvatanja: serverski dry-run prolazi bez upozorenja; Deployment ima tri željene i tri dostupne replike; svi Podovi su Running i spremni; Service ima tri spremna endpointa; HTTP /healthz vraća uspešan odgovor; nema ponavljajućih upozorenja niti restartovanja kontejnera.
  15. Izvršite cleanup nakon laboratorijske vežbe. Upozorenje: brisanje namespace-a uklanja sve namespaced resurse u njemu. U produkciji se ova komanda ne koristi bez odobrenja, provere vlasništva, zaštite podataka i plana oporavka. Za ovaj izolovani lab namespace cleanup je očekivan.
    kubectl delete -f catalog-stack.yaml --wait=true
    kubectl wait --for=delete namespace/catalog-lab --timeout=120s
    Validacija: Namespace i svi resursi moraju nestati.
    kubectl get namespace catalog-lab
    kubectl get all -n catalog-lab
    Očekuje se NotFound. Ako namespace ostane u stanju Terminating, proveravaju se preostali resursi, finalizers i dostupnost kontrolera; finalizer se ne uklanja ručno bez razumevanja posledica.

Tipične greške i način njihovog razlikovanja

Simptom Najverovatnija oblast Prva provera
YAML parser prijavljuje liniju i kolonu Uvlačenje, navodnici ili neispravna struktura YAML-a kubectl apply --dry-run=client -f fajl.yaml
Unknown field ili invalid value Pogrešna API šema, naziv polja ili tip vrednosti kubectl explain i server-side dry-run
Forbidden RBAC ili admission zabrana kubectl auth can-i i tekst odgovora API servera
Deployment postoji, ali nema dostupnih replika Scheduling, image pull, probe, resursi ili aplikacija kubectl describe pod, Events i logs
Service nema endpointe Neusklađeni selektori, oznake ili readiness Uporediti Service selector, Pod labels i EndpointSlice
Apply stalno menja ista polja Drugi field manager, webhook ili automatizacija kubectl diff i metadata.managedFields

Administratorske prakse

Kontrolna lista

Zaključak

YAML manifest je ugovor između administratora i Kubernetes API-ja: opisuje nameravano stanje, ali ne garantuje da će infrastruktura, aplikacija i sve spoljne zavisnosti to stanje uspešno ostvariti. Pouzdan rad zahteva razumevanje API grupa i verzija, strukture objekata, odnosa između labels i selector-a, razlike između spec i status, kao i podataka kojima upravlja server.

Nakon ove lekcije administrator treba da ume da izradi povezane manifeste, proveri ih prema stvarnom API serveru, pregleda planiranu razliku, primeni promenu i potvrdi rezultat kroz rollout, Events, logs, EndpointSlice i funkcionalni test. Takođe mora da razlikuje YAML sintaksnu grešku, API validacionu grešku, RBAC zabranu, admission odbijanje i runtime problem aplikacije.

Produkcioni rizik nastaje kada se manifest primenjuje na pogrešan kontekst, kada se tajne čuvaju u otvorenom obliku, kada se selector promeni bez procene posledica, kada se kopirani server-side metapodaci tretiraju kao izvor konfiguracije ili kada se poruka configured pogrešno smatra dokazom uspeha. Deklarativni model ne ukida potrebu za change kontrolom, backup-om, monitoringom, funkcionalnom proverom i jasnim vlasništvom.

Administrator sme menjati samo resurse i polja za koja ima poslovno odobrenje i tehničko ovlašćenje. Problemi sa politikama klastera, nepoznatim CRD resursima, konfliktima field manager-a, trajno zaglavljenim finalizer-ima, gubitkom podataka ili promenama koje zahtevaju cluster-scoped privilegije predstavljaju razlog za eskalaciju odgovornom platformskom, bezbednosnom ili aplikacionom timu. Kvalitet administratorskog rada meri se time da je promena ponovljiva, pregledana, proverljiva, reverzibilna i dokumentovana, a ne samo time da je API server prihvatio YAML dokument.

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