ProHoster > Blogi > Haldamine > Kas minna? Bash! Tutvuge shell-operaatoriga (KubeCon EU'2020 ülevaade ja videoaruanne)
Kas minna? Bash! Tutvuge shell-operaatoriga (KubeCon EU'2020 ülevaade ja videoaruanne)
Sel aastal oli Euroopa peamine Kubernetese konverents – KubeCon + CloudNativeCon Europe 2020 – virtuaalne. Selline formaadimuutus ei takistanud meil aga esitamast meie kaua planeeritud aruannet „Mine? Bash! Tutvuge Shelli operaatoriga”, mis on pühendatud meie avatud lähtekoodiga projektile kesta operaator.
See kõnest inspireeritud artikkel tutvustab lähenemisviisi Kubernetese operaatorite loomise protsessi lihtsustamiseks ja näitab, kuidas saate shell-operaatori abil minimaalse vaevaga ise luua.
Tutvustame video raportist (~23 minutit inglise keeles, märgatavalt informatiivsem kui artikkel) ja põhiväljavõte sellest teksti kujul. Mine!
Flantis optimeerime ja automatiseerime pidevalt kõike. Täna räägime veel ühest põnevast kontseptsioonist. Tutvuge: pilvepõhise kesta skriptimine!
Alustame aga kontekstist, milles see kõik toimub: Kubernetes.
Kubernetes API ja kontrollerid
Kubernetese API-d saab kujutada omamoodi failiserverina, kus on kataloogid igat tüüpi objektide jaoks. Selle serveri objekte (ressursse) esindavad YAML-failid. Lisaks on serveril põhiline API, mis võimaldab teha kolme asja:
saada ressurss liigi ja nime järgi;
muutus ressurss (sel juhul salvestab server ainult “õigeid” objekte - kõik valesti moodustatud või muude kataloogide jaoks mõeldud objektid visatakse kõrvale);
järgi ressursi jaoks (sel juhul saab kasutaja kohe selle praeguse/uuendatud versiooni).
Seega toimib Kubernetes omamoodi failiserverina (YAML-i manifestide jaoks) kolme põhimeetodiga (jah, tegelikult on ka teisi, kuid jätame need praegu välja).
Probleem on selles, et server saab salvestada ainult teavet. Et see toimiks, on vaja kontroller - tähtsuselt ja fundamentaalsemalt teine kontseptsioon Kubernetese maailmas.
Kontrollereid on kahte peamist tüüpi. Esimene võtab Kubernetesist teabe, töötleb seda vastavalt pesastatud loogikale ja tagastab selle K8-le. Teine võtab teavet Kubernetesist, kuid erinevalt esimesest tüübist muudab mõne välise ressursi olekut.
Vaatame lähemalt Kubernetes juurutamise loomise protsessi:
Juurutuskontroller (sisaldub komplektis kube-controller-manager) saab teavet juurutamise kohta ja loob replicaSeti.
ReplicaSet loob selle teabe põhjal kaks koopiat (kaks kausta), kuid need pole veel ajastatud.
Planeerija ajastab kaustasid ja lisab nende YAML-idele sõlmeteabe.
Kubeletid teevad muudatusi välises ressursis (näiteks Docker).
Seejärel korratakse kogu seda jada vastupidises järjekorras: kubelet kontrollib konteinereid, arvutab kauna oleku ja saadab selle tagasi. ReplicaSeti kontroller võtab vastu koopiakomplekti oleku ja värskendab selle olekut. Sama juhtub juurutamise kontrolleriga ja kasutaja saab lõpuks värskendatud (praeguse) oleku.
Shell-operaator
Selgub, et Kubernetes põhineb erinevate kontrollerite ühistööl (kubernetese operaatorid on ka kontrollerid). Tekib küsimus, kuidas luua oma operaator minimaalse vaevaga? Ja siin tuleb appi see, mille me välja arendasime kesta operaator. See võimaldab süsteemiadministraatoritel luua tuttavaid meetodeid kasutades oma avaldusi.
Lihtne näide: saladuste kopeerimine
Vaatame lihtsat näidet.
Oletame, et meil on Kubernetese klaster. Sellel on nimeruum default mõne saladusega mysecret. Lisaks on klastris ka teisi nimeruume. Mõnel neist on küljes konkreetne silt. Meie eesmärk on kopeerida Secret sildiga nimeruumidesse.
Ülesande teeb keeruliseks asjaolu, et klastris võivad ilmuda uued nimeruumid ja mõnel neist võib olla see silt. Teisest küljest tuleks sildi kustutamisel kustutada ka Secret. Lisaks sellele võib muutuda ka saladus ise: sel juhul tuleb uus Secret kopeerida kõikidesse siltidega nimeruumidesse. Kui saladus mis tahes nimeruumist kogemata kustutatakse, peaks meie operaator selle viivitamatult taastama.
Nüüd, kui ülesanne on sõnastatud, on aeg alustada selle rakendamist shell-operaatori abil. Kuid kõigepealt tasub öelda paar sõna shell-operaatori enda kohta.
Kuidas shell-operaator töötab
Sarnaselt muudele Kubernetese töökoormustele töötab shell-operaator oma kaustas. Selles kataloogis olevas kaustas /hooks käivitatavad failid salvestatakse. Need võivad olla Bashi, Pythoni, Ruby jne skriptid. Me nimetame selliseid käivitatavaid faile konksudeks (konksud).
Shell-operator tellib Kubernetese sündmused ja käivitab need konksud vastuseks neile sündmustele, mida vajame.
Kuidas kooreoperaator teab, millist konksu ja millal juhtida? Asi on selles, et igal konksul on kaks etappi. Käivitamise ajal käivitab shell-operaator kõik konksud argumendiga --config See on seadistamise etapp. Ja pärast seda käivitatakse konksud tavapärasel viisil - vastuseks sündmustele, millega need on seotud. Viimasel juhul saab konks siduva konteksti (siduv kontekst) - andmed JSON-vormingus, millest räägime allpool üksikasjalikumalt.
Operaatori tegemine Bashis
Nüüd oleme rakendamiseks valmis. Selleks peame kirjutama kaks funktsiooni (muide, soovitame raamatukogu shell_lib, mis lihtsustab oluliselt Bashis konksude kirjutamist):
esimest on vaja konfiguratsioonietapi jaoks – see kuvab sidumiskonteksti;
teine sisaldab konksu põhiloogikat.
#!/bin/bash
source /shell_lib.sh
function __config__() {
cat << EOF
configVersion: v1
# BINDING CONFIGURATION
EOF
}
function __main__() {
# THE LOGIC
}
hook::run "$@"
Järgmine samm on otsustada, milliseid objekte me vajame. Meie puhul peame jälgima:
muudatuste lähtesaladus;
kõik klastri nimeruumid, et saaksite teada, millistele on lisatud silt;
sihtsaladused, et tagada nende kõigi sünkroonis lähtesaladusega.
Telli salajane allikas
Selle sidumise konfiguratsioon on üsna lihtne. Anname nimega märku, et oleme huvitatud saladusest mysecret nimeruumis default:
Nagu näete, on konfiguratsioonis ilmunud uus väli nimega jqFilter. Nagu nimigi ütleb, jqFilter filtreerib välja kogu ebavajaliku teabe ja loob meile huvipakkuvate väljadega uue JSON-objekti. Sarnase konfiguratsiooniga konks saab järgmise sidumiskonteksti:
See sisaldab massiivi filterResults iga klastri nimeruumi jaoks. Boole'i muutuja hasLabel näitab, kas antud nimeruumile on lisatud silt. Valija keepFullObjectsInMemory: false näitab, et täielikke objekte pole vaja mälus hoida.
Sihtmärgi saladuste jälgimine
Tellime kõik saladused, millel on täpsustatud annotatsioon managed-secret: "yes" (need on meie sihtmärk dst_secrets):
Sel juhul jqFilter filtreerib välja kogu teabe, välja arvatud nimeruum ja parameeter resourceVersion. Viimane parameeter edastati annotatsioonile saladuse loomisel: see võimaldab võrrelda saladuste versioone ja hoida neid ajakohasena.
Sel viisil konfigureeritud konks saab käivitamisel kolm ülalkirjeldatud sidumiskonteksti. Neid võib pidada omamoodi hetktõmmisteks (snapshot) klaster.
Kogu selle teabe põhjal saab välja töötada põhialgoritmi. See kordub kõigis nimeruumides ja:
kui hasLabel küsimustes true praeguse nimeruumi jaoks:
võrdleb globaalset saladust kohalikuga:
kui need on samad, ei tee see midagi;
kui need erinevad - teostab kubectl replace või create;
kui hasLabel küsimustes false praeguse nimeruumi jaoks:
veendub, et Secret pole antud nimeruumis:
kui kohalik saladus on olemas, kustutage see kasutades kubectl delete;
kui kohalikku saladust ei tuvastata, ei tee see midagi.
Nii saime luua lihtsa Kubernetese kontrolleri, kasutades 35 rida YAML-i konfiguratsiooni ja umbes sama palju Bashi koodi! Shell-operaatori ülesanne on need omavahel siduda.
Saladuste kopeerimine pole aga utiliidi ainus rakendusvaldkond. Siin on veel mõned näited, et näidata, milleks ta võimeline on.
Näide 1: ConfigMapi muudatuste tegemine
Vaatame kolmest kaustast koosnevat juurutust. Podid kasutavad teatud konfiguratsiooni salvestamiseks ConfigMapi. Kui kaustad käivitati, oli ConfigMap teatud olekus (nimetagem seda v.1). Sellest lähtuvalt kasutavad kõik kaustad seda konkreetset ConfigMapi versiooni.
Oletame nüüd, et ConfigMap on muutunud (v.2). Siiski kasutavad kaustad ConfigMapi eelmist versiooni (v.1):
Kuidas saada neid uuele ConfigMapile (v.2) lülituma? Vastus on lihtne: kasutage malli. Lisame jaotisele kontrollsumma märkuse template Juurutamise konfiguratsioonid:
Selle tulemusel registreeritakse see kontrollsumma kõigis kaustades ja see on sama, mis juurutamise puhul. Nüüd peate lihtsalt annotatsiooni värskendama, kui ConfigMap muutub. Ja shell-operaator tuleb sel juhul kasuks. Kõik, mida pead tegema, on programmeerida konks, mis tellib ConfigMapi ja värskendab kontrollsummat.
Kui kasutaja teeb ConfigMapis muudatusi, märkab shell-operaator neid ja arvutab kontrollsumma uuesti. Pärast seda hakkab mängu Kubernetese maagia: orkestraator tapab kauna, loob uue, ootab, kuni see muutub. Readyja liigub järgmise juurde. Selle tulemusena sünkroonib juurutamine ja lülitub ConfigMapi uuele versioonile.
Näide 2: Kohandatud ressursimääratlustega töötamine
Nagu teate, võimaldab Kubernetes luua kohandatud tüüpi objekte. Näiteks saate luua lahke MysqlDatabase. Oletame, et sellel tüübil on kaks metaandmete parameetrit: name и namespace.
apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
name: foo
namespace: bar
Meil on erinevate nimeruumidega Kubernetese klaster, milles saame luua MySQL-i andmebaase. Sel juhul saab ressursside jälgimiseks kasutada shell-operaatorit MysqlDatabase, ühendades need MySQL-serveriga ja sünkroonides klastri soovitud ja vaadeldud olekuid.
Näide 3: klastri võrgu jälgimine
Nagu teate, on pingi kasutamine kõige lihtsam viis võrgu jälgimiseks. Selles näites näitame, kuidas sellist jälgimist shell-operaatori abil rakendada.
Kõigepealt peate tellima sõlmed. Shelli operaator vajab iga sõlme nime ja IP-aadressi. Nende abiga pingib ta need sõlmed.
Parameeter executeHookOnEvent: [] takistab konksu käivitamist vastuseks mis tahes sündmusele (st vastuseks sõlmede muutmisele, lisamisele, kustutamisele). Siiski ta hakkab jooksma (ja värskendage sõlmede loendit) Planeeritud - iga minut, nagu väljal ette nähtud schedule.
Nüüd tekib küsimus, kuidas me täpselt teame sellistest probleemidest nagu pakettakad? Vaatame koodi:
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
}
Kordame sõlmede loendit, hankime nende nimed ja IP-aadressid, pingime need ja saadame tulemused Prometheusele. Shell-operaator saab eksportida mõõdikuid Prometheusesse, salvestades need faili, mis asub keskkonnamuutujas määratud tee järgi $METRICS_PATH.
Siin nii saate teha operaatori lihtsaks võrgu jälgimiseks klastris.
Järjekorra mehhanism
See artikkel oleks puudulik, kirjeldamata teist olulist kestaoperaatorisse sisseehitatud mehhanismi. Kujutage ette, et see käivitab vastuseks klastri sündmusele mingi konksu.
Mis juhtub, kui samal ajal klastris midagi juhtub? üks veel sündmus?
Kas shell-operator käivitab teise konksu eksemplari?
Mis siis, kui klastris juhtub korraga näiteks viis sündmust?
Kas shell-operaator töötleb neid paralleelselt?
Kuidas on lood tarbitud ressurssidega, nagu mälu ja protsessor?
Õnneks on shell-operaatoril sisseehitatud järjekorra mehhanism. Kõik sündmused pannakse järjekorda ja neid töödeldakse järjest.
Illustreerime seda näidetega. Oletame, et meil on kaks konksu. Esimene sündmus läheb esimese konksu otsa. Kui selle töötlemine on lõppenud, liigub järjekord edasi. Järgmised kolm sündmust suunatakse ümber teise konksu juurde - need eemaldatakse järjekorrast ja sisestatakse sinna "kimpu". See on konks võtab vastu hulga sündmusi — või täpsemalt siduvate kontekstide massiivi.
Ka need sündmused saab ühendada üheks suureks. Selle eest vastutab parameeter group sidumiskonfiguratsioonis.
Saate luua suvalise arvu järjekordi/konkse ja nende erinevaid kombinatsioone. Näiteks võib üks järjekord töötada kahe konksuga või vastupidi.
Kõik, mida pead tegema, on väli vastavalt konfigureerida queue sidumiskonfiguratsioonis. Kui järjekorra nime pole määratud, töötab konks vaikejärjekorras (default). See järjekorramehhanism võimaldab teil konksudega töötamisel täielikult lahendada kõik ressursside haldamise probleemid.
Järeldus
Selgitasime, mis on shell-operaator, näitasime, kuidas selle abil saab kiiresti ja vaevata Kubernetese operaatoreid luua ning tõime mitmeid näiteid selle kasutamisest.
Üksikasjalik teave shell-operaatori kohta, samuti kiire õpetus selle kasutamiseks on saadaval vastavas hoidlad GitHubis. Küsimuste korral võtke meiega julgelt ühendust: saate neid arutada spetsiaalselt Telegrami grupp (vene keeles) või keeles see foorum (inglise keeles).
Ja kui teile meeldis, on meil alati hea meel näha GitHubis uusi väljaandeid/PR/staare, kust muide leiate ka teisi huvitavaid projekte. Nende hulgas tasub esile tõsta lisand-operaator, mis on shell-operaatori suur vend. See utiliit kasutab lisandmoodulite installimiseks Helmi diagramme, saab pakkuda värskendusi ja jälgida erinevaid diagrammi parameetreid/väärtusi, juhib diagrammide installiprotsessi ja saab neid ka muuta vastavalt klastris toimuvatele sündmustele.