Vanilla Kubernetes
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đuje | Administrator ili drugi sistem obezbeđuje |
|---|---|
| Bootstrap control plane i worker čvorova | VM, fizičke servere, OS image, firmware i kapacitet |
| Kubernetes PKI i kubeconfig datoteke u podrazumevanom modelu | Zaštitu ključeva, rotaciju, eksterni CA/KMS dizajn i bezbedan backup |
| Static Pod manifeste za lokalne control plane komponente | Load balancer, DNS ime i health check za stabilan API endpoint |
| Bootstrap tokene i TLS bootstrap kubeleta | Politiku izdavanja, distribucije, isteka i opoziva tokena |
| CoreDNS i kube-proxy osnovne dodatke | CNI, CSI, ingress, observability, policy i backup rešenja |
| Komande za upgrade, sertifikate, tokene i reset kubeadm artefakata | Kompletan 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.
| Model | Raspored | Prednosti | Ograničenja i rizik |
|---|---|---|---|
| Jedan control plane | API server, controller manager, scheduler i jedan etcd član na istom čvoru | Najmanje resursa; jasan laboratorijski bootstrap | Nema HA; kvar čvora ili etcd-a prekida upravljanje klasterom |
| HA sa stacked etcd | Na svakom control plane čvoru radi i lokalni etcd član | Manje infrastrukturnih čvorova; najčešći kubeadm HA model | Kvar control plane čvora istovremeno uklanja API backend i etcd člana; zahteva neparan quorum i stvarne failure-domain granice |
| HA sa external etcd | Control plane i etcd rade na odvojenim skupovima čvorova | Odvojene granice kvara i mogućnost nezavisnog upravljanja etcd-om | Najmanje 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.
| Element | Primer | Administratorska odluka i dokaz |
|---|---|---|
| Stabilno ime | k8s-api.lab.internal | DNS se razrešava sa svih čvorova i administratorskih stanica |
| Port API servera | 6443/TCP | Firewall i load balancer prosleđuju samo potreban saobraćaj |
| Backend | 10.20.30.11:6443 | U HA modelu postoje najmanje tri nezavisna control plane backenda |
| Health check | TCP ili odgovarajuća HTTPS provera | Neispravan backend se uklanja bez oslanjanja na ručnu intervenciju |
| Sertifikat | SAN sadrži DNS ime endpointa | TLS 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ćaj | Tipični port | Odredište | Napomena |
|---|---|---|---|
| Kubernetes API | 6443/TCP | Control plane / load balancer | Potreban svim čvorovima i administratorima kojima je pristup odobren |
| etcd klijentski | 2379-2380/TCP | etcd članovi | Ne izlagati široko; 2380 je peer komunikacija |
| Kubelet API | 10250/TCP | Svi čvorovi | Ograničiti na potrebne izvore |
| Scheduler | 10259/TCP | Control plane lokalno | Secure port; ne zahteva široko mrežno izlaganje |
| Controller manager | 10257/TCP | Control plane lokalno | Secure port; ne zahteva široko mrežno izlaganje |
| NodePort | 30000-32767/TCP/UDP | Čvorovi | Otvarati samo ako dizajn i test to zahtevaju |
| CNI saobraćaj | Zavisi od plugina | Između čvorova | Proveriti 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
| Artefakt | Uloga | Rizik i praksa |
|---|---|---|
/etc/kubernetes/pki | CA, klijentski i serverski sertifikati i ključevi | Privatni ključevi su kritične tajne; backup mora biti šifrovan, kontrolisan i testiran |
/etc/kubernetes/admin.conf | Administratorski kubeconfig | Visoko privilegovan; ne deliti kao korisnički kubeconfig |
/etc/kubernetes/manifests | Static Pod manifesti kontrolne ravni i lokalnog etcd-a | Izmena odmah utiče na kubelet; prvo backup, diff i plan povratka |
/var/lib/etcd | Podaci lokalnog stacked etcd člana | Ne kopirati kao običan „live” direktorijum; koristiti podržan snapshot i recovery postupak |
| Bootstrap token | Privremeni discovery i TLS bootstrap | Kratak TTL, ograničena distribucija, revocation posle upotrebe |
| Certificate key | Dešifrovanje privremeno otpremljenih control plane sertifikata | Posebno osetljiva kratkotrajna tajna; nije isto što i CA hash |
| CA public key hash | Pinovanje identiteta root CA pri token discovery-ju | Nije 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 / ime | Adresa | Uloga | Minimalni laboratorijski budžet |
|---|---|---|---|
k8s-cp01 | 10.20.30.11 | Control plane + stacked single-member etcd | 2 vCPU, 4 GB RAM, 40 GB disk |
k8s-wk01 | 10.20.30.21 | Worker | 2 vCPU, 3 GB RAM, 30 GB disk |
k8s-wk02 | 10.20.30.22 | Worker | 2 vCPU, 3 GB RAM, 30 GB disk |
k8s-api.lab.internal | 10.20.30.11 u ovoj vežbi | Stabilni API identitet | Interni 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.
-
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.
-
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 -lntupTumač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. -
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.yamlU 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.11Rizik: 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.
-
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 pullpuni 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. -
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,
journalctli runtime stanje, utvrditi poslednju završenu fazu i tek zatim izabrati recovery. -
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
NotReadyzbog neinstaliranog CNI-ja. Akocrictlnije konfigurisan za pravi runtime endpoint, prvo se rešava endpoint upozorenje; ne zaključuje se da kontejneri ne postoje. -
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 -wKada 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. -
Kreirati kratkotrajan worker join postupak.
sudo kubeadm token create \ --ttl 30m \ --description "lab workers 2026-07" \ --print-join-commandBezbednost: izlaz se prenosi samo na
k8s-wk01ik8s-wk02odobrenim kanalom. Komanda menja stanje kreiranjem tokena. U dokazima se beleže opis, vreme i kasniji status tokena, ali ne njegova puna vrednost. -
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.
-
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 wideKriterijum: 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. -
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: 8080Manifest 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.
-
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 listNa č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-verificationkao workaround. -
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.
| Simptom | Prvi dokaz | Verovatni uzrok | Bezbedna korekcija |
|---|---|---|---|
| Preflight prijavljuje aktivan swap | swapon --show i kubelet konfiguracija | OS image nije pripremljen ili swap politika nije usklađena | U labu planski isključiti swap; u produkciji primeniti odobrenu, verzijski podržanu politiku |
kubeadm init čeka control plane | journalctl -u kubelet, crictl ps -a, crictl logs | Runtime, cgroup, image, sertifikat, bind adresa ili static Pod crash | Ispraviti dokazani uzrok; ne ignorisati preflight niti ponavljati init naslepo |
| API radi lokalno, worker ne može da se pridruži | DNS i TCP 6443 provera sa workera | Pogrešan DNS, firewall, route ili endpoint | Ispraviti mrežni ugovor ili load balancer; ne menjati token dok mreža nije potvrđena |
| Join prijavljuje nevažeći token | kubeadm token list i vreme na čvorovima | Token je istekao/opozvan ili sat nije tačan | Kreirati novi kratkotrajan token posle potvrde identiteta čvora |
| CA hash se ne poklapa | Autentični hash iz kontrolisanog izvora | Pogrešan klaster, kopiranje ili potencijalni MITM | Zaustaviti join i nezavisno potvrditi endpoint i CA; nikada naslepo preskočiti proveru |
Node postoji ali je NotReady | Node Conditions, Events, CNI Pod i kubelet log | CNI nije instaliran ili ima CIDR/MTU/kernel kvar | Ispraviti CNI uzrok; ponovno init nije rešenje |
CoreDNS ostaje Pending | Pod Events i dostupni čvorovi/taint-i | Nema spremnog schedulable workera ili CNI nije funkcionalan | Osposobiti worker/CNI; ne uklanjati control plane taint bez dizajnerske odluke |
| HA endpoint povremeno ne odgovara | LB backend health, API readyz, etcd quorum | Nezdrav backend, DNS round-robin ili gubitak etcd većine | Izolovati 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
- Projektuj endpoint pre klastera. Stabilno DNS ime, load balancer, backend health i SAN vrednosti pripadaju dizajnu, ne naknadnoj improvizaciji.
- Razdvoji HA API-ja od etcd quorum-a. Dostupan load balancer ne dokazuje konzistentan backend store; obe ravni imaju posebne SLO, metrike i recovery procedure.
- Koristi deklarativni kubeadm API. Konfiguracija prolazi review i verzioniše se; tokeni, privatni ključevi i privilegovani kubeconfig-i ostaju izvan repozitorijuma.
- Pinuj podržanu minor granu i aktuelni patch. Repozitorijum, paketi, slike, CNI i version skew proveravaju se kao jedna kompatibilna celina.
- Ne zaobilazi identitet klastera. CA hash, TLS SAN i kontrolisani DNS sprečavaju da čvor bude pridružen pogrešnom ili lažnom endpointu.
- Tokeni su kratkotrajni. Kreiraju se za konkretan join prozor, prenose bezbedno, evidentiraju i opozivaju kada više nisu potrebni.
- Dokaz pre restarta. Kubelet journal, runtime stanje, static Pod manifesti, događaji i endpoint provere prikupljaju se pre korekcije.
- Ne tretiraj reset kao troubleshooting. Reset služi kontrolisanom uklanjanju kubeadm stanja sa potvrđenog čvora; nije bezazleni pokušaj popravke.
- Dokumentuj ono što kubeadm ne radi. CNI, CSI, ingress, monitoring, backup, DR, OS hardening i load balancer moraju imati vlasnika i lifecycle.
- Testiraj failure domene, ne samo broj VM. Tri control plane procesa na jednom fizičkom hostu nisu produkciona redundansa.
Završna kontrolna tačka
- Možeš precizno da objasniš faze
kubeadm initikubeadm joini granice odgovornosti alata. - Razlikuješ single control plane, HA stacked etcd i HA external etcd topologiju, njihove granice kvara i operativni trošak.
- Razlikuješ stabilni
controlPlaneEndpointod lokalne advertise adrese konkretne API server instance. - Možeš da projektuješ DNS, load balancer, portove, CIDR opsege i SAN vrednosti pre bootstrap-a.
- Proveravaš jedinstvene identitete čvorova, vreme, swap, runtime, cgroup usklađenost, portove i verzije dokazima.
- Pišeš i validiraš
kubeadm.k8s.io/v1beta4konfiguraciju bez čuvanja tajni u repozitorijumu. - Bezbedno pokrećeš prvi control plane, instaliraš odobren CNI i razlikuješ očekivani pre-CNI
NotReadyod bootstrap kvara. - Kreiraš kratkotrajan join token, autentično proveravaš CA hash i pridružuješ workere bez preskakanja TLS identiteta.
- Validiraš Node stanje, sistemske Podove, EndpointSlice, DNS i osnovnu komunikaciju, bez preuveličavanja dometa testa.
- Za init/join kvar povezuješ simptom, vreme, kubelet journal, runtime log, DNS, port, token i sertifikat pre promene stanja.
- Razumeš posledice
kubeadm resetna stacked etcd člana i znaš šta reset ne uklanja. - Možeš da predaš dokaznu arhivu bez tajni, sa verzijama, topologijom, događajima, finalnim stanjem i kontrolnom sumom.
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.