Vanilla Kubernetes

Drugi deo: Workload platforma, mreža, podaci i bezbednost
StatefulSet – aplikacije kojima su važni identitet i trajni podaci
VII. Storage i stateful aplikacije
32. StatefulSet i Headless Service – stabilan identitet, redosled i trajni podaci

Većina kontejnerskih aplikacija projektovana je tako da pojedinačna instanca može biti uklonjena i zamenjena drugom bez posledica. Deployment je zato pogodan za stateless servise čiji su podovi međusobno zamenljivi. Baze podataka, distribuirani sistemi, brokeri poruka, klasteri za pretragu i aplikacije sa lokalnim trajnim stanjem imaju drugačije zahteve: instanca često mora da zadrži prepoznatljivo ime, stabilnu mrežnu adresu, sopstveni disk i kontrolisan redosled pokretanja ili gašenja. Kubernetes za takve radne terete pruža objekat StatefulSet.

StatefulSet ne pretvara automatski aplikaciju u visoko dostupnu aplikaciju, ne sinhronizuje podatke između replika i ne rešava izbor primarne instance. Njegova uloga je da obezbedi stabilan identitet i determinističko upravljanje podovima. Replikacija, konsenzus, failover, backup i oporavak ostaju odgovornost same aplikacije, njenog operatora ili posebno projektovanog administrativnog postupka.

Zašto stateful aplikacijama nije dovoljan Deployment

Pod kojim upravlja Deployment dobija ime sa promenljivim sufiksom, na primer web-7c98b7f9b5-kp2xm. Kada se pod zameni, nova instanca dobija drugo ime i novi mrežni identitet. Takvo ponašanje je poželjno kada su sve instance iste i kada podaci žive u spoljašnjoj bazi, objekt skladištu ili drugom nezavisnom servisu.

StatefulSet svakoj replici dodeljuje stabilan ordinalni broj. Ako se objekat zove docstore, podovi se nazivaju docstore-0, docstore-1 i docstore-2. Kada se docstore-1 ponovo kreira, zadržava isto logičko ime i ponovo dobija PVC namenjen upravo toj replici. Aplikacija može koristiti ordinal za izbor uloge, formiranje klasterskog članstva, particionisanje podataka ili određivanje redosleda inicijalizacije.

Ordinali podrazumevano počinju od nule. Polje spec.ordinals.start, stabilno od Kubernetes 1.31, omogućava drugi početni ordinal kada aplikativni model to izričito zahteva. Kubernetes svakom podu dodaje labelu apps.kubernetes.io/pod-index sa njegovim ordinalom; ona je pogodnija za selekciju, metrike i konfiguraciju od parsiranja imena poda. Promena početnog ordinala nije bezazleno preimenovanje: menja skup identiteta i nazive PVC-ova, pa se planira kao migracija članstva i podataka.

Osobina Deployment StatefulSet
Identitet podova Podovi su međusobno zamenljivi Svaki pod ima stabilno ime i ordinal
Mrežni identitet Pristup se obično obavlja preko zajedničkog servisa Svaki pod može imati stabilan DNS zapis
Trajno skladište Može koristiti PVC, ali nema automatski poseban PVC po replici volumeClaimTemplates kreira poseban PVC za svaki pod
Redosled operacija Replike se uglavnom tretiraju paralelno Podrazumevano kontrolisano kreiranje, ažuriranje i gašenje
Tipična namena Web API, frontend, stateless worker Baze, brokeri, distribuirani sistemi i klasteri sa identitetom

Stabilan identitet, ordinal i headless servis

StatefulSet koristi polje spec.serviceName kako bi se povezao sa servisom koji upravlja mrežnim domenom njegovih podova. Uobičajeno se koristi headless Service, odnosno servis sa vrednošću clusterIP: None. Takav servis ne obezbeđuje jednu virtuelnu ClusterIP adresu iza koje se balansiraju svi podovi, već omogućava DNS-u da objavi adrese pojedinačnih instanci.

U namespace-u stateful-lab, StatefulSet docstore i headless servis docstore-headless daju imena poput:

docstore-0.docstore-headless.stateful-lab.svc.cluster.local
docstore-1.docstore-headless.stateful-lab.svc.cluster.local
docstore-2.docstore-headless.stateful-lab.svc.cluster.local

Stabilnost se odnosi na logički identitet, a ne na nepromenljivu IP adresu. IP adresa poda može se promeniti posle ponovnog kreiranja. Klijenti i članovi klastera zato treba da koriste DNS ime, a ne zapamćenu IP adresu. Administrator mora uzeti u obzir i DNS keširanje: neuspešan upit može privremeno ostati u kešu, pa aplikacija koja odmah traži novokreirani pod može kratko dobijati negativan odgovor.

Polje publishNotReadyAddresses: true ponekad se koristi kada aplikacija mora da otkrije buduće članove pre nego što oni postanu Ready. To je čest zahtev sistema koji tokom inicijalizacije formiraju klaster. Ova opcija se ne uključuje rutinski, jer omogućava DNS objavljivanje podova koji još nisu spremni da prihvate normalan saobraćaj.

Governing Service treba kreirati pre StatefulSet-a. Headless servis obezbeđuje otkrivanje članova, ali često nije dovoljan kao klijentska ulazna tačka. Produkcioni sistem zato može imati i drugi, običan Service koji bira samo Ready podove ili samo replike određene uloge. Aplikacija ne sme zaključivati ko je lider samo iz DNS redosleda: DNS ne pruža konsenzus, fencing ni garanciju prioriteta odgovora.

Trajno skladište kroz volumeClaimTemplates

Najvažnija veza između StatefulSet-a i trajnog skladištenja ostvaruje se pomoću volumeClaimTemplates. Kubernetes za svaki ordinal kreira poseban PersistentVolumeClaim. Za pod docstore-0 nastaje PVC data-docstore-0, za sledeću repliku data-docstore-1 i tako dalje. Svaki pod ponovo koristi svoj zahtev kada bude zamenjen.

StatefulSet sam po sebi ne obezbeđuje disk. Klaster mora imati odgovarajući StorageClass, CSI drajver i skladišni sistem ili unapred pripremljene PersistentVolume objekte. Ako dinamičko provisioniranje ne radi, PVC ostaje u stanju Pending, a pod se najčešće ne može rasporediti. Administrator tada proverava događaje PVC-a, StorageClass, CSI kontrolere, dostupne kapacitete i topološka ograničenja skladišta.

Pristupni režim ReadWriteOnce znači da volumen može biti priključen za čitanje i pisanje sa jednog noda; ne znači nužno da ga može koristiti samo jedan pod. Tačno ponašanje zavisi od drajvera i načina montiranja. Kada je potrebna stroga zaštita da isti volumen koristi samo jedan pod u celom klasteru, podržani CSI drajver može koristiti ReadWriteOncePod. Administrator mora proveriti mogućnosti konkretnog drajvera, a ne zaključivati samo na osnovu naziva pristupnog režima.

PVC-ovi se tradicionalno ne brišu automatski kada se StatefulSet obriše ili smanji broj replika, čime se podaci štite od slučajnog gubitka. Savremeni Kubernetes API podržava persistentVolumeClaimRetentionPolicy, sa ponašanjem Retain ili Delete za brisanje StatefulSet-a i smanjivanje broja replika. U produkciji je Retain bezbedniji podrazumevani izbor. Politika Delete zahteva potvrđenu backup strategiju, jasno vlasništvo nad podacima i testiran postupak oporavka.

Ova retention politika je stabilna od Kubernetes 1.32 i podrazumevano zadržava PVC-ove. Na starijim klasterima treba proveriti dostupnost API polja i feature gate StatefulSetAutoDeletePVC. Ona upravlja brisanjem PVC objekta, ali konačna sudbina stvarnog storage resursa zavisi i od persistentVolumeReclaimPolicy pripadajućeg PV-a. Kombinacija whenScaled: Delete i PV politike Delete može ukloniti i backend volumen; zato se oba nivoa proveravaju pre skaliranja naniže.

Redosled kreiranja, skaliranja i gašenja

Podrazumevana vrednost podManagementPolicy: OrderedReady nalaže kontroleru da podove kreira po rastućem ordinalu. docstore-0 mora postati Ready pre kreiranja docstore-1, a zatim se čeka docstore-2. Pri smanjenju broja replika podovi se uklanjaju obrnutim redosledom. Ovo ponašanje odgovara sistemima kod kojih naredni član zavisi od prethodnog.

Vrednost Parallel omogućava paralelno kreiranje i uklanjanje podova. Ona je pogodna samo kada aplikacija nema zahtev za strogo uređenim članstvom. Parallel ne ukida stabilna imena i PVC-ove, ali uklanja čekanje između ordinala. Pre promene administrator mora proveriti dokumentaciju aplikacije, jer ubrzavanje skaliranja može izazvati istovremeni bootstrap više članova, konflikt u izboru lidera ili preopterećenje skladišta.

Opcionalno polje minReadySeconds određuje koliko sekundi novokreirani pod mora neprekidno biti Running i Ready, bez pada kontejnera, pre nego što se smatra Available za napredovanje rolling update-a. Podrazumevana vrednost je nula, odnosno nema dodatnog perioda čekanja. Za aplikacije kojima je posle Ready probe potrebno vreme za stabilizaciju, razumna nenulta vrednost može sprečiti prebrzo ažuriranje sledeće replike.

Ažuriranje StatefulSet-a

Strategija RollingUpdate ažurira podove obrnutim ordinalnim redosledom. Kontroler obično čeka da ažurirani pod postane Running i Ready pre prelaska na sledeći. Polje partition omogućava da se ažuriraju samo podovi čiji je ordinal jednak ili veći od zadate vrednosti. Time se može izvesti kontrolisani canary postupak, na primer prvo ažurirati samo docstore-2, proveriti ga, zatim smanjiti particiju na 1 i na kraju na 0.

Alternativna strategija OnDelete ne zamenjuje pod automatski nakon izmene šablona. Administrator ili automatizacija moraju obrisati svaki pod kako bi bio kreiran iz nove specifikacije. Ova strategija daje ručnu kontrolu, ali povećava rizik da različite replike dugo koriste različite verzije.

Polje rollingUpdate.maxUnavailable omogućava istovremenu zamenu više podova, ali je u Kubernetes 1.35 i dalje beta mogućnost i odgovarajući feature gate je podrazumevano isključen. Ne treba ga stavljati u prenosiv manifest bez provere servera. Čak i kada je omogućen, vrednost veća od jedan prihvatljiva je samo ako aplikativni kvorum, replikacija, PDB i kapacitet storage sistema dopuštaju toliki paralelni gubitak članova.

Posebno važan operativni problem nastaje kada novi šablon proizvodi pod koji nikada ne postane Ready, na primer zbog pogrešne slike ili neispravne konfiguracije. Posle vraćanja StatefulSet specifikacije na ispravnu verziju može biti potrebno ručno obrisati već kreirani neispravan pod kako bi kontroler napravio novu instancu iz popravljene specifikacije. Administrator zato tokom ažuriranja prati podove, revision oznake, događaje i aplikativne logove, a ne samo rezultat komande kubectl apply.

Readiness, liveness i zaštita dostupnosti

Readiness proba određuje da li je instanca spremna za servisni saobraćaj i utiče na napredovanje uređenog ažuriranja. Liveness proba treba da otkrije proces koji više ne može da se oporavi bez restarta. Preagresivna liveness proba može napraviti restart petlju upravo dok baza ili distribuirani servis obavlja dug oporavak podataka. Za spor početak rada koristi se startup proba, koja odlaže aktiviranje liveness i readiness proba dok se aplikacija ne inicijalizuje.

PodDisruptionBudget ograničava dobrovoljne prekide, kao što su drain noda ili određene operacije održavanja, ali ne sprečava kvar noda, direktno brisanje poda ili sve oblike administratorske promene. PDB takođe ne garantuje dostupnost ako aplikacija nema dovoljnu replikaciju ili ako su sve replike raspoređene u istom failure domenu.

Za produkcione klastere potrebno je kombinovati PDB sa topologySpreadConstraints, pod anti-affinity pravilima ili odgovarajućim operatorskim mehanizmima. Cilj je da kvar jednog noda ili zone ne ukloni većinu članova. Pravila raspoređivanja moraju biti realna u odnosu na broj nodova; prestroga obavezna anti-affinity politika može ostaviti podove trajno u stanju Pending.

Kada StatefulSet jeste, a kada nije odgovarajuće rešenje

StatefulSet je opravdan kada aplikacija koristi stabilno članstvo, poseban trajni volumen po replici, ordinalnu ulogu ili kontrolisan redosled operacija. Tipični primeri su relacioni i NoSQL sistemi, koordinacioni servisi, distribuirani redovi, pretraživački klasteri i druge aplikacije čiji proizvođač izričito podržava rad u Kubernetes-u.

StatefulSet nije potreban samo zato što aplikacija zapisuje podatke. Jedna aplikacija može biti stateless, dok podatke čuva u upravljanoj bazi ili objekt skladištu. Takođe nije dovoljan za aplikaciju koja nije projektovana za distribuirani rad. Pokretanje tri nezavisne baze sa tri različita PVC-a ne stvara automatski jedan redundantni klaster baze podataka.

Kada za tehnologiju postoji zreo Kubernetes Operator, on je često sigurniji od ručno napisanog StatefulSet-a. Operator može upravljati bootstrap postupkom, članstvom, sertifikatima, backup-om, izborom lidera i bezbednim ažuriranjem. Administrator ipak mora razumeti StatefulSet, jer operator najčešće koristi iste osnovne Kubernetes objekte i jer dijagnostika zahteva razumevanje podova, PVC-ova, servisa i događaja.

Integrisani praktikum: StatefulSet sa stabilnim identitetom i posebnim diskom po replici

Poslovni i tehnički kontekst.

Interni servis za obradu dokumenata koristi tri radne instance. Svaka instanca čuva sopstveni lokalni identifikacioni zapis i skup obrađenih test podataka. Cilj praktikuma nije izgradnja distribuirane baze, već proverljiva demonstracija svojstava na kojima se takvi sistemi zasnivaju: stabilnog ordinalnog identiteta, DNS imena, zasebnog PVC-a po replici, opstanka podataka posle zamene poda i kontrolisanog skaliranja.

Referentno okruženje i preduslovi.

U produkciji prava treba obezbediti namespaced Role i RoleBinding objektima. Privilegije za menjanje StorageClass-a, PersistentVolume objekata ili CSI komponenti nisu potrebne za redovnu implementaciju i ne treba ih dodeljivati aplikativnom administratoru.

  1. Napravite radni direktorijum i proverite kontekst. Sve manifest datoteke biće sačuvane u direktorijumu statefulset-lab. Pre promene treba potvrditi da kubectl pokazuje na očekivani klaster i identitet.
    mkdir -p statefulset-lab
    cd statefulset-lab
    kubectl config current-context
    kubectl auth whoami
    kubectl auth can-i create statefulsets.apps --namespace stateful-lab
    kubectl auth can-i create persistentvolumeclaims --namespace stateful-lab
    kubectl auth can-i create pods/exec --namespace stateful-lab
    Validacija: Kontekst mora odgovarati laboratorijskom klasteru, a provere potrebnih prava treba da vrate yes. Ako kubectl auth whoami nije podržan u korišćenoj verziji klijenta ili servera, identitet proverite kroz aktuelni kubeconfig i proces izdavanja pristupa.
  2. Proverite skladište pre kreiranja aplikacije. Potrebno je utvrditi koji StorageClass je podrazumevan, koji provisioner koristi i kakav je njegov režim vezivanja volumena.
    kubectl get storageclass
    kubectl get storageclass -o custom-columns='NAME:.metadata.name,DEFAULT:.metadata.annotations.storageclass\.kubernetes\.io/is-default-class,PROVISIONER:.provisioner,BINDING:.volumeBindingMode,EXPANSION:.allowVolumeExpansion'
    Validacija: Najmanje jedan StorageClass treba da ima oznaku podrazumevane klase ili se njegovo ime mora eksplicitno uneti u kasniji manifest. Provisioner mora pripadati instaliranom CSI drajveru. Ako nema odgovarajuće klase, zaustavite implementaciju i eskalirajte timu koji upravlja skladištem.
  3. Kreirajte namespace sa bezbednosnim oznakama. Referentni workload radi bez root korisnika i bez dodatnih Linux capabilities, pa namespace može primeniti restricted Pod Security profil.
    cat > 00-namespace.yaml <<'EOF'
    apiVersion: v1
    kind: Namespace
    metadata:
      name: stateful-lab
      labels:
        pod-security.kubernetes.io/enforce: restricted
        pod-security.kubernetes.io/audit: restricted
        pod-security.kubernetes.io/warn: restricted
    EOF
    kubectl apply -f 00-namespace.yaml
    kubectl get namespace stateful-lab --show-labels
    Validacija: Namespace mora biti u stanju Active, a tri Pod Security oznake treba da imaju vrednost restricted.
  4. Kreirajte headless servis. Servis neće imati ClusterIP adresu. Njegova svrha je objavljivanje DNS zapisa pojedinačnih podova.
    cat > 10-headless-service.yaml <<'EOF'
    apiVersion: v1
    kind: Service
    metadata:
      name: docstore-headless
      namespace: stateful-lab
      labels:
        app.kubernetes.io/name: docstore
    spec:
      clusterIP: None
      publishNotReadyAddresses: true
      selector:
        app.kubernetes.io/name: docstore
      ports:
        - name: http
          port: 8080
          targetPort: http
    EOF
    kubectl apply -f 10-headless-service.yaml
    kubectl get service docstore-headless -n stateful-lab -o wide
    Validacija: Kolona CLUSTER-IP mora prikazati None. Selector mora odgovarati labeli koja će biti postavljena na podove.
  5. Kreirajte StatefulSet sa tri replike i zasebnim PVC-ovima. Init kontejner upisuje ordinalni hostname samo ako identifikacioni fajl još ne postoji. Glavni kontejner zatim iz trajnog direktorijuma formira stranicu koja prikazuje sačuvani identitet. Pod radi kao neprivilegovani korisnik.
    cat > 20-statefulset.yaml <<'EOF'
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: docstore
      namespace: stateful-lab
      labels:
        app.kubernetes.io/name: docstore
    spec:
      serviceName: docstore-headless
      replicas: 3
      podManagementPolicy: OrderedReady
      minReadySeconds: 5
      persistentVolumeClaimRetentionPolicy:
        whenDeleted: Retain
        whenScaled: Retain
      selector:
        matchLabels:
          app.kubernetes.io/name: docstore
      updateStrategy:
        type: RollingUpdate
        rollingUpdate:
          partition: 0
      template:
        metadata:
          labels:
            app.kubernetes.io/name: docstore
        spec:
          automountServiceAccountToken: false
          terminationGracePeriodSeconds: 30
          securityContext:
            runAsNonRoot: true
            runAsUser: 101
            runAsGroup: 101
            fsGroup: 101
            seccompProfile:
              type: RuntimeDefault
          initContainers:
            - name: initialize-identity
              image: busybox:1.36.1
              command:
                - sh
                - -ec
                - |
                  if [ ! -f /var/lib/docstore/identity.txt ]; then
                    printf '%s\n' "${HOSTNAME}" > /var/lib/docstore/identity.txt
                  fi
                  printf '<html><body><h1>%s</h1><p>Persistent identity: %s</p></body></html>\n' \
                    "${HOSTNAME}" "$(cat /var/lib/docstore/identity.txt)" \
                    > /var/lib/docstore/index.html
              securityContext:
                allowPrivilegeEscalation: false
                capabilities:
                  drop:
                    - ALL
              volumeMounts:
                - name: data
                  mountPath: /var/lib/docstore
          containers:
            - name: web
              image: nginxinc/nginx-unprivileged:1.27.5-alpine
              ports:
                - name: http
                  containerPort: 8080
              securityContext:
                allowPrivilegeEscalation: false
                capabilities:
                  drop:
                    - ALL
              readinessProbe:
                httpGet:
                  path: /
                  port: http
                initialDelaySeconds: 2
                periodSeconds: 5
                timeoutSeconds: 2
                failureThreshold: 3
              livenessProbe:
                httpGet:
                  path: /
                  port: http
                initialDelaySeconds: 15
                periodSeconds: 10
                timeoutSeconds: 2
                failureThreshold: 3
              resources:
                requests:
                  cpu: 50m
                  memory: 64Mi
                limits:
                  cpu: 250m
                  memory: 128Mi
              volumeMounts:
                - name: data
                  mountPath: /usr/share/nginx/html
                  readOnly: false
      volumeClaimTemplates:
        - metadata:
            name: data
            labels:
              app.kubernetes.io/name: docstore
          spec:
            accessModes:
              - ReadWriteOnce
            resources:
              requests:
                storage: 1Gi
    EOF
    kubectl apply -f 20-statefulset.yaml
    kubectl rollout status statefulset/docstore -n stateful-lab --timeout=5m
    Validacija: Rollout treba da se završi porukom da su sve tri replike uspešno ažurirane. Ako se zaustavi na prvom podu, odmah proverite PVC, događaje i logove pre bilo kakvog ručnog brisanja. U ovom laboratorijskom primeru glavni kontejner ima read-write mount zato što naredne vežbe namerno upisuju kontrolni fajl i menjaju početnu stranicu; u produkciji aplikaciji se dodeljuju samo prava koja zaista zahteva.
    kubectl get statefulset,pods,pvc -n stateful-lab -o wide
    kubectl get pods -n stateful-lab -l app.kubernetes.io/name=docstore \
      -o custom-columns='POD:.metadata.name,READY:.status.containerStatuses[0].ready,NODE:.spec.nodeName,IP:.status.podIP'
    kubectl get pvc -n stateful-lab \
      -o custom-columns='PVC:.metadata.name,STATUS:.status.phase,VOLUME:.spec.volumeName,ACCESS:.status.accessModes,STORAGE:.status.capacity.storage'
    Očekuju se podovi docstore-0, docstore-1 i docstore-2, kao i tri Bound PVC-a: data-docstore-0, data-docstore-1 i data-docstore-2.
  6. Potvrdite stabilni identitet i sadržaj diskova. Iz svakog poda čita se identifikacioni fajl. Vrednost mora odgovarati ordinalnom imenu poda.
    for pod in docstore-0 docstore-1 docstore-2; do
      printf '%s: ' "$pod"
      kubectl exec -n stateful-lab "$pod" -- cat /usr/share/nginx/html/identity.txt
    done
    Validacija: Rezultat treba da bude:
    docstore-0: docstore-0
    docstore-1: docstore-1
    docstore-2: docstore-2
    Ako dva poda prikazuju isti identitet, proverite volume mount konfiguraciju i stvarne PV/PVC veze. Svaki pod mora koristiti različit PVC.
  7. Proverite DNS pojedinačnih instanci. Privremeni dijagnostički pod koristi se samo za proveru servisa. Opcija --rm uklanja ga po završetku.
    kubectl run dns-check \
      -n stateful-lab \
      --image=busybox:1.36.1 \
      --restart=Never \
      --rm -i \
      --command -- sh -ec '
        nslookup docstore-headless;
        nslookup docstore-0.docstore-headless;
        nslookup docstore-1.docstore-headless;
        nslookup docstore-2.docstore-headless
      '
    Validacija: Upiti za pojedinačne podove treba da vrate njihove aktuelne IP adrese. Ako servis postoji, ali nema odgovora, proverite Endpoints ili EndpointSlice objekte, selector i CoreDNS.
    kubectl get endpointslice -n stateful-lab \
      -l kubernetes.io/service-name=docstore-headless -o wide
    kubectl get pods -n kube-system -l k8s-app=kube-dns
    kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100
  8. Izvršite test opstanka podataka posle zamene poda. Najpre se u trajni volumen poda docstore-1 upisuje kontrolna vrednost, zatim se pod briše bez brisanja PVC-a. Brisanje normalnog poda nije isto što i brisanje podataka; kontroler će ga ponovo kreirati sa istim identitetom.
    kubectl exec -n stateful-lab docstore-1 -- \
      sh -c 'printf "%s\n" "change-ticket-CHG-2026-0730" > /usr/share/nginx/html/acceptance.txt'
    kubectl exec -n stateful-lab docstore-1 -- \
      cat /usr/share/nginx/html/acceptance.txt
    kubectl delete pod docstore-1 -n stateful-lab
    kubectl wait --for=condition=Ready pod/docstore-1 \
      -n stateful-lab --timeout=3m
    kubectl exec -n stateful-lab docstore-1 -- \
      cat /usr/share/nginx/html/acceptance.txt
    Validacija: Posle ponovnog kreiranja poda fajl mora i dalje sadržati change-ticket-CHG-2026-0730. Proverite da je pod dobio isti PVC:
    kubectl get pod docstore-1 -n stateful-lab \
      -o jsonpath='{.spec.volumes[?(@.name=="data")].persistentVolumeClaim.claimName}{"\n"}'
    Očekivani rezultat je data-docstore-1.
  9. Izvedite negativni test spremnosti. Privremeno preimenujte početnu stranicu na poslednjem podu. Nginx će za korenski URL vratiti neuspešan status, pa readiness proba treba da označi kontejner kao NotReady. Pod ostaje pokrenut, ali se ne smatra spremnim.
    kubectl exec -n stateful-lab docstore-2 -- \
      mv /usr/share/nginx/html/index.html /usr/share/nginx/html/index.html.disabled
    kubectl get pod docstore-2 -n stateful-lab -w
    Posmatranje prekinite kada kolona READY postane 0/1. Zatim proverite događaje i vratite fajl:
    kubectl describe pod docstore-2 -n stateful-lab
    kubectl exec -n stateful-lab docstore-2 -- \
      mv /usr/share/nginx/html/index.html.disabled /usr/share/nginx/html/index.html
    kubectl wait --for=condition=Ready pod/docstore-2 \
      -n stateful-lab --timeout=2m
    Validacija: Događaji treba da pokažu neuspeh readiness probe, a posle vraćanja fajla pod mora ponovo postati Ready. Ako se kontejner restartovao, proverite da li je problem trajao dovoljno dugo da aktivira i liveness probu.
  10. Proverite ponašanje pri skaliranju naniže i naviše. StatefulSet se smanjuje na dve replike. Pod sa najvećim ordinalom biće uklonjen, ali zbog politike Retain njegov PVC ostaje.
    kubectl scale statefulset docstore -n stateful-lab --replicas=2
    kubectl rollout status statefulset/docstore -n stateful-lab --timeout=3m
    kubectl get pods,pvc -n stateful-lab
    Validacija: Pod docstore-2 više ne postoji, ali PVC data-docstore-2 ostaje u stanju Bound. Ponovnim skaliranjem na tri replike vraća se isti ordinal i isti disk.
    kubectl scale statefulset docstore -n stateful-lab --replicas=3
    kubectl rollout status statefulset/docstore -n stateful-lab --timeout=3m
    kubectl get pod docstore-2 -n stateful-lab
    kubectl get pvc data-docstore-2 -n stateful-lab
    Pod i PVC moraju biti dostupni. Ovaj rezultat potvrđuje zadržavanje skladišta, ali ne predstavlja backup.
  11. Prikupite operativne podatke i logove. Kubernetes događaji su dopunski i vremenski ograničeni zapis. Za istragu treba prikupiti specifikaciju, stanje podova, PVC-ove, događaje i logove kontejnera.
    kubectl get statefulset docstore -n stateful-lab -o yaml > docstore-observed.yaml
    kubectl get pods,pvc,endpointslice -n stateful-lab -o wide > docstore-status.txt
    kubectl get events -n stateful-lab \
      --sort-by='.metadata.creationTimestamp' > docstore-events.txt
    kubectl logs -n stateful-lab docstore-0 -c initialize-identity > docstore-0-init.log
    kubectl logs -n stateful-lab docstore-0 -c web --tail=200 > docstore-0-web.log
    Validacija: Datoteke treba da sadrže podatke i ne smeju prikazivati neočekivane greške. U realnoj promeni čuvaju se uz change ticket, vreme izvođenja, izvršioca i rezultat kriterijuma prihvatanja.

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

Dijagnostički tok incidenta.

  1. Simptom, obim i posledica: evidentirati koji ordinali nisu Ready, da li je pogođen klijentski saobraćaj, članstvo ili kvorum i kada je odstupanje počelo.
  2. Dokazi pre promene: sačuvati StatefulSet i ControllerRevision stanje, Pod/PVC/PV/EndpointSlice događaje, poslednje rollout promene, aplikativne metrike i logove. Ne brisati pod samo zato što je Pending ili NotReady.
  3. Hipoteza i neposredni uzrok: redom razdvojiti scheduling, PVC provisioning, attach/mount, image/config, probe, DNS i aplikativni kvar. Korelisati vreme Kubernetes događaja sa CSI, kubelet i aplikativnim zapisima.
  4. Osnovni uzrok: utvrditi zašto je neispravna slika, nedostupan storage domen, pogrešna proba ili nekompatibilna šema dospela u produkciju; restart nije analiza osnovnog uzroka.
  5. Zaobilazno i trajno rešenje: privremeno zaustaviti rollout, vratiti provereni šablon ili obnoviti storage/DNS zavisnost. Trajna mera može biti validacija manifesta, canary particija, promena kapaciteta, korekcija probe ili aplikativna migracija.
  6. Potvrda oporavka: proveriti Ready i Available replike, kvorum, greške klijenata, DNS, PVC veze i reprezentativne podatke tokom definisanog perioda posmatranja, pa dokumentovati uzrok, korekciju i preventivnu meru.

Rollback i cleanup.

Rollback aplikativne verzije vrši se vraćanjem proverene slike ili manifesta, a zatim praćenjem rollout-a. Za ozbiljne stateful aplikacije pre rollback-a mora se proveriti kompatibilnost formata podataka; starija verzija programa možda ne može čitati podatke koje je migrirala novija verzija.

kubectl rollout history statefulset/docstore -n stateful-lab
kubectl rollout undo statefulset/docstore -n stateful-lab
kubectl rollout status statefulset/docstore -n stateful-lab --timeout=5m

Za uklanjanje laboratorije prvo se brišu StatefulSet i servis. PVC-ovi se zbog Retain politike ne brišu automatski.

Brisanje samog StatefulSet objekta ne pruža istu uređenu garanciju gašenja kao skaliranje na nulu. Za aplikaciju kojoj je redosled kritičan najpre se izvodi kontrolisano skaliranje na nulu, potvrđuje završetak članova i tek zatim briše kontroler. U ovoj laboratoriji nema pravog klasterskog protokola, pa je neposredno brisanje prihvatljivo za demonstraciju retention politike.

kubectl delete statefulset docstore -n stateful-lab
kubectl delete service docstore-headless -n stateful-lab
kubectl get pvc -n stateful-lab

Upozorenje: sledeća komanda trajno uklanja PVC objekte, a storage reclaim politika može izazvati i brisanje stvarnih volumena i svih podataka. Izvršava se samo u laboratoriji ili posle potvrđenog backup-a, odobrenja vlasnika podataka i provere da volumen nije potreban.

kubectl delete pvc \
  data-docstore-0 data-docstore-1 data-docstore-2 \
  -n stateful-lab
kubectl delete namespace stateful-lab

Merljivi kriterijumi prihvatanja.

Administratorske prakse

Kontrolna lista

Zaključak

Administrator posle ove lekcije treba da razume da je StatefulSet kontroler identiteta i životnog ciklusa stateful replika, a ne mehanizam koji samostalno pruža replikaciju, backup ili visoku dostupnost. Mora umeti da poveže ordinalni identitet, headless servis, DNS, volumeClaimTemplates, StorageClass i konkretni CSI drajver u jednu proverljivu celinu.

U praktičnom radu administrator mora umeti da implementira StatefulSet sa najmanjim potrebnim pravima, proveri redosled kreiranja, pronađe PVC svake replike, potvrdi opstanak podataka posle zamene poda i razlikuje scheduling, provisioning, mount, readiness i aplikativni problem. Promene broja replika, slike, probe, retention politike ili skladišta izvode se tek nakon provere posledica po članstvo aplikacije, format podataka i dostupnost.

Poseban produkcioni rizik predstavljaju prisilno brisanje podova, pogrešno shvaćeni pristupni režimi volumena, neproveren rollback i pretpostavka da više replika automatski znači redundantne podatke. Administrator je odgovoran da tehničko stanje dokumentuje, da ne prekorači odobrena ovlašćenja i da eskalira problem timu za skladište, mrežu, aplikaciju ili platformu kada uzrok izlazi iz njegove zone odgovornosti. Razlog za hitnu eskalaciju su moguć split-brain, gubitak kvoruma, oštećenje podataka, neuspešan restore, nepoznato stanje starog poda ili operacija koja bi mogla nepovratno obrisati volumen.

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