Vanilla Kubernetes

Prvi deo: Temelji, arhitektura i izgradnja klastera
kubeadm i topologija klastera – bootstrap, endpoint kontrolne ravni i granice alata
II. Topologija, komponente i život klastera
6. kubeadm i topologija klastera – bootstrap, endpoint kontrolne ravni i granice alata

U prethodnoj lekciji lokalni klaster je posmatran kao instrument za određenu vrstu dokaza. Sada prelazimo na okruženje u kojem administrator neposredno odgovara za Linux čvorove, container runtime, kubelet, mrežnu dostupnost, PKI materijal i način na koji se kontrolna ravan izlaže ostatku klastera. kubeadm je zvanični Kubernetes alat za standardizovan bootstrap: izvršava proverljiv niz koraka kojima pripremljeni server postaje prvi control plane čvor ili se novi čvor pridružuje postojećem klasteru.

kubeadm nije kompletna platforma za obezbeđivanje infrastrukture i nije operater klastera tokom čitavog njegovog životnog ciklusa. On ne kreira virtuelne mašine, ne bira niti instalira CNI i CSI rešenje, ne obezbeđuje spoljašnji load balancer, DNS, firewall, monitoring, backup, upravljanje tajnama ili politiku oporavka. Upravo ta granica je njegova obrazovna vrednost: administrator jasno vidi koje odgovornosti pripadaju Kubernetes bootstrap-u, a koje ostaju infrastrukturi i operativnom timu.

U ovoj lekciji topologija se projektuje pre prve komande. Posebna pažnja posvećena je stabilnom controlPlaneEndpoint endpointu, izboru između jednog control plane čvora, stacked etcd i external etcd modela, konfiguracionom API-ju kubeadm-a, tokenima i sertifikatima, dokazima uspešnog bootstrap-a i kontrolisanom oporavku od tipičnih grešaka. Unutrašnji rad API servera, scheduler-a i controller manager-a biće sistematski obrađen u narednoj lekciji; ovde ih posmatramo onoliko koliko je potrebno da razumemo njihov nastanak i dostupnost.

Šta kubeadm radi, a šta namerno ne radi

Komanda kubeadm init izvršava uređeni workflow: proverava preduslove, priprema sertifikate i kubeconfig datoteke, generiše static Pod manifeste za komponente kontrolne ravni i lokalni etcd kada se koristi podrazumevana topologija, pokreće kubelet, čeka da kontrolna ravan postane dostupna, zapisuje bootstrap konfiguraciju u klaster, postavlja RBAC pravila i bootstrap tokene i instalira osnovne dodatke kao što su CoreDNS i kube-proxy. Pojedinačni koraci mogu se videti ili pozvati kroz kubeadm init phase, ali fazno izvršavanje zahteva disciplinu: preskočena ili ručno izmenjena faza postaje odgovornost administratora.

Na worker čvoru kubeadm join obavlja discovery klastera, proverava identitet API servera pomoću CA javnog ključa, preuzima potrebnu konfiguraciju, uspostavlja TLS bootstrap za kubelet i registruje Node objekat. Pri dodavanju novog control plane čvora join proces dodatno pribavlja ili koristi PKI materijal kontrolne ravni i generiše lokalne static Pod manifeste. Token nije dovoljan dokaz identiteta servera: bezbedan join uključuje i proveru discovery-token-ca-cert-hash vrednosti ili drugi eksplicitno projektovan discovery mehanizam.

kubeadm obezbeđujeAdministrator ili drugi sistem obezbeđuje
Bootstrap control plane i worker čvorovaVM, fizičke servere, OS image, firmware i kapacitet
Kubernetes PKI i kubeconfig datoteke u podrazumevanom modeluZaštitu ključeva, rotaciju, eksterni CA/KMS dizajn i bezbedan backup
Static Pod manifeste za lokalne control plane komponenteLoad balancer, DNS ime i health check za stabilan API endpoint
Bootstrap tokene i TLS bootstrap kubeletaPolitiku izdavanja, distribucije, isteka i opoziva tokena
CoreDNS i kube-proxy osnovne dodatkeCNI, CSI, ingress, observability, policy i backup rešenja
Komande za upgrade, sertifikate, tokene i reset kubeadm artefakataKompletan lifecycle OS-a, runtime-a, mreže, workload-a i DR plana

kubeadm se zato često koristi kao građevni blok u širem automatizovanom rešenju. Terraform može obezbediti infrastrukturu, Ansible pripremiti operativni sistem i pakete, load balancer i DNS automatizacija obezbediti endpoint, a kubeadm izvršiti Kubernetes-specifičan bootstrap. Činjenica da je kubeadm init uspešno završen nije sama po sebi dokaz da je klaster produkciono spreman.

Topologija pre bootstrap-a

Topologija određuje granice kvara, quorum, putanju do API servera, način održavanja i cenu oporavka. Odluka se ne svodi na broj servera. Potrebno je znati gde se nalaze etcd članovi, da li control plane čvorovi dele hipervizor, rack, mrežnu putanju ili storage, šta predstavlja stabilan endpoint i koja komponenta uklanja neispravan backend iz saobraćaja.

ModelRasporedPrednostiOgraničenja i rizik
Jedan control planeAPI server, controller manager, scheduler i jedan etcd član na istom čvoruNajmanje resursa; jasan laboratorijski bootstrapNema HA; kvar čvora ili etcd-a prekida upravljanje klasterom
HA sa stacked etcdNa svakom control plane čvoru radi i lokalni etcd članManje infrastrukturnih čvorova; najčešći kubeadm HA modelKvar control plane čvora istovremeno uklanja API backend i etcd člana; zahteva neparan quorum i stvarne failure-domain granice
HA sa external etcdControl plane i etcd rade na odvojenim skupovima čvorovaOdvojene granice kvara i mogućnost nezavisnog upravljanja etcd-omNajmanje tri dodatna etcd čvora za HA; više mreže, PKI-ja, monitoringa i operativne složenosti

Za HA stacked topologiju uobičajena su tri control plane čvora. Tri etcd člana mogu tolerisati gubitak jednog člana; pet mogu tolerisati dva, ali povećavaju mrežni i operativni trošak. Parni broj članova ne daje dodatnu toleranciju u odnosu na prethodni neparni broj. Quorum nije isto što i broj dostupnih API servera: klijent može dosegnuti jedan API server, a da kontrolna ravan ipak ne može pouzdano menjati stanje zato što etcd nema većinu.

Više VM na istom laptopu ili istom fizičkom hostu može demonstrirati distribuisane procese, ali ne predstavlja nezavisne failure domene. Produkcioni dizajn mora razmotriti hostove, rack-ove, zone dostupnosti, napajanje, mrežu, vremensku sinhronizaciju i latenciju etcd komunikacije. etcd zahteva pouzdan disk sa stabilnom latencijom; spor ili prezasićen storage može ugroziti kontrolnu ravan iako CPU i memorija izgledaju zdravo.

Endpoint kontrolne ravni: identitet koji mora nadživeti čvor

controlPlaneEndpoint je stabilna adresa preko koje se klijenti i čvorovi povezuju sa kontrolnom ravni, na primer k8s-api.lab.internal:6443. U HA dizajnu ta adresa obično pokazuje na TCP load balancer ili drugi podržan mehanizam koji prosleđuje saobraćaj samo zdravim API serverima. Ona nije isto što i localAPIEndpoint.advertiseAddress: advertise adresa pripada konkretnoj instanci API servera, dok control plane endpoint predstavlja klaster.

Stabilan DNS naziv treba izabrati pre bootstrap-a. kubeadm uključuje potrebna imena i adrese u Subject Alternative Name polja API server sertifikata. Naknadna promena endpointa nije obična DNS izmena: može zahtevati obnovu sertifikata i kubeconfig datoteka, promenu konfiguracije i pažljivo testiranje svih klijenata. Za laboratoriju sa jednim control plane čvorom DNS ime može privremeno pokazivati direktno na taj čvor; to ne daje HA, ali sprečava da identitet klastera bude trajno vezan za hostname pojedinačne mašine i omogućava kasnije plansko uvođenje load balancer-a.

ElementPrimerAdministratorska odluka i dokaz
Stabilno imek8s-api.lab.internalDNS se razrešava sa svih čvorova i administratorskih stanica
Port API servera6443/TCPFirewall i load balancer prosleđuju samo potreban saobraćaj
Backend10.20.30.11:6443U HA modelu postoje najmanje tri nezavisna control plane backenda
Health checkTCP ili odgovarajuća HTTPS proveraNeispravan backend se uklanja bez oslanjanja na ručnu intervenciju
SertifikatSAN sadrži DNS ime endpointaTLS validacija uspeva bez preskakanja provere sertifikata

Round-robin DNS bez health check-a nije ekvivalentan load balancer-u: može vraćati adresu neispravnog API servera i produžiti kvar zbog DNS cache-a. Load balancer takođe ne popravlja gubitak etcd quorum-a. Njegov zadatak je raspodela i uklanjanje neispravnih API backenda; konzistentnost stanja ostaje odgovornost etcd-a i kontrolne ravni.

Preduslovi čvorova i mrežni ugovor

Svi čvorovi moraju imati podržan Linux, jedinstveno ime hosta, MAC adresu i product_uuid, stabilnu adresu, sinhronizovano vreme i punu mrežnu dostupnost potrebnih portova. Klonirane VM mogu naslediti identitete i izazvati teško objašnjive konflikte. Pod CIDR i Service CIDR ne smeju se preklapati međusobno niti sa mrežom čvorova, VPN rutama, data-centar mrežama ili adresama koje organizacija planira da rutira.

Container runtime mora implementirati Kubernetes CRI. Docker Engine sam po sebi nije CRI runtime za kubelet; potreban je odgovarajući posredni sloj ili se koristi runtime kao što je containerd ili CRI-O. cgroup driver kubeleta i runtime-a mora biti usklađen, a systemd je preporučen izbor na systemd distribucijama. Ako je instalirano više runtime-a ili socket nije standardan, criSocket se navodi eksplicitno da auto-detekcija ne bi izabrala pogrešan endpoint.

Podrazumevano ponašanje kubeleta u kubeadm okruženju zahteva da swap bude onemogućen, osim ako je swap podrška namerno i verzijski usklađeno konfigurisana kroz kubelet. U ovoj laboratoriji swap se isključuje da bi početno stanje bilo jednoznačno. Produkciona promena swap politike, kernel modula, sysctl parametara ili firewall-a prolazi change proceduru i proveru uticaja na ostale servise.

hostnamectl --static
cat /sys/class/dmi/id/product_uuid
ip -brief address
ip route
timedatectl status
swapon --show
systemctl is-active containerd
containerd --version
kubeadm version -o short
kubelet --version
kubectl version --client
sudo ss -lntup

Prikazane komande čitaju stanje. Čitanje product_uuid može zahtevati drugačiju putanju ili privilegije na pojedinim platformama. Rezultati se porede između svih čvorova; uspeh nije samo odsustvo poruke o grešci, već jedinstveni identiteti, očekivane rute, sinhronizovano vreme, aktivan runtime i ista planirana Kubernetes minor verzija.

SaobraćajTipični portOdredišteNapomena
Kubernetes API6443/TCPControl plane / load balancerPotreban svim čvorovima i administratorima kojima je pristup odobren
etcd klijentski2379-2380/TCPetcd članoviNe izlagati široko; 2380 je peer komunikacija
Kubelet API10250/TCPSvi čvoroviOgraničiti na potrebne izvore
Scheduler10259/TCPControl plane lokalnoSecure port; ne zahteva široko mrežno izlaganje
Controller manager10257/TCPControl plane lokalnoSecure port; ne zahteva široko mrežno izlaganje
NodePort30000-32767/TCP/UDPČvoroviOtvarati samo ako dizajn i test to zahtevaju
CNI saobraćajZavisi od pluginaIzmeđu čvorovaProveriti zvaničnu dokumentaciju izabranog CNI-ja

Tabela je početni ugovor, ne univerzalna firewall politika. Tačni smerovi, izvori, protokoli i dodatni portovi zavise od topologije, CNI-ja, eksternog etcd-a i načina izlaganja servisa. Port se proverava sa stvarnog izvornog čvora; uspešna lokalna provera na control plane serveru ne dokazuje da worker može dosegnuti endpoint.

Verzije, repozitorijumi i konfiguracioni API

Kubernetes projekat održava tri najnovije minor grane. U julu 2026. to su 1.36, 1.35 i 1.34; za novu instalaciju bira se podržana grana i njen aktuelni patch, uz proveru release i security obaveštenja neposredno pre promene. Repozitorijumi paketa na pkgs.k8s.io odvojeni su po minor verziji. Paket ne treba neplanirano nadograditi prelaskom na drugu granu; kubeadm, kubelet i kubectl se pin-uju ili drže prema mehanizmu konkretne distribucije, a upgrade se izvodi svesno i u podržanom redosledu.

Za Kubernetes 1.36 aktuelni kubeadm konfiguracioni API je kubeadm.k8s.io/v1beta4. Stari primeri sa v1beta3 mogu biti korisni za starije grane, ali se ne kopiraju bez provere. Konfiguraciona datoteka je bolja od duge jednokratne komandne linije jer omogućava code review, verzionisanje, preflight proveru i ponovljivost. Tajne, bootstrap tokeni i privatni ključevi ipak se ne čuvaju u repozitorijumu.

apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 10.20.30.11
  bindPort: 6443
nodeRegistration:
  name: k8s-cp01
  criSocket: unix:///run/containerd/containerd.sock
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.36.2
clusterName: tashizza-lab
controlPlaneEndpoint: "k8s-api.lab.internal:6443"
networking:
  serviceSubnet: 10.96.0.0/12
  podSubnet: 10.244.0.0/16
  dnsDomain: cluster.local
apiServer:
  certSANs:
    - k8s-api.lab.internal
    - 10.20.30.10

Primer prikazuje laboratorijski plan: 10.20.30.11 je adresa prvog control plane čvora, a 10.20.30.10 rezervisana virtualna IP adresa budućeg load balancer-a. Ako load balancer još ne postoji, DNS ime u single-control-plane laboratoriji može pokazivati na 10.20.30.11, ali IP 10.20.30.10 ne treba oglašavati niti koristiti dok zaista nije implementiran. Vrednost kubernetesVersion u stvarnoj vežbi mora se zameniti aktuelnim odobrenim patch-em iz izabrane minor grane; ovde je navedena vremenski određena laboratorijska vrednost iz jula 2026, a ne trajni „latest”.

Pre promene stanja konfiguracija se može normalizovati i proveriti lokalnim kubeadm komandama. config migrate je koristan pri prelasku sa starije kubeadm API verzije, ali rezultat mora proći pregled; migracija sintakse ne dokazuje da je svaka stara operativna odluka i dalje dobra.

sudo kubeadm config validate --config /etc/kubernetes/kubeadm-init.yaml
sudo kubeadm config images list --config /etc/kubernetes/kubeadm-init.yaml
sudo kubeadm init --config /etc/kubernetes/kubeadm-init.yaml --dry-run

Validacija i listanje slika ne menjaju klaster. --dry-run ne izvršava stvarni bootstrap, ali može kreirati privremene lokalne artefakte i ne zamenjuje proveru mreže, DNS-a, image registry pristupa ni CNI kompatibilnosti. Komande se izvršavaju na planiranom prvom control plane čvoru sa sudo zato što kubeadm čita i priprema sistemske putanje.

Bootstrap prvog control plane čvora

Pre init komande mora postojati odobren plan, sačuvana konfiguracija, dokaz da su preduslovi zadovoljeni i rollback tačka za laboratoriju. kubeadm preflight greške se ne zaobilaze automatski opcijom --ignore-preflight-errors. Upozorenje se prvo tumači: ako je uzrok pogrešan hostname, aktivan swap, zauzet port, postojeći manifest ili nedostupan runtime, ignorisanje samo pomera kvar dublje u bootstrap i otežava cleanup.

Tokom bootstrap-a kubelet posmatra /etc/kubernetes/manifests i pokreće static Podove kontrolne ravni. Njih nema u Deployment objektima; lokalni kubelet je njihov neposredni upravljač, a API server kasnije prikazuje mirror Podove. Zato se rani kvar ne dijagnostikuje samo komandom kubectl get pods: API možda još nije dostupan, pa su journalctl -u kubelet, runtime alat i sadržaj manifest direktorijuma primarni dokazi.

sudo kubeadm init \
  --config /etc/kubernetes/kubeadm-init.yaml \
  --upload-certs \
  2>&1 | tee "$HOME/kubeadm-init-$(date -u +%Y%m%dT%H%M%SZ).log"

Ovo je state-changing i bezbednosno osetljiva komanda. Opcija --upload-certs privremeno šifrovano otprema zajedničke control plane sertifikate u klaster kako bi se olakšao join dodatnih control plane čvorova; odgovarajući certificate-key je tajna i automatski upload ima ograničen rok. U single-control-plane laboratoriji opcija nije neophodna, ali je uključena samo ako je sledeći odobreni korak vežba HA pridruživanja. Log može sadržati join podatke i zato se čuva sa restriktivnim dozvolama, ne objavljuje se i ne ulazi u Git.

mkdir -p "$HOME/.kube"
sudo install -o "$(id -u)" -g "$(id -g)" -m 0600 \
  /etc/kubernetes/admin.conf "$HOME/.kube/config"

kubectl cluster-info
kubectl get nodes -o wide
kubectl get pods -A -o wide

admin.conf daje privilegovani administratorski identitet i mora se štititi kao tajna. Kopiranje je state-changing lokalna operacija; naredne tri komande čitaju stanje. Pre instalacije CNI-ja očekivano je da Node još nije Ready i da CoreDNS Podovi nisu funkcionalni. To nije dokaz da je bootstrap neuspešan: proverava se da li API odgovara, static Podovi kontrolne ravni rade i događaji ukazuju na odsustvo mrežnog plugina, a ne na certifikat, runtime ili endpoint kvar.

CNI kao obavezna, ali odvojena odluka

kubeadm namerno ne bira Pod mrežu. Administrator bira CNI implementaciju čija verzija podržava odabranu Kubernetes granu, čiji adresni model odgovara podSubnet planu i čiji zahtevi za kernel module, MTU, encapsulation, BGP, firewall i NetworkPolicy odgovaraju infrastrukturi. Manifest se pre primene preuzima iz zvaničnog izvora izabranog projekta, verzioniše interno ili pin-uje na proverenu verziju, pregleda i po mogućnosti proverava kontrolnom sumom ili potpisom.

kubectl diff -f "$HOME/lab/cni-manifest.yaml" || true
kubectl apply -f "$HOME/lab/cni-manifest.yaml"
kubectl get pods -n kube-system -w
kubectl wait --for=condition=Ready node/k8s-cp01 --timeout=300s

diff je read-oriented provera, mada kontaktira API i vraća poseban izlazni kod kada razlika postoji; apply menja stanje. Ne koristi se neproveren „latest” URL direktno u produkcionoj komandi. Očekivani rezultat je da CNI DaemonSet dostigne željeni broj spremnih Podova, CoreDNS postane Running i čvor dobije stanje Ready. Ako se to ne dogodi, prvo se pregledaju događaji i logovi CNI Podova, CIDR preklapanje, kernel zahtevi i MTU, umesto ponavljanja kubeadm init komande.

Pridruživanje worker i dodatnih control plane čvorova

Podrazumevani bootstrap token ima ograničen rok važenja. Join komanda iz izlaza kubeadm init nije trajni administratorski artefakt niti treba da se šalje kroz nezaštićen chat ili tiket. Kada je potreban novi worker, na control plane čvoru se kreira namenski kratkotrajan token, beleži svrha, a komanda se prenosi odobrenim tajnim kanalom.

sudo kubeadm token list
sudo kubeadm token create \
  --ttl 30m \
  --description "join k8s-wk01 and k8s-wk02" \
  --print-join-command

Prva komanda čita stanje; druga menja stanje i ispisuje tajnu. Pre izvršavanja join komande worker mora proći iste OS, runtime, swap, DNS i mrežne provere. Na workeru se endpoint dodatno proverava bez slanja tokena u istoriju komandi kad god automatizacioni mehanizam omogućava bezbedno prosleđivanje tajne.

getent hosts k8s-api.lab.internal
nc -vz k8s-api.lab.internal 6443
sudo kubeadm join k8s-api.lab.internal:6443 \
  --token <BOOTSTRAP_TOKEN> \
  --discovery-token-ca-cert-hash sha256:<CA_PUBLIC_KEY_HASH>

Prve dve komande čitaju i proveravaju mrežno stanje; join menja čvor i klaster. Placeholder vrednosti se ne unose doslovno. Očekivani rezultat je uspešan TLS bootstrap i registracija čvora. Na control plane čvoru se zatim proveravaju Node objekat, uslovi, dodeljeni Pod CIDR i CNI Pod na novom čvoru. Ready je potreban, ali nije dovoljan dokaz: testira se i Pod-to-Pod komunikacija, DNS i raspoređivanje workload-a.

Dodatni control plane čvor pridružuje se opcijom --control-plane i, u automatizovanom upload modelu, odgovarajućim --certificate-key. Pre toga stabilni endpoint već mora biti load balancer koji može proslediti saobraćaj na postojeći zdravi API server. Novi backend se dodaje u load balancer tek kada njegov API server i lokalni etcd član prođu health provere. Sertifikacioni ključ i bootstrap token su dve različite tajne sa različitim ulogama; obe se povlače ili ostavljaju da isteknu čim odobreni join prozor završi.

Artefakti, identiteti i bezbednosne granice

ArtefaktUlogaRizik i praksa
/etc/kubernetes/pkiCA, klijentski i serverski sertifikati i ključeviPrivatni ključevi su kritične tajne; backup mora biti šifrovan, kontrolisan i testiran
/etc/kubernetes/admin.confAdministratorski kubeconfigVisoko privilegovan; ne deliti kao korisnički kubeconfig
/etc/kubernetes/manifestsStatic Pod manifesti kontrolne ravni i lokalnog etcd-aIzmena odmah utiče na kubelet; prvo backup, diff i plan povratka
/var/lib/etcdPodaci lokalnog stacked etcd članaNe kopirati kao običan „live” direktorijum; koristiti podržan snapshot i recovery postupak
Bootstrap tokenPrivremeni discovery i TLS bootstrapKratak TTL, ograničena distribucija, revocation posle upotrebe
Certificate keyDešifrovanje privremeno otpremljenih control plane sertifikataPosebno osetljiva kratkotrajna tajna; nije isto što i CA hash
CA public key hashPinovanje identiteta root CA pri token discovery-juNije privatna tajna, ali mora biti autentično distribuiran

Čuvanje admin.conf datoteke za svakog administratora stvara zajednički identitet bez individualnog audit traga. Posle inicijalnog bootstrap-a uspostavlja se organizacioni identity provider, zasebni korisnički identiteti i RBAC najmanjih privilegija. Bootstrap superuser pristup ostaje break-glass mehanizam pod strogom kontrolom, a ne svakodnevni način rada.

Granice promena i životni ciklus kubeadm klastera

kubeadm čuva ClusterConfiguration u ConfigMap objektu kubeadm-config, ali izmena tog objekta sama po sebi ne prepisuje automatski sve lokalne manifeste i konfiguracije. Rekonfiguracija komponenti zahteva verzijski odgovarajući podržan postupak, backup lokalnih fajlova, kontrolisano izvršavanje faza ili patch mehanizma i validaciju. Direktno ručno uređivanje static Pod manifesta može izazvati trenutni restart komponente; zato nije bezazlena „konfiguraciona promena”.

Nadogradnja se ne radi paketnim upgrade svih čvorova odjednom. kubeadm ima planirani workflow, pravila version skew-a i redosled control plane pa worker čvorova. Sertifikati koje kubeadm izdaje imaju rok važenja i proveravaju se komandom kubeadm certs check-expiration; automatska obnova tokom upgrade-a ne zamenjuje evidenciju, alarmiranje, backup i vežbu oporavka. Detaljan lifecycle i upgrade pripadaju kasnijim lekcijama, ali topologija izabrana danas određuje koliko će ti postupci biti bezbedni.

sudo kubeadm certs check-expiration
kubectl -n kube-system get configmap kubeadm-config -o yaml
kubectl get --raw='/readyz?verbose'
kubectl get --raw='/livez?verbose'

Komande čitaju stanje. readyz odgovara na pitanje da li je API server spreman da prihvati saobraćaj, dok livez prvenstveno pokazuje da li proces treba smatrati živim; load balancer health check se bira prema nameni i aktuelnim Kubernetes preporukama. Ne koristi se istorijski nebezbedan health endpoint niti se TLS validacija isključuje samo da bi provera „prošla”.


Integrisani praktikum – bootstrap klastera sa stabilnim endpointom

Kontekst i cilj. Tim priprema realističnu laboratoriju sa jednim control plane i dva worker čvora. Cilj je da se pre bootstrap-a formalizuju topologija i mrežni ugovor, da se klaster kreira deklarativnom kubeadm konfiguracijom, instalira prethodno odobren CNI, pridruže worker čvorovi, potvrde osnovne funkcije, simulira tipičan join incident i prikupe dokazi. Laboratorija namerno nije HA; stabilno DNS ime priprema migraciju ka budućem load balancer-u bez lažne tvrdnje o redundansi.

Čvor / imeAdresaUlogaMinimalni laboratorijski budžet
k8s-cp0110.20.30.11Control plane + stacked single-member etcd2 vCPU, 4 GB RAM, 40 GB disk
k8s-wk0110.20.30.21Worker2 vCPU, 3 GB RAM, 30 GB disk
k8s-wk0210.20.30.22Worker2 vCPU, 3 GB RAM, 30 GB disk
k8s-api.lab.internal10.20.30.11 u ovoj vežbiStabilni API identitetInterni DNS zapis dostupan svim čvorovima

Preduslovi. Sve tri VM imaju podržan Linux release, jedinstvene identitete, statične DHCP rezervacije ili druge stabilne adrese, sinhronizovano vreme, containerd sa usklađenim systemd cgroup driver-om i pakete kubeadm, kubelet i kubectl iz iste odobrene minor grane. Paket kubelet može biti u stanju restarta pre init/join postupka jer još nema konfiguraciju. Pripremljen je provereni lokalni fajl $HOME/lab/cni-manifest.yaml iz zvaničnog izvora izabranog CNI projekta, kompatibilan sa Pod CIDR-om 10.244.0.0/16.

Nalozi i privilegije. Koristi se imenovani Linux administrator sa sudo pravima. Root login i deljenje admin.conf datoteke nisu potrebni. Bootstrap token i certificate key ne upisuju se u Git, tiket ili nezaštićen terminal transcript.

Rizik i rollback. Vežba menja mrežne i Kubernetes sistemske putanje na tri namenske VM. Pre početka napraviti proverene powered-off snapshot-e čistih laboratorijskih VM ili automatizovan način ponovnog kreiranja. Snapshot nije produkcioni backup. kubeadm reset koristi se samo na tačno potvrđenom laboratorijskom čvoru i nije potpun cleanup svih CNI, firewall, kubeconfig ili storage artefakata.

  1. Dokumentovati plan i početno stanje na sva tri čvora.
    mkdir -p "$HOME/lab/evidence"
    {
      date -u
      hostnamectl --static
      cat /sys/class/dmi/id/product_uuid
      ip -brief address
      ip route
      timedatectl status
      swapon --show
      systemctl is-active containerd
      containerd --version
      kubeadm version -o short
      kubelet --version
    } | tee "$HOME/lab/evidence/$(hostname)-preflight.txt"

    Očekivani rezultat i validacija: svaki čvor ima tačno planirano ime i adresu, jedinstven UUID, očekivanu default rutu, sinhronizovano vreme, nema aktivan swap, containerd je aktivan i Kubernetes alati pripadaju odobrenoj minor grani. Komande su read-only osim kreiranja lokalnog direktorijuma i evidence fajla.

  2. Proveriti DNS i portove iz stvarnih izvora.
    getent ahostsv4 k8s-api.lab.internal
    for host in 10.20.30.11 10.20.30.21 10.20.30.22; do
      ping -c 2 "$host"
    done
    nc -vz k8s-api.lab.internal 6443 || true
    sudo ss -lntup

    Tumačenje: DNS mora vratiti 10.20.30.11. Pre bootstrap-a je očekivano da port 6443 još ne sluša; važan dokaz je da ime pravilno pokazuje na planiranu adresu i da firewall pravila neće blokirati buduću putanju. ICMP uspeh ne dokazuje TCP dostupnost. Na workerima proveriti da nijedan Kubernetes sistemski port već nije zauzet.

  3. Kreirati konfiguraciju na k8s-cp01.
    sudo install -d -m 0700 /etc/kubernetes
    sudoedit /etc/kubernetes/kubeadm-init.yaml
    sudo chmod 0600 /etc/kubernetes/kubeadm-init.yaml

    U editor uneti sledeći sadržaj, uz aktuelni odobreni patch umesto demonstracione vrednosti ako se vežba izvodi kasnije:

    apiVersion: kubeadm.k8s.io/v1beta4
    kind: InitConfiguration
    localAPIEndpoint:
      advertiseAddress: 10.20.30.11
      bindPort: 6443
    nodeRegistration:
      name: k8s-cp01
      criSocket: unix:///run/containerd/containerd.sock
    ---
    apiVersion: kubeadm.k8s.io/v1beta4
    kind: ClusterConfiguration
    kubernetesVersion: v1.36.2
    clusterName: tashizza-lab
    controlPlaneEndpoint: "k8s-api.lab.internal:6443"
    networking:
      serviceSubnet: 10.96.0.0/12
      podSubnet: 10.244.0.0/16
      dnsDomain: cluster.local
    apiServer:
      certSANs:
        - k8s-api.lab.internal
        - 10.20.30.11

    Rizik: konfiguracija ne sadrži token, ali otkriva internu topologiju; dozvole su restriktivne. Adresa, ime čvora, CRI socket i CIDR vrednosti moraju odgovarati stvarnom planu. Ne dodavati buduću virtualnu IP adresu kao aktivnu putanju ako ona nije rezervisana i kontrolisana.

  4. Validirati konfiguraciju i preuzeti slike pre change prozora.
    sudo kubeadm config validate --config /etc/kubernetes/kubeadm-init.yaml
    sudo kubeadm config images list --config /etc/kubernetes/kubeadm-init.yaml \
      | tee "$HOME/lab/evidence/control-plane-images.txt"
    sudo kubeadm config images pull --config /etc/kubernetes/kubeadm-init.yaml
    sudo kubeadm init --config /etc/kubernetes/kubeadm-init.yaml --dry-run \
      2>&1 | tee "$HOME/lab/evidence/kubeadm-dry-run.txt"

    Promena stanja: images pull puni runtime image cache, ali ne kreira klaster; ostale komande su validacija. Kriterijum: nema fatalne preflight greške, sve slike su dostupne i postoji dovoljno diska. Ako registry nije dostupan, problem se rešava proxy/mirror i supply-chain procedurom, ne isključivanjem TLS provere.

  5. Pokrenuti bootstrap prvog control plane čvora.
    umask 077
    sudo kubeadm init --config /etc/kubernetes/kubeadm-init.yaml \
      2>&1 | tee "$HOME/lab/evidence/kubeadm-init.log"

    Očekivani rezultat: kubeadm završava sve faze i prikazuje uputstvo za kubeconfig i worker join. Ovo je state-changing korak. Ako komanda ne uspe, ne pokretati je naslepo drugi put; sačuvati izlaz, journalctl i runtime stanje, utvrditi poslednju završenu fazu i tek zatim izabrati recovery.

  6. Postaviti administratorski kubeconfig i potvrditi ranu kontrolnu ravan.
    mkdir -p "$HOME/.kube"
    sudo install -o "$(id -u)" -g "$(id -g)" -m 0600 \
      /etc/kubernetes/admin.conf "$HOME/.kube/config"
    
    kubectl cluster-info
    kubectl get --raw='/readyz?verbose' | tee "$HOME/lab/evidence/apiserver-readyz.txt"
    kubectl get nodes -o wide
    kubectl get pods -n kube-system -o wide
    sudo crictl ps --name 'kube-apiserver|kube-scheduler|kube-controller-manager|etcd'

    Validacija: API je dostupan preko DNS endpointa navedenog u kubeconfig-u, static Pod kontejneri rade, a jedini čvor može privremeno biti NotReady zbog neinstaliranog CNI-ja. Ako crictl nije konfigurisan za pravi runtime endpoint, prvo se rešava endpoint upozorenje; ne zaključuje se da kontejneri ne postoje.

  7. Instalirati prethodno odobren CNI i dokazati stabilizaciju.
    sha256sum "$HOME/lab/cni-manifest.yaml" \
      | tee "$HOME/lab/evidence/cni-manifest.sha256"
    kubectl diff -f "$HOME/lab/cni-manifest.yaml" || true
    kubectl apply -f "$HOME/lab/cni-manifest.yaml"
    kubectl get pods -n kube-system -w

    Kada se CNI Podovi stabilizuju, u drugom terminalu izvršiti:

    kubectl wait --for=condition=Ready node/k8s-cp01 --timeout=300s
    kubectl get daemonsets -n kube-system
    kubectl get pods -n kube-system -o wide
    kubectl get events -A --sort-by=.metadata.creationTimestamp \
      > "$HOME/lab/evidence/events-after-cni.txt"

    Kriterijum: control plane čvor je Ready, CNI DaemonSet i CoreDNS imaju očekivan broj spremnih instanci, a događaji ne pokazuju trajni sandbox ili routing kvar. Kontrolna suma omogućava kasnije dokazivanje tačne CNI deklaracije.

  8. Kreirati kratkotrajan worker join postupak.
    sudo kubeadm token create \
      --ttl 30m \
      --description "lab workers 2026-07" \
      --print-join-command

    Bezbednost: izlaz se prenosi samo na k8s-wk01 i k8s-wk02 odobrenim kanalom. Komanda menja stanje kreiranjem tokena. U dokazima se beleže opis, vreme i kasniji status tokena, ali ne njegova puna vrednost.

  9. Na svakom workeru proveriti endpoint i izvršiti join.
    getent hosts k8s-api.lab.internal
    nc -vz k8s-api.lab.internal 6443
    sudo kubeadm join k8s-api.lab.internal:6443 \
      --token <BOOTSTRAP_TOKEN> \
      --discovery-token-ca-cert-hash sha256:<CA_PUBLIC_KEY_HASH>

    Očekivani rezultat: kubeadm potvrđuje uspešan join. Placeholder vrednosti zamenjuju se tajnim, autentično dobijenim vrednostima. Komanda se izvršava jednom po workeru. Ako join ne uspe, pre ponavljanja proveravaju se DNS, vreme, port 6443, token TTL, CA hash, runtime i kubelet logovi.

  10. Sa control plane čvora validirati oba workera.
    kubectl get nodes -o wide
    kubectl wait --for=condition=Ready node/k8s-wk01 --timeout=300s
    kubectl wait --for=condition=Ready node/k8s-wk02 --timeout=300s
    kubectl describe node k8s-wk01
    kubectl describe node k8s-wk02
    kubectl get pods -n kube-system -o wide

    Kriterijum: tri Node objekta postoje, svi su Ready, imaju očekivane interne adrese i Pod CIDR vrednosti, a CNI komponenta radi na svakom čvoru. Pošto control plane čvor standardno ima taint, obični workload-i treba da se raspoređuju na workere; taint se ne uklanja samo da bi laboratorijski kapacitet izgledao veći.

  11. Izvršiti funkcionalni DNS i raspoređivački test.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: topology-test
      namespace: default
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: topology-test
      template:
        metadata:
          labels:
            app: topology-test
        spec:
          containers:
            - name: web
              image: registry.k8s.io/e2e-test-images/agnhost:2.53
              args: ["netexec", "--http-port=8080"]
              ports:
                - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: topology-test
      namespace: default
    spec:
      selector:
        app: topology-test
      ports:
        - port: 80
          targetPort: 8080

    Manifest sačuvati kao $HOME/lab/topology-test.yaml, zatim:

    kubectl apply -f "$HOME/lab/topology-test.yaml"
    kubectl rollout status deployment/topology-test --timeout=180s
    kubectl get pods -o wide
    kubectl get service topology-test
    kubectl get endpointslice -l kubernetes.io/service-name=topology-test
    kubectl run dns-test --rm -i --restart=Never \
      --image=registry.k8s.io/e2e-test-images/agnhost:2.53 \
      --command -- /bin/sh -c \
      'nslookup topology-test.default.svc.cluster.local && wget -qO- http://topology-test'

    Validacija: dve replike rade na worker čvorovima kada kapacitet to dopušta, EndpointSlice sadrži spremne endpoint-e, DNS ime servisa se razrešava i HTTP zahtev vraća odgovor. Test proverava osnovni scheduling, CNI i DNS tok; ne dokazuje NetworkPolicy, ingress, trajni storage ni HA kontrolne ravni.

  12. Simulirati istekao ili pogrešan join token bez menjanja zdravih čvorova.

    Na control plane čvoru kreirati token sa kratkim TTL-om samo za kontrolisanu vežbu, zabeležiti njegov ID, sačekati istek van produkcionog change prozora ili ga odmah opozvati, a zatim pokušati join na čistoj dodatnoj VM k8s-wk03. Bezbednija i brža simulacija je opoziv pre upotrebe:

    TOKEN=$(sudo kubeadm token create --ttl 10m --description "negative join test")
    TOKEN_ID=${TOKEN%%.*}
    sudo kubeadm token delete "$TOKEN_ID"
    sudo kubeadm token list

    Na čistom testnom workeru pokušati join sa opozvanim tokenom i ispravnim CA hash-em. Token se unosi iz sigurnog privremenog izvora, ne iz shell istorije u produkciji.

    sudo kubeadm join k8s-api.lab.internal:6443 \
      --token <REVOKED_TOKEN> \
      --discovery-token-ca-cert-hash sha256:<CA_PUBLIC_KEY_HASH>

    Očekivani simptom: discovery ili autentikacija ne uspeva; zdravi klaster i postojeći čvorovi ostaju nepromenjeni. Neposredni uzrok: token više nije važeći. Osnovni uzrok: namerna negativna proba. Korekcija: potvrditi identitet testnog workera, kreirati nov kratkotrajan token sa opisom i ponoviti join samo ako je taj čvor odobren. Ne koristiti --discovery-token-unsafe-skip-ca-verification kao workaround.

  13. Prikupiti završne dokaze i zatvoriti bootstrap prozor.
    kubectl get nodes -o wide \
      > "$HOME/lab/evidence/nodes-final.txt"
    kubectl get pods -A -o wide \
      > "$HOME/lab/evidence/pods-final.txt"
    kubectl get events -A --sort-by=.metadata.creationTimestamp \
      > "$HOME/lab/evidence/events-final.txt"
    kubectl get --raw='/readyz?verbose' \
      > "$HOME/lab/evidence/readyz-final.txt"
    sudo kubeadm token list \
      | sed -E 's/[a-z0-9]{6}\.[a-z0-9]{16}/REDACTED/g' \
      > "$HOME/lab/evidence/token-status-redacted.txt"
    tar -C "$HOME/lab" -czf "$HOME/tashizza-kubeadm-evidence.tar.gz" evidence
    sha256sum "$HOME/tashizza-kubeadm-evidence.tar.gz"

    Kriterijum završetka: sva tri planirana čvora su Ready; testni workload, Service i DNS rade; nema nepotrebnog aktivnog tokena; dokazna arhiva ne sadrži tajne i ima kontrolnu sumu. CNI manifest i kubeadm konfiguracija čuvaju se u kontrolisanom repozitorijumu samo nakon pregleda i uklanjanja osetljivih podataka.

Troubleshooting – od simptoma do potvrđenog uzroka

Dijagnostika počinje vremenom incidenta, obimom i poslednjom promenom. Najpre se prikupljaju dokazi koji ne menjaju stanje, zatim se postavlja hipoteza, a korektivna akcija se bira tek kada nalaz podržava uzrok. Restart kubeleta, brisanje manifesta ili kubeadm reset nisu početne dijagnostičke komande.

SimptomPrvi dokazVerovatni uzrokBezbedna korekcija
Preflight prijavljuje aktivan swapswapon --show i kubelet konfiguracijaOS image nije pripremljen ili swap politika nije usklađenaU labu planski isključiti swap; u produkciji primeniti odobrenu, verzijski podržanu politiku
kubeadm init čeka control planejournalctl -u kubelet, crictl ps -a, crictl logsRuntime, cgroup, image, sertifikat, bind adresa ili static Pod crashIspraviti dokazani uzrok; ne ignorisati preflight niti ponavljati init naslepo
API radi lokalno, worker ne može da se pridružiDNS i TCP 6443 provera sa workeraPogrešan DNS, firewall, route ili endpointIspraviti mrežni ugovor ili load balancer; ne menjati token dok mreža nije potvrđena
Join prijavljuje nevažeći tokenkubeadm token list i vreme na čvorovimaToken je istekao/opozvan ili sat nije tačanKreirati novi kratkotrajan token posle potvrde identiteta čvora
CA hash se ne poklapaAutentični hash iz kontrolisanog izvoraPogrešan klaster, kopiranje ili potencijalni MITMZaustaviti join i nezavisno potvrditi endpoint i CA; nikada naslepo preskočiti proveru
Node postoji ali je NotReadyNode Conditions, Events, CNI Pod i kubelet logCNI nije instaliran ili ima CIDR/MTU/kernel kvarIspraviti CNI uzrok; ponovno init nije rešenje
CoreDNS ostaje PendingPod Events i dostupni čvorovi/taint-iNema spremnog schedulable workera ili CNI nije funkcionalanOsposobiti worker/CNI; ne uklanjati control plane taint bez dizajnerske odluke
HA endpoint povremeno ne odgovaraLB backend health, API readyz, etcd quorumNezdrav backend, DNS round-robin ili gubitak etcd većineIzolovati sloj; LB korekcija ne može vratiti izgubljen etcd quorum
sudo journalctl -u kubelet --since '-20 min' --no-pager
sudo crictl ps -a
sudo crictl logs <CONTAINER_ID>
sudo ls -l /etc/kubernetes/manifests
sudo ss -lntp | grep -E ':6443|:2379|:2380|:10250'
kubectl get nodes
kubectl get pods -n kube-system -o wide
kubectl get events -A --sort-by=.metadata.creationTimestamp
kubectl get --raw='/readyz?verbose'

Kubelet journal stvara systemd servis kubelet i u njemu se traže greške vezane za tačno vreme bootstrap-a: CRI endpoint, cgroup, static Pod, certifikat i probe. crictl čita runtime stanje i logove kontejnera čak i kada API server nije dostupan. Kubernetes Events su korisni za redosled skorijih događaja, ali nisu trajni audit sistem; za dužu korelaciju potrebni su centralizovani logovi i monitoring.

Bezbedan reset i povratak laboratorije

kubeadm reset pokušava da vrati promene koje su napravili init ili join. Na control plane čvoru sa stacked etcd-om uklanja i lokalnog etcd člana. Komanda je destruktivna i ne izvršava se kao opšti „repair”; pre nje se potvrđuju hostname, IP, uloga čvora, postojanje potrebnog backup-a i plan za uklanjanje člana. U zdravom višekontrolnom klasteru pogrešan reset može smanjiti etcd quorum i produžiti incident.

Reset ne čisti nužno CNI konfiguraciju u /etc/cni/net.d, sva mrežna pravila, korisnički $HOME/.kube/config ili podatke eksternog storage-a. Cleanup je zavisan od CNI-ja i okruženja. Najbezbedniji povratak ove vežbe je gašenje i vraćanje unapred proverenih čistih VM snapshot-a ili potpuno ponovno kreiranje VM iz automatizacije.

hostnamectl --static
ip -brief address
sudo kubeadm reset --dry-run
sudo kubeadm reset --force

Prve dve komande potvrđuju cilj; --dry-run prikazuje plan bez namernog izvršavanja promena, a poslednja komanda destruktivno menja stanje. Izvršava se samo na namenskoj laboratorijskoj VM posle čuvanja dokaza. Zatim se primenjuje dokumentovani cleanup izabranog CNI-ja ili se VM vraća na čistu snapshot tačku. Ručno univerzalno brisanje iptables/nftables pravila nije bezbedan generički korak jer može ukloniti pravila drugih servisa.

Administratorske prakse

Završna kontrolna tačka

Zaključak

kubeadm pretvara pripremljene Linux čvorove u Kubernetes klaster kroz standardizovan, fazni i proverljiv bootstrap. Njegova snaga nije u tome što skriva infrastrukturu, već što jasno odvaja Kubernetes-specifične korake od odgovornosti koje ostaju administratoru: serveri, runtime, mreža, DNS, load balancer, CNI, storage, identitet, monitoring, backup i oporavak.

Najvažnija arhitektonska odluka ove lekcije jeste da identitet kontrolne ravni pripada klasteru, a ne prvom serveru. Stabilan controlPlaneEndpoint, ispravan TLS SAN, zdravi API backend-i i održan etcd quorum čine povezanu, ali ne istu celinu. Single-control-plane laboratorija može verno naučiti bootstrap i dijagnostiku; ne može dokazati HA. Stacked i external etcd modeli zatim menjaju failure domene, broj čvorova, mrežne zavisnosti i složenost oporavka.

Posle praktikuma čitalac ume da formalizuje topologiju, proveri preduslove, validira kubeadm konfiguraciju, podigne prvi control plane, instalira odobrenu Pod mrežu, bezbedno pridruži workere, potvrdi DNS i workload tok, analizira neuspešan join i vrati laboratoriju u poznato stanje. To je osnova za narednu lekciju, u kojoj se komponente kontrolne ravni više ne posmatraju samo kao bootstrap artefakti, već kao učesnici u kompletnom toku upravljačke odluke.

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