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ų.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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).

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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.
  • „Kubelets“ keičia išorinius išteklius (tarkime, „Docker“).

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ą.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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).

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

„Shell-operator“ užsiprenumeruoja „Kubernetes“ įvykius ir paleidžia šiuos „kablius“ reaguodamas į tuos įvykius, kurių mums reikia.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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:

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

function __config__() {
  cat << EOF
    configVersion: v1
    kubernetes:
    - name: src_secret
      apiVersion: v1
      kind: Secret
      nameSelector:
        matchNames:
        - mysecret
      namespace:
        nameSelector:
          matchNames: ["default"]
      group: main
EOF

Dėl to kabliukas bus suaktyvintas, kai pasikeis šaltinio paslaptis (src_secret) ir gauti tokį privalomą kontekstą:

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

Kaip matote, jame yra pavadinimas ir visas objektas.

Vardų erdvių stebėjimas

Dabar turite užsiprenumeruoti vardų erdves. Norėdami tai padaryti, nurodome šią įrišimo konfigūraciją:

- name: namespaces
  group: main
  apiVersion: v1
  kind: Namespace
  jqFilter: |
    {
      namespace: .metadata.name,
      hasLabel: (
       .metadata.labels // {} |  
         contains({"secret": "yes"})
      )
    }
  group: main
  keepFullObjectsInMemory: false

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ą:

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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):

- name: dst_secrets
  apiVersion: v1
  kind: Secret
  labelSelector:
    matchLabels:
      managed-secret: "yes"
  jqFilter: |
    {
      "namespace":
        .metadata.namespace,
      "resourceVersion":
        .metadata.annotations.resourceVersion
    }
  group: main
  keepFullObjectsInMemory: false

Š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.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

Algoritmo įgyvendinimas Bash galite atsisiųsti iš mūsų saugyklos su pavyzdžiais.

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):

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

Kaip priversti juos persijungti į naują ConfigMap (v.2)? Atsakymas paprastas: naudokite šabloną. Prie skyriaus pridėkime kontrolinės sumos anotaciją template Diegimo konfigūracijos:

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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ą.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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.

configVersion: v1
kubernetes:
- name: nodes
  apiVersion: v1
  kind: Node
  jqFilter: |
    {
      name: .metadata.name,
      ip: (
       .status.addresses[] |  
        select(.type == "InternalIP") |
        .address
      )
    }
  group: main
  keepFullObjectsInMemory: false
  executeHookOnEvent: []
schedule:
- name: every_minute
  group: main
  crontab: "* * * * *"

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.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

Galite sukurti bet kokį eilių / kabliukų skaičių ir įvairius jų derinius. Pavyzdžiui, viena eilė gali veikti su dviem kabliukais arba atvirkščiai.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

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.

Eiti? Bash! Susipažinkite su apvalkalo operatoriumi (apžvalga ir vaizdo reportažas iš KubeCon EU'2020)

Vaizdo įrašai ir skaidrės

Vaizdo įrašas iš spektaklio (~23 min.):


Pranešimo pristatymas:

PS

Taip pat skaitykite mūsų tinklaraštyje:

Šaltinis: www.habr.com

Добавить комментарий