Nemrég bemutattam, hogyan lehet 2 perc alatt létrehozni egy Kubernetes labort.
Most azt fogom bemutatni, hogy hogyan lehet ezt a klasztert tuningolni. A dolog egyetlen hátránya, hogy meglévő KinD fürtön nem lehet mindent alkalmazni, ezért le kell törölnünk a régit (ha kind-demo néven futott):
kind delete cluster --name kind-demo
A másik módszer, hogy új néven hozzuk létre az új fürtöt, de akkor dupla annyi memóriára lesz szükségünk. Mivel ez egy K8s labor, ne legyünk érzelgősek, töröljük a régit 🙂
Az alábbi módosításokat fogom eszközölni az alaptelepítéshez képest:
- nem telepítjük fel a KinD által használt hálózatot
- helyette feltesszük a calico hálózat kezelőt
- telepítjük a metrics-servert, majd rögtön patcheljük is
- létrehozunk egy ‘secure’ nevű névteret, amin be is állítjuk a pod szintű biztonságot
- létrehozunk egy ‘readonly’ felhasználót (mindent lát, semmit se tud módosítani)
- létrehozunk egy ‘dev-admin’ felhasználót, aki csak a ‘dev’ névteret írhatja/olvashatja
- feltelepítjük az istiót, majd rögtön patcheljük is
- a KinD figyelni fog a 80-as és a 443-as tcp portokon is, szóval ha fut webszerverünk ezeken a portokon, előbb le kell állítanunk!
- permanens tárolót is használhatunk
- és végül a zabbix monitoring-hoz szükséges eszközöket (ez opcionális)
Miért van szükség a felsorolt változtatásokra?
- Ha szeretnénk egy olyan K8s labort, ami a lehető legközelebb áll egy kereskedelmi Kuberneteshez, akkor keményítenünk kell a KinD fürtünket. Így fogunk tudni olyan yaml fájlokat tesztelni, amiket akár az Azure-beli AKS-ben is futtathatunk. Jómagam is hónapok óta ezt teszem, gyártom a konténereket, tesztelem a laboromban, majd felteszem az AKS-be.
- Ha szeretnénk, hogy az istió-n keresztül érjük el a konténereinket.
- Ha szeretnénk egyszerű erőforrásmérést végezni.
Mire lesz szükségünk mindehhez?
A szokásos szoftverekre: docker, kind, és új appként kell az ‘istioctl’, amit így kell telepíteni.
A parancsokra és a konfig fájlokra. Ezeket bemásolhatnám, Te pedig kimásolhatnád, de ez mindkettőnknek sok időbe telne 🙂 Ezért inkább feltöltöttem mindent a git repómba.
Azt javaslom, hogy hozz létre egy mappát:
$ mkdir ~/Kind
Majd lépj is bele:
$ cd ~/Kind
Most pedig töltsd le a git repót:
$ git clone https://git.msandor.hu/demo/kind-lab.git
Végezetül lépjünk bele:
$ cd kind-demo
Ezeket a fájlokat fogod látni (a rejtetteket direkt nem mutatom, mert nem relevánsak):
├── 0.deploy-ALL.sh
├── 1.kind-cluster-create.sh
├── 2.0.base.sh
├── 2.5.istio-deploy.sh
├── 3.helm-deploy-zabbix-monitoring.sh
├── apps
│ └── dokuwiki
│ ├── apply.sh
│ ├── delete.sh
│ ├── deployment.yaml
│ ├── istio.yaml
│ ├── pvc.yaml
│ └── service.yaml
├── istio-ingressgateway-patch-nodeport.yaml
├── kind-cluster-delete.sh
├── kind-demo-cluster-config.yaml
├── LICENSE
├── README.md
├── setup-kind-users.sh
├── volume
└── zabbix_values.yaml
Nagyon fontos, hogy a ‘~/Kind/kind-demo/volume’ mappa lesz a fürtön belül a ‘/volume’ mappa alá csatolva. Így, ha olyan konténert futtatsz, aminek meg kell őrizni a fájljait, ez alá teheted, természetesen almappába, hogy más konténer ne lássa. Erről majd később.
Még egy fontos tudnivaló, a kind fürt neve ‘kind-demo’ lesz, ha más nevet szeretnél használni, minden fájlban cserélned kell!
Hozzuk létre a tuningolt fürtöt
A git repóban állva csak egy fájlt kell futtatni:
$ ./0.deploy-ALL.sh
2 perc múlva készen áll a K8s laborunk 🙂
Miért kell patchelni metrics-servert?
Mert enélkül el sem fog indulni, hiszen a fürtünk certjei önaláírtak.
Mire jó a metrics-server?
Méri a cpu és memória fogyasztását a podoknak.
Nézzük meg a zabbix podok fogyasztását:
$ kubectl top pods -n monitoring
NAME CPU(cores) MEMORY(bytes)
zabbix-agent-892h7 1m 5Mi
zabbix-agent-hlqgj 1m 5Mi
zabbix-agent-pk5lb 1m 5Mi
zabbix-kube-state-metrics-8695b59cc8-gjkld 2m 12Mi
zabbix-proxy-5c65ff5f79-k9qpl 5m 43Mi
Ebben az esetben névsor szerint listázza őket.
Nézzük meg az összes pod fogyasztását memória szerint rendezve:
$ kubectl top pods -A --sort-by memory
NAMESPACE NAME CPU(cores) MEMORY(bytes)
kube-system kube-apiserver-kind-demo-control-plane 141m 501Mi
kube-system calico-node-vh6ch 39m 153Mi
kube-system calico-node-zgz9k 36m 150Mi
kube-system calico-node-5dlvp 38m 149Mi
kube-system kube-controller-manager-kind-demo-control-plane 26m 119Mi
kube-system etcd-kind-demo-control-plane 60m 86Mi
kube-system calico-kube-controllers-576865d959-8c4f9 11m 59Mi
kube-system kube-scheduler-kind-demo-control-plane 19m 51Mi
kube-system kube-proxy-l2mv5 1m 49Mi
kube-system kube-proxy-7p8dt 1m 44Mi
kube-system kube-proxy-vssc8 1m 43Mi
monitoring zabbix-proxy-5c65ff5f79-k9qpl 6m 43Mi
istio-system istiod-5cc4ffd9b-ctzjp 3m 30Mi
local-path-storage local-path-provisioner-7dc846544d-kgvjq 1m 29Mi
istio-system istio-ingressgateway-794d965757-nlxt7 3m 25Mi
kube-system metrics-server-56fb9549f4-w56g6 10m 25Mi
kube-system coredns-668d6bf9bc-pxwrq 8m 16Mi
kube-system coredns-668d6bf9bc-7rvgq 5m 16Mi
monitoring zabbix-kube-state-metrics-8695b59cc8-gjkld 2m 12Mi
monitoring zabbix-agent-pk5lb 1m 5Mi
monitoring zabbix-agent-hlqgj 1m 5Mi
monitoring zabbix-agent-892h7 1m 5Mi
Nézzük meg az összes pod fogyasztását cpu szerint rendezve:
$ kubectl top pods -A --sort-by cpu
NAMESPACE NAME CPU(cores) MEMORY(bytes)
kube-system kube-apiserver-kind-demo-control-plane 98m 503Mi
kube-system etcd-kind-demo-control-plane 60m 87Mi
kube-system calico-node-vh6ch 45m 153Mi
kube-system calico-node-5dlvp 44m 149Mi
kube-system calico-node-zgz9k 40m 151Mi
kube-system kube-controller-manager-kind-demo-control-plane 24m 119Mi
kube-system kube-scheduler-kind-demo-control-plane 16m 51Mi
kube-system calico-kube-controllers-576865d959-8c4f9 15m 63Mi
kube-system metrics-server-56fb9549f4-w56g6 8m 25Mi
monitoring zabbix-proxy-5c65ff5f79-k9qpl 6m 43Mi
kube-system coredns-668d6bf9bc-7rvgq 6m 16Mi
kube-system coredns-668d6bf9bc-pxwrq 5m 17Mi
istio-system istio-ingressgateway-794d965757-nlxt7 3m 25Mi
istio-system istiod-5cc4ffd9b-ctzjp 3m 30Mi
monitoring zabbix-kube-state-metrics-8695b59cc8-gjkld 2m 12Mi
kube-system kube-proxy-vssc8 1m 43Mi
kube-system kube-proxy-l2mv5 1m 49Mi
kube-system kube-proxy-7p8dt 1m 44Mi
local-path-storage local-path-provisioner-7dc846544d-kgvjq 1m 29Mi
monitoring zabbix-agent-892h7 1m 5Mi
monitoring zabbix-agent-hlqgj 1m 5Mi
monitoring zabbix-agent-pk5lb 1m 5Mi
A CPU oszlopban látható számok melletti kicsi ‘m’ betű milicpu-t jelent, azaz 1 CPU mag = 1000m. A lista alján látható zabbix-agent podok fejenként egy processzor mag ezred részét használják el ebben a pillanatban. Ami nem túl sok, valljuk be 😉
Miért kell patchelni az istiót?
Ezt nem feltétlen kell, de gyárilag sok erőforrást allokál magának, ami miatt be fog jelezni a zabbix. Ha nálad nincs zabbixba kötve a fürt, vagy bőven van erőforrásod, akkor ezt nem szükséges végrehajtanod. (A 2.5.istio-deploy.sh fájlban kommentezz ki mindent a 9. sortól az utolsóig)
Miért cseréltük le a KinD saját hálózati rétegét Calicóra?
Mert a kindnetd nem támogatja a Network Policy beállításokat. A Calico igen, és talán ez a legnépszerűbb K8s Container Network Interface.
A Network Policy tesztelésére létrehozunk egy ‘secure’ nevű névteret, ha egy podot ebbe szeretnél elindítani, csak abban az esetben fog sikerülni, ha megfelel a szigorú szabályoknak, pl:
- nem futhat rootként a pod-ban lévő appunk
- már a konténer létrehozásakor be kell állítanunk, hogy milyen UID-val fog futni, az nem jó, hogy
"USER appuser"
, ami jó:"USER 12345"
(a szám tetszőleges, csak ne 0 legyen, javasolt 1000 felettit használni) - futás közben nem válthat root felhasználóvá
Mire jó a „readonly” és a „dev-admin” felhasználó? Hiszen full admin vagyok!
Céges környezetben nem biztos, hogy full admin jogaid lesznek. Nálunk az a szabály, hogy a fejlesztőknek nem lehet az éles környezethez hozzáférésük, csak az adminoknak. De ha adsz readonly jogot a fejlesztőknek, akkor legalább láthatják, hogy rendben futnak az alkalmazásaik. Vagy a teszt fürthöz adhatsz a fejlesztőknek admin jogot, de csak egy névtérhez. Így véletlenül sem tudnak kárt tenni a fürtben 🙂
A saját laborodban felesleges magadat szívatnod, de legalább ki tudod próbálni, hogy mi lenne ha…
Mire jó az istió?
Amikor először fogalmazódott meg bennem, hogy jó lenne egy konténert úgy elérnem, hogy nem egy 30478-as (jó magas) porton érem el, hanem rendesen DNS névvel a 80-as vagy a 443-as porton keresztül, akkor rákerestem erre a neten. Az első találat feldobta az ingress-t. Megtanultam, és boldogan használtam egészen addig, amíg közölték velem, hogy a céges AKS-ben istio-t kell használni.
Egy jó kis (angol nyelvű) összefoglaló a két megoldás előnyeiről, hátrányairól.
Összefoglalva: az istió a fürtödben a reverse proxy. Természetesen kezeli a titkosított kapcsolatokat is, szükség esetén Let’s Encrypt certet is létre tud hozni.
Nézzünk egy mindent az egyben példát!
A bemutatáshoz a dokuwiki nevű wiki alkalmazást választottam. Nem titok, ez az egyik kedvencem 😀
Ettől eltekintve, azért is alkalmas demonstrálni, mert nincs szüksége adatbázisra a működéséhez. Csak egy php fordító kell neki a webszerver mellé, ezeket pedig tartalmazza a konténer.
Fontos! A Let’s Encrypt certek automatikus létrehozásához elengedhetetlen feltétel, hogy a fürtöd 80-as portja elérhető legyen az Internet felől, valamint a használni kívánt DNS bejegyzése a laborod külső IP címére mutasson! Otthoni környezetben a routeren is továbbítanod kell a 80/443-as portokat a laborod IP címére.
Ezek a feltételek nem mindenki számára állnak fent, ezért most azt a verziót fogom bemutatni, hogy hogyan próbáld ki ha csak egy munkaállomásod van, és azon fut a KinD laborod.
Fontos! Azon a gépen, ahol a kind-demo fürtöd is fut, vedd fel az /etc/hosts fájlba az alábbi sort:
127.0.0.1 wiki.kind.local
Indítsuk el a dokuwikit
Elvileg bent vagyunk a git repóban (~/Kind/kind-demo
), most lépjünk be a dokuwiki mappájába:
$ cd apps/dokuwiki
Külön raktam a logikailag különböző fájlokat: deployment.yaml istio.yaml pvc.yaml service.yaml.
Abc sorrendben:
- deployment.yaml: ez definiálja a konténert, és a hozzá tartozó változókat, tárolókat
- istio.yaml: ez állítja be a gatewayt és a virtual service-t
- pvc.yaml: ez a permanens mappát állítja be (a klaszter törlése után is megmarad)
- service.yaml: ettől lesz hálózati kapcsolata a konténernek
Szándékosan a "default"
névtérbe tettem mindent, mert ez alapból létrejön a fürt létrehozásakor, és nincs rajta semmilyen korlátozás. Így tudjuk betölteni a yaml fájlokat (azaz elindítani a dokuwikit):
$ kubectl apply -f pvc.yaml -f deployment.yaml -f service.yaml -f istio.yaml
Az egyszerűség kedvéért ugyanezt a parancsot betettem az apply.sh
-ba is.
Kb 40 másodperc múlva próbáld betölteni a böngésződdel a dokuwikit. Ezt kellene látnod:

Adjunk hozzá valamilyen szöveget, ezzel is tesztelve a permanens kötetünket. A jobb oldali ceruza ikonra kattintva válaszd ki a Create this page menüpontot:

A szöveget a bal alsó Save gombbal mentsük el:

Most már így fog kinézni a nyitólap:

Most állítsuk le, majd indítsuk el, vastaggal kiemeltem a parancsokat:
msandor@msandordell:~/Kind/kind-demo/apps/dokuwiki$ kubectl delete -f deployment.yaml -f service.yaml -f pvc.yaml -f istio.yaml
deployment.apps "dokuwiki" deleted
service "dokuwiki" deleted
persistentvolume "dokuwiki-pv" deleted
persistentvolumeclaim "dokuwiki-pvc" deleted
gateway.networking.istio.io "dokuwiki-gw" deleted
virtualservice.networking.istio.io "dokuwiki-vs" deleted
msandor@msandordell:~/Kind/kind-demo/apps/dokuwiki$ kubectl apply -f pvc.yaml -f deployment.yaml -f service.yaml -f istio.yaml
persistentvolume/dokuwiki-pv created
persistentvolumeclaim/dokuwiki-pvc created
deployment.apps/dokuwiki created
service/dokuwiki created
gateway.networking.istio.io/dokuwiki-gw created
virtualservice.networking.istio.io/dokuwiki-vs created
Frissíts rá a dokuwiki weboldalára, ha mindent jól csináltál, ugyanazt a szöveget fogod látni!
Most már tudjuk, hogy fut a dokuwiki, keményítsünk!
Állítsuk le wikit:
$ kubectl delete -f deployment.yaml -f service.yaml -f pvc.yaml -f istio.yaml
Nyisd meg szövegszerkesztővel valamelyik yaml fájlt, majd a default szó összes előfordulását cseréljük le secure-ra. Ezt végezzük el az összes yaml fájllal. Egy kivételével mindegyik a namespace mező lesz:
$ grep default *.yaml
deployment.yaml: namespace: default
istio.yaml: namespace: default
istio.yaml: namespace: default
istio.yaml: host: dokuwiki.default.svc.cluster.local
pvc.yaml: namespace: default
service.yaml: namespace: default
Indítsuk el a dokuwikit:
$ ./apply.sh
persistentvolume/dokuwiki-pv created
persistentvolumeclaim/dokuwiki-pvc created
Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "dokuwiki" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabi
lities (container "dokuwiki" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "dokuwiki" must set securityContext.runAsNonRoot=true), seccompProfi
le (pod or container "dokuwiki" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
deployment.apps/dokuwiki created
service/dokuwiki created
gateway.networking.istio.io/dokuwiki-gw created
virtualservice.networking.istio.io/dokuwiki-vs created
Kiemeltem a problémát, azaz minden erőforrás sikeresen elindult, kivéve a konténerünk. Ha újra és újra elindítjuk, már nem fogja kiírni a hibaüzenetet, de el sem fog indulni.
Mi a megoldás?
Ki kell egészíteni a deployment.yaml fájlt. Az új sorokat kiemeltem:
apiVersion: apps/v1
kind: Deployment
metadata:
name: dokuwiki
namespace: secure
spec:
replicas: 1
selector:
matchLabels:
app: dokuwiki
template:
metadata:
labels:
app: dokuwiki
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: dokuwiki
image: lscr.io/linuxserver/dokuwiki
ports:
- containerPort: 80
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumeMounts:
- mountPath: /config
name: dokuwikidata
volumes:
- name: dokuwikidata
persistentVolumeClaim:
claimName: dokuwiki-pvc
restartPolicy: Always
Most próbáljuk elindítani a wikit:
$ kubectl apply -f pvc.yaml -f deployment.yaml -f service.yaml -f istio.yaml
Most már hibaüzenet nélkül el fog indulni a konténer… vagy mégsem!
Mármint nem lesz hibaüzenet, de nem is fog elindulni a konténerünk, kérjük le a státuszát:
$ kubectl get po -n secure
NAME READY STATUS RESTARTS AGE
dokuwiki-648c478548-mpmsj 0/1 CreateContainerConfigError 0 85s
Ez nem hangzik jól, bővebb infóra lesz szükségünk:
$ kubectl describe pod -n secure $(kubectl get pod -n secure -l app=dokuwiki -o jsonpath="{.items[0].metadata.name}") | grep Error
Reason: CreateContainerConfigError
Warning Failed 3s (x14 over 2m52s) kubelet Error: container has runAsNonRoot and image will run as root (pod: "dokuwiki-648c478548-mpmsj_secure(23a01010-5b0f-49c8-8de7-a06e122afae4)", container: dokuwiki)
Ennek az a magyarázata, hogy sajnálatos módon a konténer készítője nem volt kellően körültekintő, ezért a konténeren belül bizonyos processzek mindenképpen rootként fognak futni. Ezt pedig megakadályozza a secure névtéren alkalmazott keményítés.
Két lehetőségünk van:
- visszaállítsuk a secure névteret default-ra
- keresünk egy olyan konténert, amiben nem rootként fut az app
Én sem ismerek más dokuwiki konténert. Bár készítettem több K8s kompatibilis konténert, de ezek nem publikusak, így el kell hinned nekem, hogy a keményítés ellenére is lehet futtatni konténereket a Kubernetesben…
Ugye nem gondoljátok, hogy üres kézzel fogtok távozni?
Csak itt, csak most, csak nektek csináltam egy egyszerű konténert, benne egy apache webszerverrel, és egy index.html fájllal. Ügyeltem arra, hogy az apache ne rootként fusson 🙂
Ezt is feltöltöttem a git repóba, menj a ~/Kind/kind-demo/apps/apache-demo
mappába. Illetve bővítsük a hosts fájlunkat:
127.0.0.1 wiki.kind.local app.kind.local
Majd indítsuk el:
msandor@msandordell:~/Kind/kind-demo/apps/apache-demo$ ./apply.sh
deployment.apps/apache-demo created
service/apache-demo created
gateway.networking.istio.io/apache-demo-gw created
virtualservice.networking.istio.io/apache-demo-vs created
Ehhez nem kell PV/PVC, mivel nem tárol fájlokat a szerveren. Sokkal gyorsabban el fog indulni, kattints erre a linkre, és már láthatod is a demo oldalt:

És ez valóban a secure névtérben fut, nyugodtan nézzétek meg a deployment.yaml fájlt, ha nem hiszitek el nekem 🙂

Végszó
Kicsit hosszúra sikerült a bemutató, és nem is beszéltem mindenről, ami kimaradt, arról a következő cikkemben fogok értekezni. Akinek nem localhoston fut a kind fürtje, az értelemszerűen a megfelelő IP címmel helyettesítse!
Ha kérdésed van, a lap alján írj kommentet, amint tudok, válaszolni fogok rá!