ProHoster > Dienoraštis > Administravimas > Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)
Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)
Šiais metais pagrindinė Europos Kubernetes konferencija – KubeCon + CloudNativeCon Europe 2020 – buvo virtuali. Tačiau toks formato pakeitimas nesutrukdė mums pristatyti ilgai planuoto pranešimo „Eiti? Bash! Susipažinkite su Shell operatoriumi“, skirta mūsų atvirojo kodo projektui apvalkalo operatorius.
Šiame pokalbio įkvėptame straipsnyje pateikiamas požiūris, kaip supaprastinti „Kubernetes“ operatorių kūrimo procesą, ir parodoma, kaip galite sukurti patys su minimaliomis pastangomis naudodami apvalkalo operatorių.
Pristatome reportažo vaizdo įrašas (~23 min. anglų kalba, pastebimai informatyvesnis nei straipsnis) ir pagrindinė ištrauka iš jo tekstine forma. Pirmyn!
„Flant“ nuolat viską optimizuoja ir automatizuoja. Šiandien mes kalbėsime apie kitą įdomią koncepciją. Susitikti: debesies vietinis apvalkalo scenarijus!
Tačiau pradėkime nuo konteksto, kuriame visa tai vyksta: Kubernetes.
Kubernetes API ir valdikliai
API „Kubernetes“ gali būti pavaizduota kaip failų serveris su kiekvieno tipo objektų katalogais. Objektai (ištekliai) šiame serveryje yra vaizduojami YAML failais. Be to, serveryje yra pagrindinė API, leidžianti atlikti tris dalykus:
gauti išteklius pagal rūšį ir pavadinimą;
keistis resursas (šiuo atveju serveris saugo tik „teisingus“ objektus - visi neteisingai suformuoti ar skirti kitiems katalogams yra atmetami);
takelis ištekliui (šiuo atveju vartotojas iš karto gauna dabartinę / atnaujintą versiją).
Taigi, „Kubernetes“ veikia kaip savotiškas failų serveris (YAML manifestams) su trimis pagrindiniais metodais (taip, iš tikrųjų yra ir kitų, bet kol kas jų praleisime).
Problema ta, kad serveris gali saugoti tik informaciją. Kad tai veiktų, jums reikia kontrolierius - antra pagal svarbą ir pagrindinę koncepciją Kubernetes pasaulyje.
Yra du pagrindiniai valdiklių tipai. Pirmasis paima informaciją iš Kubernetes, apdoroja ją pagal įdėtą logiką ir grąžina į K8s. Antrasis paima informaciją iš Kubernetes, tačiau, skirtingai nei pirmasis, keičia kai kurių išorinių išteklių būseną.
Pažvelkime atidžiau į diegimo „Kubernetes“ kūrimo procesą:
Diegimo valdiklis (įtrauktas į kube-controller-manager) gauna informaciją apie diegimą ir sukuria replikų rinkinį.
Remdamasis šia informacija, „ReplicaSet“ sukuria dvi kopijas (dvi rinkinius), tačiau šios grupės dar nėra suplanuotos.
Planuotojas suplanuoja rinkinius ir prideda mazgų informaciją į savo YAML.
Tada visa ši seka kartojama atvirkštine tvarka: kubeletas patikrina konteinerius, apskaičiuoja ankšties būseną ir siunčia atgal. ReplicaSet valdiklis gauna būseną ir atnaujina kopijų rinkinio būseną. Tas pats atsitinka su diegimo valdikliu ir vartotojas pagaliau gauna atnaujintą (dabartinę) būseną.
Korpuso operatorius
Pasirodo, Kubernetes yra paremtas bendru įvairių valdiklių darbu (Kubernetes operatoriai taip pat yra kontrolieriai). Kyla klausimas, kaip su minimaliomis pastangomis susikurti savo operatorių? Ir čia į pagalbą ateina tas, kurį sukūrėme apvalkalo operatorius. Tai leidžia sistemos administratoriams sukurti savo pareiškimus naudojant pažįstamus metodus.
Paprastas pavyzdys: paslapčių kopijavimas
Pažiūrėkime į paprastą pavyzdį.
Tarkime, kad turime Kubernetes klasterį. Jis turi vardų erdvę default su kažkokia Paslaptimi mysecret. Be to, klasteryje yra ir kitų vardų erdvių. Kai kurie iš jų turi specialią etiketę. Mūsų tikslas yra nukopijuoti Secret į vardų sritis su etikete.
Užduotį apsunkina tai, kad klasteryje gali atsirasti naujų vardų sričių, o kai kurios iš jų gali turėti šią etiketę. Kita vertus, ištrynus etiketę, „Secret“ taip pat turėtų būti ištrintas. Be to, pati Paslaptis taip pat gali pasikeisti: tokiu atveju nauja paslaptis turi būti nukopijuota į visas vardų sritis su etiketėmis. Jei paslaptis netyčia ištrinta bet kurioje vardų srityje, mūsų operatorius turėtų nedelsdamas jį atkurti.
Dabar, kai užduotis suformuluota, laikas pradėti ją įgyvendinti naudojant apvalkalo operatorių. Tačiau pirmiausia verta pasakyti keletą žodžių apie patį apvalkalo operatorių.
Kaip veikia apvalkalo operatorius
Kaip ir kiti „Kubernetes“ darbo krūviai, apvalkalo operatorius veikia atskiroje grupėje. Šiame kataloge /hooks vykdomieji failai yra saugomi. Tai gali būti scenarijai Bash, Python, Ruby ir kt. Tokius vykdomuosius failus vadiname kabliukais (kabliukai).
„Shell-operator“ užsiprenumeruoja „Kubernetes“ įvykius ir paleidžia šiuos „kablius“ reaguodamas į tuos įvykius, kurių mums reikia.
Kaip apvalkalo operatorius žino, kurį kabliuką ir kada paleisti? Esmė ta, kad kiekvienas kabliukas turi du etapus. Paleidimo metu apvalkalo operatorius paleidžia visus kabliukus su argumentu --config Tai yra konfigūracijos etapas. O po jo kabliukai paleidžiami įprastu būdu – reaguojant į įvykius, prie kurių jie yra pritvirtinti. Pastaruoju atveju kabliukas gauna privalomą kontekstą (privalomas kontekstas) – duomenys JSON formatu, apie kuriuos plačiau kalbėsime toliau.
Operatoriaus kūrimas Bash
Dabar esame pasiruošę įgyvendinti. Norėdami tai padaryti, turime parašyti dvi funkcijas (beje, mes rekomenduojame biblioteka shell_lib, kuris labai supaprastina rašymo kabliukus Bash):
pirmasis reikalingas konfigūravimo etapui – rodo įrišimo kontekstą;
antrajame yra pagrindinė kabliuko logika.
#!/bin/bash
source /shell_lib.sh
function __config__() {
cat << EOF
configVersion: v1
# BINDING CONFIGURATION
EOF
}
function __main__() {
# THE LOGIC
}
hook::run "$@"
Kitas žingsnis – nuspręsti, kokių objektų mums reikia. Mūsų atveju turime sekti:
pakeitimų šaltinio paslaptis;
visos klasterio vardų erdvės, kad žinotumėte, kurios iš jų turi etiketę;
tikslinės paslaptys, kad užtikrintumėte, jog jos visos yra sinchronizuojamos su šaltinio paslaptimi.
Prenumeruokite slaptą šaltinį
Įrišimo konfigūracija yra gana paprasta. Pavadinimu nurodome, kad mus domina Secret mysecret vardų erdvėje default:
Kaip matote, konfigūracijoje atsirado naujas laukas su pavadinimu jqFilter. Kaip rodo jo pavadinimas, jqFilter išfiltruoja visą nereikalingą informaciją ir sukuria naują JSON objektą su mus dominančiais laukais. Panašios konfigūracijos kabliukas gaus tokį įrišimo kontekstą:
Jame yra masyvas filterResults kiekvienai klasterio vardų erdvei. Būlio kintamasis hasLabel nurodo, ar etiketė yra pridėta prie nurodytos vardų srities. Rinkiklis keepFullObjectsInMemory: false rodo, kad nereikia laikyti pilnų objektų atmintyje.
Taikinio paslapčių sekimas
Prenumeruojame visas Paslaptis, kuriose nurodyta anotacija managed-secret: "yes" (tai yra mūsų tikslas dst_secrets):
Šiuo atveju jqFilter išfiltruoja visą informaciją, išskyrus vardų erdvę ir parametrą resourceVersion. Kuriant paslaptį anotacijai buvo perduotas paskutinis parametras: jis leidžia palyginti paslapčių versijas ir jas atnaujinti.
Taip sukonfigūruotas kabliukas, kai jis bus vykdomas, gaus tris aukščiau aprašytus susiejimo kontekstus. Jie gali būti laikomi savotišku momentiniu vaizdu (momentinė nuotrauka) klasteris.
Remiantis visa ši informacija, galima sukurti pagrindinį algoritmą. Jis kartojasi visose vardų erdvėse ir:
jei hasLabel klausimai true dabartinei vardų erdvei:
lygina pasaulinę paslaptį su vietine:
jei jie yra vienodi, tai nieko nedaro;
jei skiriasi – vykdo kubectl replace arba create;
jei hasLabel klausimai false dabartinei vardų erdvei:
užtikrina, kad Secret nėra nurodytoje vardų erdvėje:
jei yra vietinė paslaptis, ištrinkite ją naudodami kubectl delete;
jei vietinė paslaptis neaptinkama, ji nieko nedaro.
Taip mums pavyko sukurti paprastą „Kubernetes“ valdiklį naudodami 35 YAML konfigūracijos eilutes ir maždaug tiek pat „Bash“ kodo! Korpuso operatoriaus darbas yra juos sujungti.
Tačiau paslapčių kopijavimas nėra vienintelė programos taikymo sritis. Štai dar keli pavyzdžiai, rodantys, ką jis sugeba.
1 pavyzdys: „ConfigMap“ keitimas
Pažvelkime į diegimą, kurį sudaro trys blokai. Pods naudoja ConfigMap tam tikrai konfigūracijai išsaugoti. Kai buvo paleisti ankšties, ConfigMap buvo tam tikros būsenos (vadinkime tai v.1). Atitinkamai, visos ankštys naudoja šią konkrečią „ConfigMap“ versiją.
Dabar tarkime, kad ConfigMap pasikeitė (v.2). Tačiau ankštyse bus naudojama ankstesnė ConfigMap versija (v.1):
Kaip priversti juos persijungti į naują ConfigMap (v.2)? Atsakymas paprastas: naudokite šabloną. Prie skyriaus pridėkime kontrolinės sumos anotaciją template Diegimo konfigūracijos:
Dėl to ši kontrolinė suma bus užregistruota visose grupėse ir bus tokia pati kaip diegimo. Dabar jums tereikia atnaujinti anotaciją, kai pasikeičia ConfigMap. O apvalkalo operatorius šiuo atveju praverčia. Viskas, ką jums reikia padaryti, tai programuoti kabliukas, kuris užsiprenumeruos ConfigMap ir atnaujins kontrolinę sumą.
Jei vartotojas atlieka pakeitimus ConfigMap, apvalkalo operatorius juos pastebės ir perskaičiuos kontrolinę sumą. Po to įsijungs Kubernetes magija: orkestrantas užmuš ankštį, sukurs naują, lauks, kol ji taps Ready, ir pereina prie kito. Dėl to diegimas bus sinchronizuojamas ir persijungs į naują ConfigMap versiją.
2 pavyzdys: darbas su pasirinktiniais išteklių apibrėžimais
Kaip žinote, Kubernetes leidžia kurti pasirinktinius objektų tipus. Pavyzdžiui, galite sukurti malonų MysqlDatabase. Tarkime, kad šis tipas turi du metaduomenų parametrus: name и namespace.
apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
name: foo
namespace: bar
Turime Kubernetes klasterį su skirtingomis vardų erdvėmis, kuriose galime kurti MySQL duomenų bazes. Šiuo atveju ištekliams sekti gali būti naudojamas apvalkalo operatorius MysqlDatabase, prijungdamas juos prie MySQL serverio ir sinchronizuodamas norimas ir stebimas klasterio būsenas.
3 pavyzdys: klasterio tinklo stebėjimas
Kaip žinote, ping yra paprasčiausias būdas stebėti tinklą. Šiame pavyzdyje parodysime, kaip tokį stebėjimą įgyvendinti naudojant apvalkalo operatorių.
Visų pirma, turėsite užsiprenumeruoti mazgus. Apvalkalo operatoriui reikia kiekvieno mazgo pavadinimo ir IP adreso. Su jų pagalba jis sujungs šiuos mazgus.
Parametras executeHookOnEvent: [] neleidžia paleisti kabliuko reaguojant į bet kokį įvykį (ty reaguojant į mazgų keitimą, pridėjimą, ištrynimą). Tačiau jis bėgs (ir atnaujinkite mazgų sąrašą) Suplanuota - kiekvieną minutę, kaip nurodyta lauke schedule.
Dabar kyla klausimas, kaip tiksliai žinoti apie tokias problemas kaip paketų praradimas? Pažvelkime į kodą:
function __main__() {
for i in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do
node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')"
node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')"
packets_lost=0
if ! ping -c 1 "$node_ip" -t 1 ; then
packets_lost=1
fi
cat >> "$METRICS_PATH" <<END
{
"name": "node_packets_lost",
"add": $packets_lost,
"labels": {
"node": "$node_name"
}
}
END
done
}
Mes kartojame mazgų sąrašą, gauname jų pavadinimus ir IP adresus, siunčiame juos ping ir siunčiame rezultatus „Prometheus“. Shell operatorius gali eksportuoti metrikas į Prometheus, išsaugodami juos į failą, esantį pagal aplinkos kintamajame nurodytą kelią $METRICS_PATH.
Čia taip galite sukurti operatorių paprastam tinklo stebėjimui klasteryje.
Eilių mechanizmas
Šis straipsnis būtų neišsamus, jei neaprašytume kito svarbaus mechanizmo, įtaisyto apvalkalo operatoriuje. Įsivaizduokite, kad jis vykdo tam tikrą kabliuką, reaguodamas į įvykį klasteryje.
Kas atsitiks, jei tuo pačiu metu kažkas atsitiks klasteryje? dar vieną renginys?
Ar apvalkalo operatorius paleis kitą kabliuko egzempliorių?
Ką daryti, jei, tarkime, vienu metu klasteryje įvyksta penki įvykiai?
Ar apvalkalo operatorius juos apdoros lygiagrečiai?
Ką apie sunaudotus išteklius, tokius kaip atmintis ir procesorius?
Laimei, apvalkalo operatorius turi įmontuotą eilių mechanizmą. Visi įvykiai yra eilėje ir apdorojami nuosekliai.
Iliustruojame tai pavyzdžiais. Tarkime, kad turime du kabliukus. Pirmasis įvykis patenka į pirmąjį kabliuką. Kai jo apdorojimas bus baigtas, eilė juda į priekį. Kiti trys įvykiai nukreipiami į antrąjį kabliuką - jie pašalinami iš eilės ir įtraukiami į ją „ryšulyje“. Tai yra kabliukas gauna daugybę įvykių — arba, tiksliau, įpareigojančių kontekstų masyvas.
Taip pat šios renginius galima sujungti į vieną didelį. Už tai atsakingas parametras group įrišimo konfigūracijoje.
Galite sukurti bet kokį eilių / kabliukų skaičių ir įvairius jų derinius. Pavyzdžiui, viena eilė gali veikti su dviem kabliukais arba atvirkščiai.
Viskas, ką jums reikia padaryti, tai atitinkamai sukonfigūruoti lauką queue įrišimo konfigūracijoje. Jei eilės pavadinimas nenurodytas, kabliukas veikia pagal numatytąją eilę (default). Šis eilių mechanizmas leidžia visiškai išspręsti visas resursų valdymo problemas dirbant su kabliukais.
išvada
Paaiškinome, kas yra apvalkalo operatorius, parodėme, kaip su juo galima greitai ir be vargo sukurti Kubernetes operatorius, pateikėme kelis jo panaudojimo pavyzdžius.
Išsamią informaciją apie apvalkalo operatorių, taip pat trumpą pamoką, kaip jį naudoti, rasite atitinkamame „GitHub“ saugyklos. Nedvejodami susisiekite su mumis iškilusiais klausimais: juos galite aptarti specialioje Telegramų grupė (rusų kalba) arba k šis forumas (angliškai).
O jei patiko, visada džiaugiamės matydami naujus leidinius/PR/žvaigždes GitHube, kur, beje, galite rasti ir kitų įdomių projektų. Tarp jų verta pabrėžti priedų operatorius, kuris yra didysis apvalkalo operatoriaus brolis. Ši programa naudoja „Helm“ diagramas priedams įdiegti, gali teikti naujinimus ir stebėti įvairius diagramos parametrus / reikšmes, kontroliuoja diagramų diegimo procesą ir taip pat gali jas modifikuoti reaguodama į klasterio įvykius.