Kaip paaiškėjo pusės dienos darbo klasterio diegimui nepakako. O esamų programų migravimui ir pritaikymui normaliam „Kubernetes“ klasteriui prireikė daugiau, nei savaitės ir šis procesas tebevyksta, nes savaitgaliais ir šiaip ką veikti, o po darbo to laiko lieka ne taip jau ir daug. Taigi apie viską iš eilės. Pirmiausia apie „Kubernetes“ diegimą, nes serverių būsena "Ready" dar nereiškia, kad jis tikrai paruoštas darbui.

Pirmiausia teko susidurti su keliomis Linux sistemos klaidomis ir programinės įrangos nesuderinamumais. Įdiegęs „Kubernetes“, savaime suprantama norėjau turėti galimybę matyti klasterio apkrovą ir išteklių sąnaudas. Tam reikėjo įdieti „Kubernetes“ Metrics“ tarnybą, tačiau paaiškėjo kad paprastos diegimo instrukcijos, pateiktos https://github.com/„Kubernetes“-sigs/metrics-server/ puslapyje nėra pakankamos. Reikėjo papildomų veiksmų, leidžiančių normaliai išnaudoti TLS šifravimą. O besiaiškinant, kodėl „Kubernetes“ neveikė išteklių naudojimo tarnyba, paaiškėjo, kad turima „Cillium“ tinko tarnyba nėra suderinama su „Ubuntu 22.04“.

Taigi įdiegus „Metrics“ tarnybą, paaiškėjo, kad jokių išteklių sanaudų duomenų ji nerenka, programos ataskaitose buvo matomos TCP tinklo ryšio klaidos.

Metrics server error:
panic: unable to load configmap based request-header-client-ca-file: Get "https://10.96.0.1:443/api/v1/namespaces/kube-system/configmaps/extension-apiserver-authentication": dial tcp 10.96.0.1:443: i/o timeout

Tokios klaidos buvo keistos, nes mano atveju 10.96.0.1 yra „Kubernetes“ pagrindinės klasterio sisteminės tarnybos adresas, mat „kubeadm“ klasterio tarnybų adresams naudoja 10.96.0.0/16 potinklį. Pats klasteris atrodė visiškai veiksnus, nes galėjau naudotis pirmajame klasterio serveryje (vm-serv) paleistų programų teikiamomis paslaugomis ir paleisti konteinerius naujuose serveriuose. Taigi pradėjau kapstyti giliau. Pasirodo, „Kubernetes“ API tarnyba buvo nepasiekiama iš „Kubernetes“ konteinerių, paleistų naujuose klasterio serveriuose. Tačiau ryšys neveikė tik pačiuose konteineriuose.

Bandant pasiekti API adresą pačioje serverio OS, duodavo visiškai teisingą atsakymą į tokią užklausą:

root@k8s3:~# curl -k https://10.96.0.1:443
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {},
  "code": 403
}

Tuo tarpu paleidus užklausą iš konteinerio aplinkos ryšio užmegzti nepavykdavo:

tmp-shell  ~  curl -k http://10.96.0.1:443
curl: (28) Failed to connect to 10.96.0.1 port 443 after 130963 ms: Couldn't connect to server

Šis skirtumas rodė, kad problema slypi kažkur Kubernetes tinklo posistemyje, o mano klasteryje pastarąjį valdo „Cilium“ tarnyba. Pradėjus ieškoti, gan greitai pavyko aptikti užuominų, kad kai kurios senos „Cilium“ versijos yra nesuderinamos su naujomis „Ubuntu“ versijomis. Kadangi „Kubernetes“ naudojuosi jau daugiau, nei 700 dienų, tai „Cilium“ tarnybos versija taip ir liko ta pati 1.9.5, kokia buvo įdiegus, nes naujinant „Kubernetes“, „kubeadm“ paliko „Cilium“ nuošalėje.

Plačiau apie tai galima pasiskaityti šiuose pranešimuose apie „Cilium“ ir „Kubespray“ veikimo trikdžius:
https://github.com/cilium/cilium/issues/20125
https://github.com/cilium/cilium/pull/20072
https://github.com/kubernetes-sigs/kubespray/issues/9039

Atnaujinus „Cilium“, ryšio problemos dingo. Tuomet teko imtis „Metrics“ tarnybos neveikimo. Po ilgo naršymo ir dokumentacijos skaitymo, po akimis pakliuvo šis puslapis, kuriame buvo paminėta viena nuostata, apie kurią nėra gausiai pasakojama oficialiame „Metrics“ puslapyje.

Kadangi diegdamas naują „Kubernetes“ klasterį prieš du metus nediegiau, nei „Metric“ tarnybos ir neskyriau daug dėmėsio TLS sertifikatų generavimui, tai pro akis praslydo serverTLSBootstrap: true nuostata. Ji turėjo būti nurodoma pirminėje „kubeadm“ diegimo konfigūracijoje, o jei to nebuvo padaryta, tai ją reikėjo įkelti į kiekvieno serverio „Kubelet“ konfigūracijos failą /var/lib/kubelet/config.yaml, o taip pat į kubelet-config ConfigMap konfigūracijos objektą, esantį kube-system vardų erdvėje (namespace). Perkrovus „Kubelet“ procesus, „Metrics“ tarnyba pagaliau pradėjo veikti ir jau galima vertinti klasterio apkrovą.

bacila@juodas ~/Documents/K8s/ $ kubectl top nodes
NAME      CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s1      1316m        16%    2971Mi          38%
k8s2      252m         3%     2965Mi          38%
k8s3      118m         1%     2504Mi          32%
vm-serv   784m         19%    4664Mi          29%

Susitvarkius su tarnybomis, atėjo laikas imtis klasteryje veikiančių programų, kurios nėra pilnai pritaikytos veikti „Kubernetes“ aplinkoje, nes jos buvo migruotos iš „Docker Compose“. Esminis skirtumas tarp šių aplinkų yra tas, kad „Docker Compose“ veikia viename serveryje, o „Kubernetes“ yra skirta veikti serverių klasteryje. Dėl šio skirtumo „Docker Compose“ įprastas duomenų tomo aprašas, nurodantis serverio failų sistemos kelią nėra tinkamas „Kubernetes“ aplinkai, nes toks tomas gali veikti tik tame konkrečiame serveryje, kur yra saugomi duomenų tomo failai. Problemai spręsti reikalinga tarnyba, galinti kompiuteriniu tinklu programoms pateikti prieigą prie reikiamų failų arba kitaip tariant NAS (Network Attached Storage).

Atmetus paskirstytąsias sistemas, tokias, kaip „Ceph“, „GlusterFS“ ar „LongHorn“ bei specializuotų duomenų saugykloms skirtus sprendimus lieka 3 populiariausi būdai, kaip pateikti duomenis tinklu iš centralizuoto serverio: CIFS/SMBFS, NFS ir iSCSI. „Windows“ aplinkoms įprastu CIFS/SMBFS protokolu veikianti SMB FlexVolume tarnyba yra pripažinta pasenusia („deprecated“) nuo „Kubernetes“ versijos v1.21. Blokų lygmenyje veikiantis iSCSI yra labai efektyvus ir našus būdas pateikti duomenis, tačiau tam reikėtų sukurti naujus tuščius LVM tomus, juos prijungti prie Kubernetes tarnybų, tuomet kažkaip perkelti duomenis iš dabartinės serverio failinės sistemos. Kitaip tariant daug darbo ir neturint papildomų diskų nėra įmanoma, nes serveryje nebėra vietos sukurti naują tuščią tomą, kuriame tilptų visa filmoteka ir muzikos archyvas. Taigi liko tik laiko patikrinta NFS tarnyba.

Pirmasis bandymas naudoti vartotojo lygmens „NFS Ganesha“ baigėsi fiasko, nes projekto puslapyje dokumentacijos kiekis yra atvirkščiai proporcingas nuostatų gausai. Nors pačią tarnybą pavyko įdiegti ir šiaip ne taip paleisti, tačiau prisijungti prie tinklu viešinamos failinės sistemos taip ir nepavyko. Kiek pavyko išmąstyti iš gaunamų klaidų, nepavyko sukonfigūruoti vartotojo ID transliavimo tarp kliento ir serverio. Po poros dienų žaidimo - spjoviau ir panaudojau laiko patikrintą branduolio lygmens NFS tarnybą, kuri suveikė iš pirmo karto. Pakako tik aprašyti viešinamas failinės sistemos dalis /etc/exports faile ir paleisti „exportfs -a“.

/K8S/NFS_VOL  192.168.4.0/24(rw,sync,no_subtree_check,no_root_squash)
/MEDIA  192.168.4.0/24(rw,sync,no_subtree_check,no_root_squash)
/FREENET 192.168.4.0/24(rw,sync,no_subtree_check,no_root_squash)

Pasiekti šias failines sistemas į „Kubernetes“ reikėjo įdiegti NFS CSI modulį (https://github.com/kubernetes-csi/csi-driver-nfs). Su jo įdiegimu jokių keblumų nekilo ir pakako aprašyti atitinkamas duomenų saugyklų klases, kurios jungtųsi prie mano NFS serverio.

$ kubectl  get sc
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  49d
nfs                    nfs.csi.k8s.io          Delete          Immediate              false                  30d
nfs-freenet            nfs.csi.k8s.io          Delete          Immediate              false                  4d4h
nfs-media              nfs.csi.k8s.io          Delete          Immediate              false                  4d4h

Tiesa, galvoju, kad nfs-freenet ir nfs-media saugyklų klases reikės perkurti ir dėl visa ko pakeisti duomenų išsaugojimo taisykles iš „Delete“ į „Retain“. Paprastai duomenų saugyklos klasėse naudojama „Delete“ nuostata, kuri nurodo, kad baigus naudotis „Kubernetes“ duomenų tomu ir ištrynus „PersistentVolume“ objektą, su juo susieti duomenys turėtų būti ištrinami iš saugyklos. Tai yra patogu, nes nereikia rūpinis senų nereikalingų failų/blokinių įrenginių šalinimu, nes tai vyksta automatiškai.

Bet patogu tik iki tol, kol nepabandoma „Kubernetes“ programai pateikti jau esamų duomenų. Tai padaryti labai paprasta, pakanka „PersistentVolume“ duomenų tomo apraše nurodyti konkretų failų sistemos kelią iki duomenų. To nepadarius, NFS CSI modulis sukurs atsitiktinį katalogą viešinamos NFS failų sistemos šaknyje, kur saugos programos sukurtus duomenis. Taigi „Plex“ mediatekos tarnybai aprašiau tokį duomenų tomą, kuris prieis prie /MEDIA katalogo, kur yra saugomas fotoarchyvas, videoteka, muzikos archyvas, programinės įrangos rinkinys ir t.t. Tinklo kompiuteriams šis turinys yra pasiekiamas SMB protokolu.

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: plex-data
spec:
  storageClassName: nfs-media
  persistentVolumeReclaimPolicy: Retain
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /MEDIA/
    server: 192.168.4.250
  mountOptions:
    - vers=4
    - minorversion=1

Taigi o dabar įsivaizduojam situaciją. Kuriant šį tomą netyčia pamiršta nurodyti persistentVolumeReclaimPolicy: Retain ir aprašas panaudoja duomenų saugyklos klasės nuostatą persistentVolumeReclaimPolicy: Delete. Nusprendus perinstaliuoti „Plex“ mediatekos programą ir trinant duomenų tomo objektą, NFS CSI gali nuspręsti, kad /MEDIA katalogas ir jo turinys taip pat yra nebereikalingas. Nors NFS tarnyba to ir nepadaro (tikrinau kelis kartus), tačiau rizikuoti visu serverio turiniu nesu linkęs.