Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Ove godine, glavna evropska Kubernetes konferencija - KubeCon + CloudNativeCon Europe 2020 - bila je virtuelna. Međutim, takva promjena formata nas nije spriječila da isporučimo naš dugo planirani izvještaj „Go? Bash! Upoznajte Shell-operatora” posvećenog našem Open Source projektu shell-operator.

Ovaj članak, inspiriran govorom, predstavlja pristup pojednostavljenju procesa kreiranja operatora za Kubernetes i pokazuje kako možete napraviti svoj vlastiti uz minimalan napor koristeći shell-operator.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Predstavljamo video izvještaja (~23 minuta na engleskom, znatno informativnije od članka) i glavni izvod iz njega u tekstualnom obliku. Idi!

U Flantu stalno sve optimizujemo i automatizujemo. Danas ćemo govoriti o još jednom uzbudljivom konceptu. upoznajte: skriptiranje ljuske u izvornom oblaku!

Međutim, počnimo s kontekstom u kojem se sve ovo događa: Kubernetes.

Kubernetes API i kontroleri

API u Kubernetesu može biti predstavljen kao vrsta servera datoteka sa direktorijumima za svaki tip objekta. Objekti (resursi) na ovom serveru su predstavljeni YAML datotekama. Pored toga, server ima osnovni API koji vam omogućava da uradite tri stvari:

  • uzmi resurs po svojoj vrsti i nazivu;
  • promjena resurs (u ovom slučaju server pohranjuje samo "ispravne" objekte - svi pogrešno formirani ili namijenjeni drugim direktorijima se odbacuju);
  • track za resurs (u ovom slučaju korisnik odmah prima njegovu trenutnu/ažuriranu verziju).

Dakle, Kubernetes djeluje kao neka vrsta servera datoteka (za YAML manifeste) sa tri osnovne metode (da, zapravo postoje i drugi, ali ćemo ih za sada izostaviti).

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Problem je što server može pohraniti samo informacije. Da bi to funkcionisalo vam je potrebno kontroler - drugi najvažniji i fundamentalni koncept u svetu Kubernetesa.

Postoje dvije glavne vrste kontrolera. Prvi uzima informacije iz Kubernetesa, obrađuje ih prema ugniježđenoj logici i vraća ih u K8s. Drugi preuzima informacije iz Kubernetesa, ali, za razliku od prvog tipa, mijenja stanje nekih eksternih resursa.

Pogledajmo bliže proces kreiranja Deploymenta u Kubernetesu:

  • Kontrolor implementacije (uključen u kube-controller-manager) prima informacije o implementaciji i kreira ReplicaSet.
  • ReplicaSet kreira dvije replike (dva modula) na osnovu ovih informacija, ali ti podovi još nisu zakazani.
  • Planer raspoređuje podove i dodaje informacije o čvorovima njihovim YAML-ovima.
  • Kubelets unose promjene na vanjski resurs (recimo Docker).

Zatim se cijeli niz ponavlja obrnutim redoslijedom: kubelet provjerava kontejnere, izračunava status modula i šalje ga nazad. ReplicaSet kontroler prima status i ažurira stanje skupa replika. Ista stvar se dešava sa kontrolorom implementacije i korisnik konačno dobija ažurirani (trenutni) status.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Shell-operator

Ispostavilo se da je Kubernetes zasnovan na zajedničkom radu različitih kontrolora (Kubernetes operateri su takođe kontrolori). Postavlja se pitanje, kako stvoriti vlastitog operatera uz minimalan trud? I ovdje u pomoć dolazi onaj koji smo razvili shell-operator. Omogućava administratorima sistema da kreiraju vlastite izjave koristeći poznate metode.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Jednostavan primjer: kopiranje tajni

Pogledajmo jednostavan primjer.

Recimo da imamo Kubernetes klaster. Ima imenski prostor default sa nekom Tajnom mysecret. Osim toga, postoje i drugi imenski prostori u klasteru. Neki od njih imaju posebnu etiketu. Naš cilj je kopirati Secret u imenske prostore s oznakom.

Zadatak je kompliciran činjenicom da se u klasteru mogu pojaviti novi prostori imena, a neki od njih mogu imati ovu oznaku. S druge strane, kada se oznaka obriše, potrebno je izbrisati i Secret. Osim toga, sama tajna se također može promijeniti: u ovom slučaju, nova tajna mora biti kopirana u sve prostore imena s oznakama. Ako se Secret slučajno izbriše u bilo kojem imenskom prostoru, naš operater bi ga trebao odmah vratiti.

Sada kada je zadatak formuliran, vrijeme je da počnemo da ga implementiramo koristeći shell-operator. Ali prvo je vrijedno reći nekoliko riječi o samom shell-operatoru.

Kako radi shell-operator

Kao i druga radna opterećenja u Kubernetesu, shell-operator se pokreće u vlastitom pod-u. U ovom pod u direktoriju /hooks izvršne datoteke se pohranjuju. To mogu biti skripte u Bash, Python, Ruby, itd. Takve izvršne datoteke nazivamo kukicama (kuke).

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Shell-operator se pretplaćuje na Kubernetes događaje i pokreće ove kuke kao odgovor na one događaje koji su nam potrebni.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Kako shell-operator zna koji hook da pokrene i kada? Poenta je da svaka udica ima dvije faze. Tokom pokretanja, shell-operator pokreće sve zakačive s argumentom --config Ovo je faza konfiguracije. A nakon toga, kuke se pokreću na normalan način - kao odgovor na događaje za koje su vezane. U potonjem slučaju, kuka prima kontekst povezivanja (obavezujući kontekst) - podaci u JSON formatu, o čemu ćemo detaljnije govoriti u nastavku.

Pravljenje operatora u Bashu

Sada smo spremni za implementaciju. Da bismo to učinili, moramo napisati dvije funkcije (usput, preporučujemo biblioteku shell_lib, što uvelike pojednostavljuje pisanje udica u Bashu):

  • prvi je potreban za fazu konfiguracije - prikazuje kontekst povezivanja;
  • drugi sadrži glavnu logiku kuke.

#!/bin/bash

source /shell_lib.sh

function __config__() {
  cat << EOF
    configVersion: v1
    # BINDING CONFIGURATION
EOF
}

function __main__() {
  # THE LOGIC
}

hook::run "$@"

Sljedeći korak je odlučiti koji su nam objekti potrebni. U našem slučaju moramo pratiti:

  • izvorna tajna za promjene;
  • svi imenski prostori u klasteru, tako da znate koji imaju pridruženu oznaku;
  • ciljane tajne kako bi se osiguralo da su sve sinkronizirane s izvornom tajnom.

Pretplatite se na tajni izvor

Konfiguracija vezivanja za to je prilično jednostavna. Nazivom označavamo da nas zanima Secret mysecret u imenskom prostoru default:

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa 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

Kao rezultat toga, kuka će se pokrenuti kada se promijeni izvorna tajna (src_secret) i primite sljedeći obavezujući kontekst:

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Kao što vidite, sadrži ime i cijeli objekt.

Praćenje imenskih prostora

Sada se morate pretplatiti na imenske prostore. Da bismo to učinili, specificiramo sljedeću konfiguraciju vezivanja:

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

Kao što vidite, pojavilo se novo polje u konfiguraciji sa imenom jqFilter. Kao što mu ime govori, jqFilter filtrira sve nepotrebne informacije i kreira novi JSON objekat sa poljima koja nas zanimaju. Hook sa sličnom konfiguracijom će dobiti sljedeći kontekst povezivanja:

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Sadrži niz filterResults za svaki prostor imena u klasteru. Boolean varijabla hasLabel označava da li je oznaka pridružena datom imenskom prostoru. Selektor keepFullObjectsInMemory: false označava da nema potrebe za čuvanjem kompletnih objekata u memoriji.

Praćenje tajni meta

Pretplaćujemo se na sve Tajne koje imaju specificiranu napomenu managed-secret: "yes" (ovo su naša meta 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

U ovom slučaju jqFilter filtrira sve informacije osim imenskog prostora i parametra resourceVersion. Posljednji parametar je proslijeđen u napomenu prilikom kreiranja tajne: omogućava vam da uporedite verzije tajni i da ih ažurirate.

Ovako konfigurirana kuka će, kada se izvrši, primiti tri gore opisana konteksta povezivanja. Mogu se smatrati svojevrsnim snimkom (snimak) klaster.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Na osnovu svih ovih informacija može se razviti osnovni algoritam. Iterira preko svih imenskih prostora i:

  • ako hasLabel pitanja true za trenutni imenski prostor:
    • uspoređuje globalnu tajnu s lokalnom:
      • ako su isti, to ne čini ništa;
      • ako se razlikuju - izvršava kubectl replace ili create;
  • ako hasLabel pitanja false za trenutni imenski prostor:
    • osigurava da Secret nije u datom imenskom prostoru:
      • ako je lokalna tajna prisutna, obrišite je koristeći kubectl delete;
      • ako lokalna tajna nije otkrivena, ne radi ništa.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Implementacija algoritma u Bashu možete preuzeti u našoj spremišta sa primjerima.

Tako smo uspeli da kreiramo jednostavan Kubernetes kontroler koristeći 35 linija YAML konfiguracije i otprilike istu količinu Bash koda! Posao operatera je da ih poveže.

Međutim, kopiranje tajni nije jedino područje primjene uslužnog programa. Evo još nekoliko primjera koji pokazuju za šta je sposoban.

Primjer 1: Izmjena ConfigMap-a

Pogledajmo Deployment koji se sastoji od tri modula. Podovi koriste ConfigMap za pohranjivanje neke konfiguracije. Kada su podovi pokrenuti, ConfigMap je bio u određenom stanju (nazovimo ga v.1). Shodno tome, svi podovi koriste ovu konkretnu verziju ConfigMap-a.

Sada pretpostavimo da se ConfigMap promijenio (v.2). Međutim, podovi će koristiti prethodnu verziju ConfigMap-a (v.1):

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Kako ih mogu natjerati da se prebace na novi ConfigMap (v.2)? Odgovor je jednostavan: koristite šablon. Dodajmo napomenu kontrolne sume u sekciju template Konfiguracije implementacije:

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Kao rezultat toga, ovaj kontrolni zbroj će biti registriran u svim podovima, i bit će isti kao onaj za Deployment. Sada samo trebate ažurirati napomenu kada se ConfigMap promijeni. I shell-operator u ovom slučaju dobro dođe. Sve što treba da uradite je da programirate kuka koja će se pretplatiti na ConfigMap i ažurirati kontrolni zbroj.

Ako korisnik napravi promjene u ConfigMap-u, shell-operator će ih primijetiti i ponovo izračunati kontrolni zbroj. Nakon čega će se uključiti magija Kubernetesa: orkestrator će ubiti kapsulu, stvoriti novu, čekati da postane Ready, i prelazi na sljedeću. Kao rezultat toga, Deployment će se sinkronizirati i prebaciti na novu verziju ConfigMap-a.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Primjer 2: Rad s prilagođenim definicijama resursa

Kao što znate, Kubernetes vam omogućava da kreirate prilagođene tipove objekata. Na primjer, možete kreirati vrstu MysqlDatabase. Recimo da ovaj tip ima dva parametra metapodataka: name и namespace.

apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
  name: foo
  namespace: bar

Imamo Kubernetes klaster sa različitim imenskim prostorima u kojima možemo kreirati MySQL baze podataka. U ovom slučaju shell-operator se može koristiti za praćenje resursa MysqlDatabase, povezujući ih sa MySQL serverom i sinhronizujući željena i posmatrana stanja klastera.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Primjer 3: Nadgledanje mreže klastera

Kao što znate, korištenje pinga je najjednostavniji način za praćenje mreže. U ovom primjeru ćemo pokazati kako implementirati takav nadzor koristeći shell-operator.

Prije svega, morat ćete se pretplatiti na čvorove. Shell operator treba ime i IP adresu svakog čvora. Uz njihovu pomoć, on će pingovati ove čvorove.

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: "* * * * *"

Parametar executeHookOnEvent: [] sprečava pokretanje kuke kao odgovor na bilo koji događaj (to jest, kao odgovor na promjenu, dodavanje, brisanje čvorova). Međutim, on će trčati (i ažurirati listu čvorova) Zakazano - svakog minuta, kako je propisano na terenu schedule.

Sada se postavlja pitanje, kako tačno znamo o problemima kao što je gubitak paketa? Pogledajmo 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
}

Iteriramo kroz listu čvorova, dobijamo njihova imena i IP adrese, pingujemo ih i šaljemo rezultate Prometheusu. Shell-operator može izvesti metriku u Prometheus, spremajući ih u datoteku koja se nalazi prema putanji navedenoj u varijabli okruženja $METRICS_PATH.

Evo tako možete napraviti operatora za jednostavno praćenje mreže u klasteru.

Mehanizam čekanja

Ovaj članak bi bio nepotpun bez opisa drugog važnog mehanizma ugrađenog u shell-operator. Zamislite da izvršava neku vrstu kuke kao odgovor na događaj u klasteru.

  • Šta se dešava ako se, istovremeno, nešto dogodi u klasteru? još jedan događaj?
  • Hoće li shell-operator pokrenuti još jednu instancu kuke?
  • Šta ako se, recimo, u klasteru dogodi pet događaja odjednom?
  • Hoće li ih shell-operator obraditi paralelno?
  • Šta je sa potrošenim resursima kao što su memorija i CPU?

Na sreću, shell-operator ima ugrađeni mehanizam čekanja. Svi događaji se nalaze u redu čekanja i obrađuju se uzastopno.

Ilustrirajmo to primjerima. Recimo da imamo dvije udice. Prvi događaj ide na prvu udicu. Kada se obrada završi, red se kreće naprijed. Sljedeća tri događaja se preusmjeravaju na drugu kuku - uklanjaju se iz reda čekanja i unose u njega u "snopu". To je hook prima niz događaja — ili, preciznije, niz obavezujućih konteksta.

Takođe i ove događaji se mogu spojiti u jedan veliki. Za to je odgovoran parametar group u konfiguraciji vezivanja.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Možete kreirati bilo koji broj redova/kukica i njihove različite kombinacije. Na primjer, jedan red može raditi s dvije kuke, ili obrnuto.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Sve što trebate učiniti je konfigurirati polje u skladu s tim queue u konfiguraciji vezivanja. Ako ime reda nije specificirano, kuka se pokreće na zadanom redu (default). Ovaj mehanizam čekanja vam omogućava da u potpunosti riješite sve probleme upravljanja resursima kada radite sa zakačaljkama.

zaključak

Objasnili smo šta je shell-operator, pokazali kako se može koristiti za brzo i lako kreiranje Kubernetes operatora i naveli nekoliko primjera njegove upotrebe.

Detaljne informacije o shell-operatoru, kao i brzi vodič o tome kako ga koristiti, dostupni su u odgovarajućem spremišta na GitHub-u. Ne ustručavajte se kontaktirati nas sa pitanjima: o njima možete razgovarati u posebnom Telegram grupa (na ruskom) ili na ovaj forum (na engleskom).

A ako vam se svidjelo, uvijek smo sretni da vidimo nove izdanja/PR/zvijezde na GitHubu, gdje, inače, možete pronaći i druge zanimljivih projekata. Među njima je vrijedno istaknuti addon-operator, koji je veliki brat shell-operatora. Ovaj uslužni program koristi Helmove grafikone za instaliranje dodataka, može isporučiti ažuriranja i pratiti različite parametre/vrijednosti grafikona, kontrolira proces instalacije grafikona, a također ih može modificirati kao odgovor na događaje u klasteru.

Idi? Bash! Upoznajte shell-operatora (pregled i video izvještaj sa KubeCon EU'2020)

Video zapisi i slajdovi

Video sa nastupa (~23 minute):


Prezentacija izvještaja:

PS

Pročitajte i na našem blogu:

izvor: www.habr.com

Dodajte komentar