Vanilla Kubernetes

Treći deo: Produkcione operacije, otpornost i enterprise integracije
Dodatak 1. Vanilla Kubernetes laboratorijsko okruženje za učenje i vežbu
XII. Laboratorijsko okruženje i integrisani projekti
Dodatak 1. Izgradnja Vanilla Kubernetes laboratorije – mreža, čvorovi, kubeadm i početna validacija

Dobro projektovano laboratorijsko okruženje omogućava administratoru da istražuje Kubernetes arhitekturu, izvodi kontrolisane promene, izaziva kvarove i vežba oporavak bez rizika po produkcione sisteme. Cilj laboratorije nije samo da nekoliko podova dobije status Running, već da okruženje dovoljno verno predstavlja način na koji funkcioniše samostalno upravljan vanilla Kubernetes klaster: svaki čvor ima sopstveni operativni sistem, mrežni identitet, container runtime i kubelet, dok se control plane i radna opterećenja razdvajaju na različite virtuelne mašine.

U ovoj lekciji gradi se tročvorni klaster pomoću alata kubeadm, containerd runtime-a i Calico CNI dodatka. Referentno okruženje koristi jedan control plane čvor i dva worker čvora. Takva topologija nije visoko dostupna i ne predstavlja preporučenu produkcionu arhitekturu, ali je dovoljno realistična za učenje raspoređivanja podova, mrežne komunikacije, servisa, NetworkPolicy pravila, kvarova čvorova, upravljanja sertifikatima, nadogradnji i osnovnog oporavka.

Namena i granice laboratorijskog klastera

Vanilla Kubernetes označava Kubernetes klaster koji nije vezan za upravljanu cloud uslugu ili komercijalnu distribuciju sa dodatnim kontrolnim slojem. Administrator sam obezbeđuje virtuelne ili fizičke servere, operativni sistem, mrežu, runtime, CNI, skladište, monitoring, backup i lifecycle postupke. Upravo zato laboratorija zasnovana na kubeadm pruža dobar uvid u komponente koje su na upravljanim platformama često skrivene.

kubeadm automatizuje bezbedno inicijalno podizanje minimalnog klastera. On generiše sertifikate, kubeconfig datoteke i statičke Pod manifeste za API server, scheduler, controller manager i lokalni etcd, ali ne kreira virtuelne mašine, ne bira CNI, ne obezbeđuje trajno skladište i ne instalira enterprise monitoring. Administrator zbog toga mora da razume granicu između bootstrap alata i kompletne platforme.

Referentna laboratorija pogodna je za vežbanje administracije resursa, RBAC-a, mrežnih politika, rollout-a, skaliranja, troubleshooting-a i nadogradnje. Nije odgovarajuća za merenje produkcionih performansi, testiranje visoke dostupnosti control plane-a, čuvanje važnih podataka ili objavljivanje servisa na Internetu. Jedan control plane predstavlja jedinstvenu tačku otkaza, lokalni diskovi nisu redundantni, a laboratorijski sertifikati i pristupni podaci obično nisu integrisani sa organizacionim PKI i IAM sistemima.

Referentna arhitektura

Referentni dizajn koristi tri zasebne virtuelne mašine i administratorsku radnu stanicu. Sve adrese su laboratorijske i moraju se pre primene uporediti sa lokalnim LAN, VPN, hipervizorskim i drugim klasterskim rutama. Jedan control plane čvor je namerno pojednostavljenje za učenje: nema redundantnog API endpoint-a niti redundantnog etcd-a, pa njegov kvar zaustavlja upravljanje klasterom.

Čvor Uloga IP adresa Interfejs OS Minimalni resursi Preporučeni resursi
k8s-cp01 control plane i lokalni etcd 192.168.56.10 ens33 ili lokalni ekvivalent Ubuntu Server 24.04 LTS 2 vCPU, 4 GB RAM, 40 GB 4 vCPU, 8 GB RAM, 60 GB
k8s-worker01 worker 192.168.56.11 ens33 ili lokalni ekvivalent Ubuntu Server 24.04 LTS 2 vCPU, 4 GB RAM, 40 GB 4 vCPU, 8 GB RAM, 60 GB
k8s-worker02 worker 192.168.56.12 ens33 ili lokalni ekvivalent Ubuntu Server 24.04 LTS 2 vCPU, 4 GB RAM, 40 GB 4 vCPU, 8 GB RAM, 60 GB
ElementReferentna vrednostNamena i dokaz
Administratorska radna stanicaLinux Mint ili drugi SSH/kubectl host u 192.168.56.0/24SSH ključ, pristup TCP 22 čvorovima i TCP 6443 API serveru; ne čuva nezaštićen admin.conf
Host/Node mreža192.168.56.0/24Stabilne Node IP adrese; potvrda sa ip route i kubectl get nodes -o wide
Pod CIDR172.20.0.0/16Calico IP pool; ne sme biti LAN, VPN ili Service ruta
Service CIDR10.96.0.0/12Virtuelne ClusterIP adrese; ne rutiraju se kao host mreža
LoadBalancer pool192.168.56.200–192.168.56.219, rezervisanoNe koristi se u ovom dodatku; ostavlja se za naredni projekat i isključuje iz DHCP pool-a
Laboratorijski DNS domenlab.tashizza.internalHost zapisi ili dosledan /etc/hosts; primer: k8s-cp01.lab.tashizza.internal
Kubernetes cluster domaincluster.localInterni Service DNS; nije isto što i host DNS domen
Vremesystemd-timesyncd ili organizacioni NTPtimedatectl show -p NTPSynchronized --value vraća yes
Repozitorijumi i registriUbuntu, pkgs.k8s.io, registry.k8s.io, ghcr.io/quay.io prema CNI-uDNS, TLS i izlazni HTTPS rade sa svakog čvora

Promenljive laboratorije i verzijska odluka

OznakaVrednost u ovoj laboratorijiPravilo
CONTROL_PLANE_IP192.168.56.10Statička ili DHCP rezervisana adresa
WORKER1_IP / WORKER2_IP192.168.56.11 / 192.168.56.12Jedinstvene adrese u host mreži
POD_CIDR172.20.0.0/16Mora odgovarati kubeadm i Calico konfiguraciji
SERVICE_CIDR10.96.0.0/12Ne sme se preklapati ni sa jednom rutom
KUBERNETES_MINORv1.36Namenski pkgs.k8s.io kanal; bira se konkretan patch iz tog kanala
KUBERNETES_VERSIONv1.36.0 u referentnoj konfiguracijiPre izvođenja uskladiti sa stvarno instaliranim kubeadm paketom; ne koristiti neprovereni latest
CALICO_VERSIONv3.32.1Manifest preuzeti iz zvaničnog, verzionisanog izvora i pregledati pre primene

Kubernetes 1.36 koristi kubeadm.k8s.io/v1beta4. Paketni kanal, kubeadm, kubelet, control plane image-i, CRI v1 podrška runtime-a i podržana Calico verzija proveravaju se ponovo neposredno pre izvođenja. Ubuntu 24.04 paket containerd-a može pripadati grani 1.7 ili novijoj, pa se putanja CRI plugin konfiguracije ne pretpostavlja: generiše se konfiguracija za stvarno instaliranu verziju, zatim proveravaju containerd --version, containerd config dump i crictl info. Kubernetes 1.36 može automatski preuzeti cgroup driver preko CRI RuntimeConfig kada runtime to podržava; eksplicitna vrednost systemd ipak ostaje dokumentovana zbog jasnog i kompatibilnog ponašanja.

Ako se vrednosti privremeno unesu kao shell promenljive, one važe samo u toj shell sesiji. Pre upotrebe obavezno se proveravaju pomoću printf '%s\n' "$CONTROL_PLANE_IP" "$POD_CIDR". Prazna promenljiva ne sme se koristiti u komandi koja menja stanje, a destruktivne komande u završnoj fazi namerno koriste eksplicitne putanje, ne promenljive.

Svi čvorovi koriste Ubuntu Server 24.04 LTS, systemd, containerd, kubelet, kubeadm i kubectl iz repozitorijuma za Kubernetes 1.36. Pod mreža koristi opseg 172.20.0.0/16, Service mreža podrazumevani opseg 10.96.0.0/12, a mreža virtuelnih mašina 192.168.56.0/24. Ovi opsezi ne smeju da se preklapaju sa fizičkom mrežom, VPN rutama, drugim laboratorijama ili mrežama koje koristi hipervizor.

Statičke ili rezervisane DHCP adrese su važne zato što kubelet, API server sertifikati i join postupak zavise od stabilne komunikacije među čvorovima. DNS imena moraju dosledno da se razrešavaju, lokalno preko DNS servera ili privremeno preko datoteke /etc/hosts. Promena hostname-a ili IP adrese nakon inicijalizacije može prekinuti TLS validaciju, pristup API serveru i komunikaciju između čvorova.

Laboratorijske virtuelne mašine treba povezati na mrežu koja omogućava međusobnu komunikaciju i pristup repozitorijumima. NAT mreža sa odvojenim internim segmentom često je bezbednija od direktnog bridged povezivanja. API server na portu TCP 6443 ne treba izlagati nepoverljivoj mreži. Administratorski SSH pristup ograničava se na upravljačku stanicu, a pristup korišćenjem lozinke treba zameniti SSH ključevima.

Operativni sistem, vreme i mrežni preduslovi

Kubernetes zahteva da čvorovi imaju jedinstvena imena, MAC adrese i identifikatore proizvoda. Kloniranje virtuelne mašine bez regenerisanja identiteta može izazvati nejasne registracije čvorova. Pre instalacije proveravaju se hostname, IP konfiguracija, DNS, podrazumevana ruta, sinhronizacija vremena i dostupnost potrebnih portova. Vremensko odstupanje može uticati na validnost sertifikata, tokene i korelaciju logova.

Swap se tradicionalno isključuje zato što kubelet mora predvidivo da upravlja memorijskim pritiskom i eviction mehanizmima. Novije verzije Kubernetes-a podržavaju kontrolisanu upotrebu swap-a kroz eksplicitnu kubelet konfiguraciju, ali to nije podrazumevano laboratorijsko ponašanje. Za ovu laboratoriju swap se isključuje kako bi konfiguracija ostala jasna i kompatibilna sa standardnim kubeadm preduslovima.

Kernel mora prosleđivati bridged IPv4 saobraćaj kroz netfilter i dozvoliti IP forwarding. CNI dodatak zatim kreira interfejse, rute i pravila potrebna za Pod-to-Pod i Pod-to-Service komunikaciju. Ako su kernel moduli ili sysctl vrednosti pogrešni, podovi mogu biti kreirani, ali neće imati funkcionalnu mrežu. Takav simptom se razlikuje od problema scheduler-a: pod dobija čvor, ali ostaje u stanju ContainerCreating ili ne može da pristupi drugim adresama.

Container runtime i cgroup upravljanje

Kubernetes više ne upravlja kontejnerima preko ugrađenog Docker interfejsa. Kubelet komunicira sa runtime-om preko Container Runtime Interface-a. U laboratoriji se koristi containerd sa aktivnim CRI dodatkom. Komanda ctr namenjena je niskom nivou rada sa containerd-om i ne prikazuje Kubernetes objekte na isti način kao CRI. Za dijagnostiku runtime-a administrator koristi crictl, dok za deklarativno upravljanje klasterom koristi kubectl.

Kubelet i runtime moraju dosledno koristiti cgroup upravljački program. Na savremenim systemd distribucijama preporučuje se systemd cgroup driver. Nepodudaranje može dovesti do nestabilnog upravljanja procesima, pogrešnog obračuna resursa ili neuspešnog pokretanja podova. Konfiguracija containerd-a zato eksplicitno uključuje SystemdCgroup = true, a kubeadm generiše odgovarajuću kubelet konfiguraciju.

Containerd konfiguracija se nalazi u /etc/containerd/config.toml. Posle svake izmene administrator proverava sintaksu posredno kroz uspešno ponovno pokretanje servisa, status CRI dodatka i runtime odgovor. Sam status active (running) nije dovoljan ako je CRI dodatak onemogućen; zato se dodatno koriste ctr plugins ls i crictl info.

Uloga kubeadm-a i tok inicijalizacije

Na control plane čvoru kubeadm init izvršava preflight provere, generiše PKI materijal, kubeconfig datoteke i statičke manifeste u direktorijumu /etc/kubernetes/manifests. Kubelet posmatra taj direktorijum i preko containerd-a pokreće control plane komponente kao statičke podove. Njih ne kreira Deployment i njihov lifecycle nije isti kao kod običnih aplikacionih podova.

Podaci klastera čuvaju se u etcd-u, koji je u ovoj topologiji lokalni statički pod na k8s-cp01. Direktorijum /var/lib/etcd zato predstavlja kritičnu lokaciju. Gubitak tog direktorijuma bez upotrebljivog snapshot-a znači gubitak deklarativnog stanja klastera, iako datoteke aplikacija ili container image slojevi možda još postoje na worker čvorovima.

Worker se priključuje naredbom kubeadm join. Bootstrap token dokazuje da novi čvor ima pravo da započne proces, dok hash CA javnog ključa sprečava povezivanje sa lažnim control plane-om. Token je vremenski ograničen i ne treba ga čuvati u javnom repozitorijumu, shell istoriji ili dokumentaciji promene. Kada istekne, generiše se nova join komanda.

CNI i mrežni model laboratorije

Kubernetes definiše mrežni model, ali ga sam kubeadm ne implementira. Svaki pod treba da dobije jedinstvenu IP adresu i da, u okviru pravila mrežne politike, može direktno da komunicira sa drugim podovima. CNI dodatak kreira potrebne interfejse i rute. Dok CNI nije instaliran, CoreDNS podovi obično ostaju u stanju Pending, a čvorovi mogu imati uslov NetworkUnavailable.

Calico u laboratoriji obezbeđuje CNI, upravljanje Pod adresama i podršku za Kubernetes NetworkPolicy. Operator pristup odvaja instalacionu logiku od korisničke konfiguracije. Pod mreža 172.20.0.0/16 mora odgovarati vrednosti zadatoj tokom kubeadm init. Ako se opsezi razlikuju, podovi mogu dobiti pogrešne adrese ili mrežne komponente neće postati spremne.

Mrežna politika nije automatski podrazumevano zabrani-sve mehanizam. Bez NetworkPolicy objekta, namespace obično dozvoljava saobraćaj u skladu sa standardnim Kubernetes modelom. Administrator mora eksplicitno definisati izolaciju i dozvoljene tokove. Negativni testovi su zato važni: nije dovoljno potvrditi da dozvoljena konekcija radi, već i da zabranjena konekcija zaista ne prolazi.

Administrativni pristup i zaštita laboratorije

Datoteka /etc/kubernetes/admin.conf daje veoma široka administratorska prava i mora se tretirati kao tajna. Njeno kopiranje u korisnički direktorijum olakšava rad, ali ne smanjuje privilegije. Ne treba je slati elektronskom poštom, ugrađivati u skripte ili trajno koristiti na deljenim računarima. Za redovan rad realnije je kreirati posebne identitete i RBAC ovlašćenja, dok se admin.conf čuva za kontrolisane administratorske intervencije.

Snapshot virtuelne mašine koristan je za brzo vraćanje laboratorije, ali nije zamena za Kubernetes backup. Nekonzistentan snapshot uključenog control plane čvora može obuhvatiti disk dok etcd upis još traje. Za vežbu oporavka treba praviti etcd snapshot alatima koji razumeju etcd format, čuvati potrebne sertifikate i dokumentovati tačnu verziju klastera.

Integrisani praktikum: izgradnja tročvornog kubeadm klastera

Mapa laboratorije

FazaMesto izvršavanjaPromenaDokaz uspeha
1–2. Topologija, verzije i VMadministratorska stanica i hipervizorinventar i tri jedinstvena hostanema CIDR sukoba; resursi i identiteti provereni
3. Imena, DNS i vremesvi čvorovistabilan identitet i vremegetent i timedatectl
4–5. Mreža, kernel i swapsvi čvorovi, sudodozvoljeni tokovi, moduli i sysctlrute/portovi, lsmod, sysctl, swapon
6–7. Runtime i paketisvi čvorovi, sudocontainerd CRI i verzionisani Kubernetes alaticrictl info, verzije i package hold
8. Pre-flightsvi čvorovi; cp01 dodatnosačuvano početno stanje i image-inema nerešenih pre-flight grešaka
9–10. Control plane i pristupsamo k8s-cp01PKI, etcd, statički Podovi i kubeconfigAPI dostupan; kubeconfig mode 600
11–12. CNI i worker-icp01, zatim worker-iPod mreža i priključenje čvorovaCalico spreman; sva tri čvora Ready
13–14. Validacija i workloadk8s-cp01test aplikacija, Service i politikaDNS, cross-node Pod tok, endpointi, HTTP i self-healing
15. Greškeograničeni laboratorijski ciljreverzibilan kvaruzrok dokazan, korekcija i oporavak zabeleženi
16. Evidencija/odlukaadministratorska stanica i čvorovicheckpoint ili destruktivan resetarhiva dokaza ili potvrđeno čisto stanje

Faze 1–2: projektovanje i priprema virtuelnih mašina

Mesto, nalog i uticaj. Inventar se priprema na administratorskoj stanici bez promene čvorova; VM resursi i mrežni adapteri menjaju se u hipervizoru dok su VM-ovi isključeni. Na hostovima labadmin sa sudo samo čita inventar. Ne klonirati već inicijalizovan Kubernetes čvor. Ako se koristi template, identitet instance i SSH host ključevi regenerišu se prema pravilima distribucije pre uključivanja kopije u istu mrežu.

# Svi čvorovi; read-only inventar
hostnamectl
lscpu | sed -n '1,15p'
free -h
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS
ip -brief link
cat /etc/machine-id
sudo cat /sys/class/dmi/id/product_uuid

Očekuju se jedinstveni hostname, MAC, machine-id i product UUID, najmanje resursi iz tabele i dovoljan slobodan disk. Duplirani identitet prekida fazu: VM se izoluje i ponovo priprema. Kontrolna tačka je dokumentovan inventar tri jedinstvena hosta i snapshot čistog, ugašenog OS-a pre klasterskog stanja.

Faze 3–16: sekvencijalno izvršavanje

Poslovni i tehnički kontekst. Infrastrukturni tim priprema izolovanu laboratoriju u kojoj administratori treba da vežbaju instalaciju, mrežnu segmentaciju, raspoređivanje aplikacija i troubleshooting pre rada na produkcionim Kubernetes platformama. Cilj je podići ponovljiv tročvorni klaster, potvrditi komunikaciju između podova i servisa, dokazati sprovođenje NetworkPolicy pravila i dokumentovati postupak čišćenja.

Referentno okruženje i preduslovi. Tri sveže Ubuntu Server 24.04 virtuelne mašine imaju IP adrese i resurse iz prethodne tabele. Korisnik labadmin postoji na svim čvorovima, prijavljuje se SSH ključem i ima pravo sudo. Internet pristup je dozvoljen prema Ubuntu, Kubernetes i Calico repozitorijumima. Komande označene sa „svi čvorovi” izvršavaju se na sve tri virtuelne mašine.

  1. Provera identiteta, mreže i vremena na svim čvorovima. Pre promene mora se potvrditi da svaki čvor ima očekivano ime i adresu, da se imena međusobno razrešavaju i da je sistemsko vreme sinhronizovano.
    hostnamectl
    ip -brief address
    ip route
    timedatectl
    getent hosts k8s-cp01 k8s-worker01 k8s-worker02
    ping -c 2 192.168.56.10
    Ako laboratorija nema DNS zapis, na sva tri čvora dodaje se ista kontrolisana mapa:
    sudo tee -a /etc/hosts >/dev/null <<'EOF'
    192.168.56.10 k8s-cp01
    192.168.56.11 k8s-worker01
    192.168.56.12 k8s-worker02
    EOF
    Validacija: getent hosts mora vratiti tačno jednu očekivanu adresu za svaki naziv. Duplikati ili različiti odgovori moraju se ukloniti pre inicijalizacije.
  2. Faza 4 – mrežna povezanost, portovi, firewall, MTU i rutiranje na svim čvorovima. Sledeće komande naloga labadmin samo čitaju stanje. Pre inicijalizacije očekuje se da host mreža ne sadrži rutu koja obuhvata Pod ili Service CIDR i da svi čvorovi koriste kompatibilan MTU. Test TCP 6443 ima smisla tek kada API server sluša; pre toga očekivani connection refused dokazuje putanju do hosta, dok timeout upućuje na firewall ili rutu.
    ip -4 route
    ip link show
    ping -c 2 192.168.56.10
    getent ahostsv4 k8s-cp01
    sudo ss -lntup
    curl -k --connect-timeout 3 https://192.168.56.10:6443/livez
    OdredištePort/protokolKo treba da pristupaNapomena
    API serverTCP 6443svi čvorovi i administracijaulaz na control plane; ne izlagati nepoverljivoj mreži
    etcdTCP 2379–2380lokalne control plane komponenteu single-node stacked topologiji ne otvarati široko
    kubelet APITCP 10250control plane ka svim čvorovimapotreban za logove, exec i metrike
    scheduler/controller-managerTCP 10259/10257lokalni control planesecure portovi; ne izlagati LAN-u
    NodePortTCP/UDP 30000–32767samo ako se NodePort koristinije potreban za ClusterIP test u ovoj laboratoriji
    Calicozavisi od VXLAN/BGP izborameđu čvorovimaprimeniti tačne zvanične zahteve iz izabrane Calico konfiguracije
    Kontrolna tačka: dokumentovane su firewall zone i pravila; Node IP mreža, 172.20.0.0/16 i 10.96.0.0/12 ne preklapaju se; efektivni MTU je isti ili je CNI MTU svesno prilagođen tunelskom overhead-u. Ne gasiti firewall bez analize. Ako tok ne radi, sa oba kraja proveriti rutu, listener i pravilo, pa menjati samo pravilo za konkretan izvor, odredište i port.
  3. Priprema kernel-a i isključivanje swap-a na svim čvorovima. Moduli overlay i br_netfilter omogućavaju kontejnerski overlay filesystem i obradu bridged saobraćaja. IP forwarding je neophodan za rutiranje paketa između interfejsa.
    sudo swapoff -a
    sudo sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab
    
    cat <<'EOF' | sudo tee /etc/modules-load.d/k8s.conf
    overlay
    br_netfilter
    EOF
    
    sudo modprobe overlay
    sudo modprobe br_netfilter
    
    cat <<'EOF' | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
    net.bridge.bridge-nf-call-iptables = 1
    net.bridge.bridge-nf-call-ip6tables = 1
    net.ipv4.ip_forward = 1
    EOF
    
    sudo sysctl --system
    Validacija:
    swapon --show
    lsmod | grep -E 'overlay|br_netfilter'
    sysctl net.bridge.bridge-nf-call-iptables net.ipv4.ip_forward
    swapon --show ne treba da vrati uređaj, a obe sysctl vrednosti moraju biti 1.
  4. Instalacija i konfiguracija containerd-a na svim čvorovima. Instalira se distribucioni paket, generiše početna konfiguracija i uključuje systemd cgroup driver.
    sudo apt-get update
    sudo apt-get install -y containerd
    
    sudo mkdir -p /etc/containerd
    containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
    sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
    
    sudo systemctl restart containerd
    sudo systemctl enable containerd
    Validacija:
    systemctl is-active containerd
    sudo ctr plugins ls | grep -E 'io.containerd.grpc.v1.cri|io.containerd.cri.v1.runtime'
    grep -n 'SystemdCgroup' /etc/containerd/config.toml
    Runtime mora biti aktivan, CRI dodatak u stanju ok, a relevantna konfiguracija mora prikazati true. Ako servis ne može da se pokrene, prva dijagnostika je sudo journalctl -u containerd -b --no-pager.
  5. Instalacija Kubernetes paketa na svim čvorovima. Za svaku Kubernetes minor verziju koristi se namenski pkgs.k8s.io repozitorijum. Paketi se zadržavaju kako nekontrolisani sistemski upgrade ne bi promenio verziju samo jednog čvora.
    sudo apt-get install -y apt-transport-https ca-certificates curl gpg
    sudo mkdir -p -m 755 /etc/apt/keyrings
    
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key \
      | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    
    echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /' \
      | sudo tee /etc/apt/sources.list.d/kubernetes.list
    
    sudo apt-get update
    sudo apt-get install -y kubelet kubeadm kubectl cri-tools
    sudo apt-mark hold kubelet kubeadm kubectl
    sudo systemctl enable kubelet
    Validacija:
    kubeadm version
    kubectl version --client
    kubelet --version
    apt-mark showhold | grep -E 'kubeadm|kubectl|kubelet'
    Sva tri Kubernetes paketa treba da pripadaju istoj minor verziji. Kubelet može periodično prijavljivati neuspeh pre init ili join postupka jer još nema konfiguraciju klastera; to je očekivano privremeno stanje.
  6. Podešavanje CRI dijagnostičkog klijenta na svim čvorovima. crictl se usmerava na containerd socket kako bi se izbeglo automatsko isprobavanje više endpoint-a.
    cat <<'EOF' | sudo tee /etc/crictl.yaml
    runtime-endpoint: unix:///run/containerd/containerd.sock
    image-endpoint: unix:///run/containerd/containerd.sock
    timeout: 10
    debug: false
    EOF
    
    sudo crictl info
    Validacija: izlaz mora sadržati runtime informacije bez poruke o nedostupnom endpoint-u. Greška unknown service runtime.v1.RuntimeService ukazuje na neaktivan ili pogrešno konfigurisan CRI dodatak.
  7. Inicijalizacija control plane čvora. Pre state-changing komande sačuvati početni dokaz i preuzeti potrebne image-e. Na k8s-cp01 sledeće komande prvo čitaju stanje, a kubeadm config images pull menja lokalni runtime cache bez formiranja klastera:
    mkdir -p ~/k8s-lab/evidence
    date -Is | tee ~/k8s-lab/evidence/start-time.txt
    containerd --version | tee ~/k8s-lab/evidence/containerd-version.txt
    kubeadm version -o short | tee ~/k8s-lab/evidence/kubeadm-version.txt
    sudo crictl info > ~/k8s-lab/evidence/crictl-info.json
    sudo kubeadm config images list --kubernetes-version v1.36.0
    sudo kubeadm config images pull --kubernetes-version v1.36.0 \
      --cri-socket unix:///run/containerd/containerd.sock
    sudo crictl images
    Ako stvarni kubeadm version -o short nije v1.36.0, konfiguraciona vrednost i image komande uskladiti sa instaliranim podržanim patch izdanjem pre nastavka. Pre-flight upozorenje se klasifikuje i dokumentuje; greška se otklanja. Opcija --ignore-preflight-errors=all nije korektivna mera. Ovaj korak izvršava se samo na k8s-cp01. Konfiguraciona datoteka se čuva radi ponovljivosti i revizije promene.
    mkdir -p ~/k8s-lab
    cat <<'EOF' > ~/k8s-lab/kubeadm-init.yaml
    apiVersion: kubeadm.k8s.io/v1beta4
    kind: InitConfiguration
    localAPIEndpoint:
      advertiseAddress: 192.168.56.10
      bindPort: 6443
    nodeRegistration:
      criSocket: unix:///run/containerd/containerd.sock
    ---
    apiVersion: kubeadm.k8s.io/v1beta4
    kind: ClusterConfiguration
    clusterName: tashizza-lab
    kubernetesVersion: v1.36.0
    controlPlaneEndpoint: 192.168.56.10:6443
    networking:
      serviceSubnet: 10.96.0.0/12
      podSubnet: 172.20.0.0/16
      dnsDomain: cluster.local
    ---
    apiVersion: kubelet.config.k8s.io/v1beta1
    kind: KubeletConfiguration
    cgroupDriver: systemd
    EOF
    
    sudo kubeadm config validate --config ~/k8s-lab/kubeadm-init.yaml
    sudo kubeadm init --config ~/k8s-lab/kubeadm-init.yaml \
      | tee ~/k8s-lab/kubeadm-init-output.txt
    Validacija: završni izlaz mora navesti da je control plane uspešno inicijalizovan i prikazati join komandu. Pošto izlaz sadrži osetljivu bootstrap informaciju, datoteka se odmah štiti sa chmod 600 ~/k8s-lab/kubeadm-init-output.txt i ne commit-uje. Ako preflight provera prijavi zauzet port ili postojeći manifest, ne treba koristiti --ignore-preflight-errors=all; prvo se utvrđuje da li je čvor ranije delimično inicijalizovan.
  8. Konfiguracija kubectl pristupa na control plane čvoru.
    mkdir -p "$HOME/.kube"
    sudo cp /etc/kubernetes/admin.conf "$HOME/.kube/config"
    sudo chown "$(id -u):$(id -g)" "$HOME/.kube/config"
    chmod 600 "$HOME/.kube/config"
    
    kubectl cluster-info
    kubectl get nodes -o wide
    kubectl get pods -n kube-system -o wide
    Validacija: API server mora biti dostupan. Čvor u ovoj fazi može biti NotReady, a CoreDNS Pending, jer CNI još nije instaliran. To je normalno stanje, a ne razlog za ponavljanje kubeadm init.
  9. Instalacija Calico CNI dodatka. Na k8s-cp01 preuzimaju se operator i referentni custom resources, a zatim se proverava i prilagođava Pod CIDR.
    cd ~/k8s-lab
    curl -fsSLO https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/tigera-operator.yaml
    curl -fsSLO https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/custom-resources.yaml
    
    sed -i 's#cidr: 192.168.0.0/16#cidr: 172.20.0.0/16#' custom-resources.yaml
    grep -A8 -B4 'cidr:' custom-resources.yaml
    
    kubectl create -f tigera-operator.yaml
    kubectl create -f custom-resources.yaml
    Validacija:
    kubectl get tigerastatus
    kubectl get pods -n tigera-operator
    kubectl get pods -n calico-system -o wide
    kubectl get nodes
    Sačekati da Calico komponente postanu spremne, a k8s-cp01 dobije status Ready. Ako operator pod radi, ali Calico čvor nije spreman, pregledaju se događaji i logovi: kubectl describe pod -n calico-system POD i kubectl logs -n calico-system POD -c calico-node.
  10. Priključivanje worker čvorova. Na k8s-cp01 generiše se nova kratkotrajna join komanda. Njena vrednost se prenosi bezbednim administrativnim kanalom i izvršava posebno na svakom worker-u.
    kubeadm token create --ttl 30m --print-join-command
    Primer strukture komande, bez stvarnih vrednosti:
    sudo kubeadm join 192.168.56.10:6443 \
      --token <BOOTSTRAP_TOKEN> \
      --discovery-token-ca-cert-hash sha256:<CA_PUBLIC_KEY_HASH>
    Validacija: na svakom worker-u proveriti sudo systemctl status kubelet i sudo crictl ps. Na control plane čvoru:
    kubectl get nodes -o wide
    kubectl wait --for=condition=Ready node/k8s-worker01 --timeout=180s
    kubectl wait --for=condition=Ready node/k8s-worker02 --timeout=180s
    Sva tri čvora moraju imati status Ready, očekivane interne IP adrese i istu minor verziju kubelet-a.
  11. Funkcionalni test raspoređivanja, DNS-a i servisa. Kreira se namespace i jednostavna aplikacija sa dve replike. Podovi treba da budu raspoređeni na worker čvorove, a Service treba da obezbedi stabilan DNS naziv.
    cat <<'EOF' > ~/k8s-lab/lab-app.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: lab-app
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: web
      namespace: lab-app
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: web
      template:
        metadata:
          labels:
            app: web
        spec:
          containers:
          - name: nginx
            image: nginx:1.29
            ports:
            - containerPort: 80
            resources:
              requests:
                cpu: 50m
                memory: 64Mi
              limits:
                cpu: 250m
                memory: 128Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: web
      namespace: lab-app
    spec:
      selector:
        app: web
      ports:
      - port: 80
        targetPort: 80
    EOF
    
    kubectl apply -f ~/k8s-lab/lab-app.yaml
    kubectl rollout status deployment/web -n lab-app --timeout=180s
    kubectl get pods -n lab-app -o wide
    kubectl get service,endpointslices -n lab-app
    Test klijent proverava DNS i HTTP odgovor:
    kubectl run test-client -n lab-app \
    --image=curlimages/curl:8.15.0 \
    --restart=Never --command -- sleep 3600
    
    kubectl wait --for=condition=Ready pod/test-client -n lab-app --timeout=120s
    kubectl exec -n lab-app test-client -- nslookup web.lab-app.svc.cluster.local
    kubectl exec -n lab-app test-client -- curl -fsS http://web
    Očekivani rezultat: DNS vraća ClusterIP servisa, a HTTP zahtev vraća početnu nginx stranicu. EndpointSlice mora sadržati adrese oba spremna web poda. Za dokaz međučvorne Pod komunikacije nije dovoljno pretpostaviti da dve replike rade. Proveriti na kojim su čvorovima, izabrati IP replike na drugom čvoru od test-client i izvršiti direktan HTTP zahtev ka tom Pod IP-u. Ako scheduler smesti obe web replike na isti worker, privremeno primeniti podAntiAffinity ili skalirati na više replika; ne proglašavati cross-node test uspešnim bez dokaza iz kolone NODE.
    kubectl get pods -n lab-app -o wide
    kubectl exec -n lab-app test-client -- curl -fsS http://<REMOTE_POD_IP>
    kubectl get endpointslices -n lab-app -l kubernetes.io/service-name=web -o wide
    Zatim se dokazuje deklarisano samoisceljenje. Brisanje jednog aplikacionog Pod-a menja stanje samo u namespace-u lab-app; Deployment mora kreirati zamenu i vratiti dve dostupne replike.
    kubectl get pods -n lab-app -l app=web
    kubectl delete pod -n lab-app <ONE_WEB_POD_NAME>
    kubectl rollout status deployment/web -n lab-app --timeout=180s
    kubectl get pods -n lab-app -l app=web -o wide
    kubectl get events -n lab-app --sort-by=.metadata.creationTimestamp | tail -n 20
    Kontrolna tačka: novi Pod ima novi UID, Deployment ponovo ima dve dostupne replike, Service EndpointSlice pokazuje spremne endpoint-e, DNS i HTTP test i dalje prolaze. Ako ne prolaze, prvo se pregledaju Deployment uslovi, događaji novog Pod-a i image/CNI stanje; ne kreira se ručno zamenski Pod.
  12. Negativni test NetworkPolicy kontrole. Prvo se uvodi default-deny ingress politika. Nakon toga prethodno uspešan zahtev mora prestati da radi, što potvrđuje da CNI zaista sprovodi politiku.
    cat <<'EOF' > ~/k8s-lab/network-policy.yaml
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: default-deny-ingress
      namespace: lab-app
    spec:
      podSelector: {}
      policyTypes:
      - Ingress
    ---
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-client-to-web
      namespace: lab-app
    spec:
      podSelector:
        matchLabels:
          app: web
      policyTypes:
      - Ingress
      ingress:
      - from:
        - podSelector:
            matchLabels:
              access: web
        ports:
        - protocol: TCP
          port: 80
    EOF
    
    kubectl apply -f ~/k8s-lab/network-policy.yaml
    kubectl exec -n lab-app test-client -- \
      curl --connect-timeout 3 -fsS http://web
    Validacija negativnog testa: zahtev bez odgovarajuće oznake treba da istekne ili bude odbijen. Zatim se dozvola dodeljuje oznakom:
    kubectl label pod test-client -n lab-app access=web
    kubectl exec -n lab-app test-client -- curl -fsS http://web
    Poslednji zahtev mora ponovo uspeti. Ako oba zahteva uspevaju, proveravaju se NetworkPolicy objekti, selektori i Calico status; ako oba ne uspevaju, proveravaju se oznaka poda, port i EndpointSlice.
  13. Provera logova i osnovna dijagnostika. Aplikacioni logovi čitaju se preko API-ja, dok se node servisi proveravaju kroz systemd journal. Statički control plane podovi pregledaju se pomoću kubectl ili crictl kada API nije dostupan.
    kubectl logs -n lab-app deployment/web --tail=20
    kubectl get events -n lab-app --sort-by=.metadata.creationTimestamp
    kubectl get events -A --sort-by=.metadata.creationTimestamp | tail -n 30
    
    sudo journalctl -u kubelet -b --no-pager | tail -n 50
    sudo journalctl -u containerd -b --no-pager | tail -n 50
    sudo crictl pods
    sudo crictl ps -a
    Tumačenje: FailedScheduling ukazuje na problem kapaciteta, taint-a ili selektora; ErrImagePull i ImagePullBackOff na image ili registry problem; FailedCreatePodSandBox često upućuje na CNI ili runtime; CrashLoopBackOff znači da je kontejner pokrenut, ali se ponavljano završava.
  14. Cleanup aplikacije i bezbedan reset klastera. Opcija A – očuvanje klastera. Ovo je preporučena odluka kada se laboratorija koristi kao osnova za naredne integrisane projekte. Ne brišu se lab-app i NetworkPolicy ako će služiti kao regression test; umesto toga beleže se verzije, čvorovi, CIDR-i i konačni dokaz, uklanjaju se ili opozivaju nepotrebni bootstrap tokeni i pravi kontrolisan checkpoint ugašenih VM-ova. Snapshot nije zamena za etcd backup i ne sme se predstavljati kao produkcioni DR.
    # k8s-cp01; read-only evidencija
    kubectl get nodes -o wide > ~/k8s-lab/evidence/final-nodes.txt
    kubectl get pods -A -o wide > ~/k8s-lab/evidence/final-pods.txt
    kubectl get events -A --sort-by=.metadata.creationTimestamp \
      > ~/k8s-lab/evidence/final-events.txt
    kubeadm version -o short > ~/k8s-lab/evidence/final-kubeadm-version.txt
    kubeadm token list
    sudo kubeadm certs check-expiration
    Za ponovno korišćenje klastera dovoljno je ukloniti namespace:
    kubectl delete namespace lab-app
    kubectl get namespace lab-app
    Opcija B – potpuno resetovanje; destruktivan laboratorijski postupak. Koristi se samo kada se laboratorija namerno vraća u stanje pre kubeadm bootstrap-a. Pre toga kopirati inventar, kubeadm YAML, verzije, događaje i relevantne journal isečke na administratorsku stanicu, proveriti backup i tačno identifikovati sva tri ciljana čvora. Na control plane-u reset uklanja lokalnog stacked etcd člana i klastersko stanje te laboratorije. Najpre se koristi read-only dry-run, zatim se potvrđena naredba izvršava na worker čvorovima i na kraju na control plane čvoru.
    # Svaki tačno identifikovan čvor; read-only pregled
    hostnamectl --static
    sudo kubeadm reset --dry-run --cri-socket unix:///run/containerd/containerd.sock
    
    # DESTRUKTIVNO; worker-i prvo, control plane poslednji
    sudo kubeadm reset --force \
      --cri-socket unix:///run/containerd/containerd.sock
    
    # Dodatno čišćenje tek posle pregleda; eksplicitne putanje
    sudo ls -la /etc/cni/net.d
    sudo rm -rf /etc/cni/net.d
    ls -la "$HOME/.kube"
    rm -rf "$HOME/.kube"
    Validacija: sudo crictl ps -a ne treba da prikazuje prethodne Kubernetes kontejnere, a /etc/kubernetes/manifests ne treba da sadrži statičke manifeste. kubeadm reset ne uklanja /etc/cni/net.d, korisnički kubeconfig, niti garantuje uklanjanje iptables, nftables ili IPVS pravila. CNI interfejsi, rute i pravila najpre se inventarišu; uklanjaju se samo zvaničnim cleanup postupkom odgovarajuće verzije CNI-a/kube-proxy-ja ili reprovision-om VM-a. Slepo izvršavanje iptables -F ili nftables flush komande nije prihvatljivo jer može prekinuti SSH i druge host servise.

Kriterijumi prihvatanja laboratorije. Klaster je prihvaćen kada sva tri čvora najmanje deset minuta održavaju status Ready; svi sistemski podovi imaju očekivano stanje bez ponavljanih restartovanja; dve aplikacione replike rade na worker čvorovima; DNS ime web.lab-app.svc.cluster.local razrešava se iz test poda; Service vraća HTTP odgovor; default-deny politika blokira neoznačenog klijenta; oznaka access=web ponovo omogućava pristup; kubelet i containerd logovi nemaju ponavljane kritične greške; konfiguracione datoteke i rezultat validacije sačuvani su u dokumentaciji laboratorije.

Tipične greške i njihovo razlikovanje

Faza 15 koristi isti obrazac za svaki incident: zabeležiti vreme i poslednju promenu; odrediti obim; prikupiti read-only dokaze; postaviti hipotezu; potvrditi neposredni i osnovni uzrok; primeniti najmanju reverzibilnu korekciju; ponoviti početni test; dokumentovati nalaz. Privremeni workaround se koristi samo ako ne prikriva uzrok. Eksperimenti se izvode jedan po jedan, nikada istovremeno.

Scenario A: zaustavljen kubelet na jednom worker čvoru

Bezbedna granica: samo k8s-worker02, bez promene control plane-a, containerd-a ili mreže. Pre testa proveriti da su aplikacione replike raspoređene i da drugi worker ima kapacitet. Komanda systemctl stop menja stanje i zahteva sudo.

# k8s-worker02; state-changing laboratorijska simulacija
sudo systemctl stop kubelet
sudo systemctl is-active kubelet

# k8s-cp01; read-only dokazi posle isteka Node lease/grace perioda
kubectl get nodes
kubectl describe node k8s-worker02
kubectl get events -A --sort-by=.metadata.creationTimestamp | tail -n 30

# k8s-worker02; read-only lokalni dokaz, zatim korekcija
sudo journalctl -u kubelet --since '-10 minutes' --no-pager
sudo systemctl start kubelet
sudo systemctl is-active kubelet

# k8s-cp01; potvrda oporavka
kubectl wait --for=condition=Ready node/k8s-worker02 --timeout=180s
kubectl get pods -A -o wide
kubectl exec -n lab-app test-client -- curl -fsS http://web

Simptom je prelazak jednog Node objekta u NotReady posle dozvoljenog perioda, obim je jedan worker, neposredni uzrok je zaustavljen servis, a osnovni uzrok u realnom incidentu bila bi neovlašćena promena, kvar systemd jedinice ili hosta. Trajna mera je uklanjanje uzroka i kontrola promene, ne samo restart. Oporavak je potvrđen tek kada su Node, workload, DNS/Service test i novi događaji uredni.

Scenario B: istekla ili pogrešna join komanda

Bezbedna granica: vežba se na još nepriključenom worker-u ili na svežoj VM kopiji, nikada na funkcionalnom članu. Ne unosi se proizvoljan CA hash i ne koristi --discovery-token-unsafe-skip-ca-verification. Greška token id ... is invalid ili nemogućnost pronalaska JWS potpisa potvrđuje bootstrap problem; timeout ka 6443 je mrežni problem, ne token.

# k8s-cp01; read-only spisak bez deljenja kompletne tajne
kubeadm token list

# k8s-cp01; state-changing: novi token sa kratkim TTL-om i puna join komanda
kubeadm token create --ttl 30m --description tashizza-lab-worker-join \
  --print-join-command

# ciljni worker; izvršiti dobijenu komandu sa sudo, bez čuvanja u repozitorijumu
sudo kubeadm join 192.168.56.10:6443 \
  --token <NEW_BOOTSTRAP_TOKEN> \
  --discovery-token-ca-cert-hash sha256:<VERIFIED_CA_PUBLIC_KEY_HASH>

Podrazumevani token koji kreira kubeadm init važi 24 časa; u laboratoriji se namenski generiše token od 30 minuta. Ako je token dospeo u shell istoriju, uklanjanje jedne istorijske linije nije dovoljna zaštita: token se opoziva pomoću kubeadm token delete <TOKEN_ID>, a zatim se proverava kubeadm token list.

Scenario C: DNS/Service ili CNI simptom

Bez menjanja host mreže prvo se razlikuju slojevi. kubectl get endpointslices bez endpoint-a upućuje na selector/readiness; uspešan direktan Pod IP zahtev uz neuspešan Service zahtev upućuje na Service proxy ili politiku; neuspeh direktnog cross-node Pod IP zahteva uz lokalno uspešan zahtev upućuje na CNI/rutu/MTU/firewall; neuspešan nslookup uz uspešan HTTP ka ClusterIP-u upućuje na CoreDNS ili Pod DNS konfiguraciju.

kubectl get pods -n kube-system -o wide
kubectl get endpointslices -n lab-app -o yaml
kubectl describe pod -n lab-app test-client
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100
kubectl get events -A --sort-by=.metadata.creationTimestamp | tail -n 40
kubectl get pods -n calico-system -o wide
kubectl logs -n calico-system -l k8s-app=calico-node -c calico-node --tail=100

Ne menja se Pod CIDR na živom klasteru kao brza korekcija. Neusklađen CIDR je dizajnerska greška koja u ovoj laboratoriji zahteva čuvanje dokaza, uklanjanje workload-a i kontrolisanu ponovnu izgradnju ili zvaničan, verzijski podržan migracioni postupak. Ručno brisanje nasumičnih ruta, CNI interfejsa ili firewall pravila bez atribucije može proširiti kvar na host.

Administratorske prakse

Završna kontrolna lista

Zaključak

Administrator nakon ove lekcije treba da razume da funkcionalan Kubernetes klaster nastaje saradnjom operativnog sistema, kernel mrežnih funkcija, container runtime-a, kubelet-a, control plane komponenti i CNI dodatka. Kubeadm pojednostavljuje bootstrap, ali ne uklanja odgovornost za adresni plan, bezbednost hostova, izbor mreže, backup, nadogradnje i dijagnostiku.

Praktično znanje obuhvata pripremu čvorova, doslednu runtime i cgroup konfiguraciju, inicijalizaciju control plane-a, bezbedno priključivanje worker-a, instalaciju CNI-a i dokazivanje rada DNS-a, servisa i mrežnih politika. Jednako je važno umeti razlikovati normalno privremeno stanje, kao što je NotReady pre instalacije CNI-a, od stvarnog kvara runtime-a, mreže ili sertifikata.

Laboratorija omogućava kontrolisane greške, ali administrator i u njoj mora primenjivati produkcionu disciplinu: beležiti početno stanje, ograničiti privilegije, čuvati tajne, validirati svaku promenu i imati proverljiv rollback. Potpuni reset, brisanje mrežnih pravila ili manipulacija etcd podacima prelaze granicu rutinske intervencije i zahtevaju backup, jasan plan i razumevanje posledica.

Razlog za eskalaciju postoji kada problem uključuje nedostupnost ili korupciju etcd-a, neobjašnjive TLS greške, nekonzistentno stanje više čvorova, sumnju na kompromitovanje administratorskog identiteta, ponavljanu nestabilnost kernel-a ili runtime-a, kao i mrežne promene izvan ovlašćenja Kubernetes administratora. Odgovoran administrator ne prikriva simptom nasilnim resetom, već prikuplja događaje, logove, verzije i vremenski sled, štiti postojeće dokaze i uključuje vlasnike mreže, virtuelizacije, bezbednosti ili skladišta kada uzrok izlazi iz granica klastera.

← Prethodna lekcija Povratak na sadržaj Dodatak 2 →