Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Ove godine glavna europska Kubernetes konferencija – KubeCon + CloudNativeCon Europe 2020 – bila je virtualna. No, takva promjena formata nije nas spriječila da isporučimo dugo planiranu reportažu „Go? bas! Upoznajte Shell-operatora” posvećen našem Open Source projektu ljuska-operator.

Ovaj članak, inspiriran govorom, predstavlja pristup pojednostavljivanju procesa stvaranja operatora za Kubernetes i pokazuje kako možete izraditi vlastiti uz minimalan napor koristeći operator ljuske.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Upoznavanje video izvještaja (~23 minute na engleskom, osjetno informativnije od članka) i glavni izvadak iz njega u tekstualnom obliku. Ići!

U Flantu stalno sve optimiziramo i automatiziramo. Danas ćemo govoriti o još jednom uzbudljivom konceptu. Upoznajte: izvorno skriptiranje ljuske u oblaku!

No, krenimo od konteksta u kojem se sve to događa: Kubernetes.

Kubernetes API i kontroleri

API u Kubernetesu može se predstaviti kao neka vrsta poslužitelja datoteka s direktorijima za svaku vrstu objekta. Objekti (resursi) na ovom poslužitelju predstavljeni su YAML datotekama. Osim toga, poslužitelj ima osnovni API koji vam omogućuje da radite tri stvari:

  • primati izvor prema vrsti i nazivu;
  • promijeniti resurs (u ovom slučaju poslužitelj pohranjuje samo "ispravne" objekte - svi neispravno oblikovani ili namijenjeni drugim direktorijima se odbacuju);
  • staza za resurs (u ovom slučaju korisnik odmah dobiva njegovu trenutnu/ažuriranu verziju).

Dakle, Kubernetes djeluje kao neka vrsta poslužitelja datoteka (za YAML manifeste) s tri osnovne metode (da, zapravo postoje i druge, ali ćemo ih za sada izostaviti).

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Problem je u tome što poslužitelj može samo pohranjivati ​​informacije. Da bi funkcioniralo potrebno vam je kontrolor - drugi najvažniji i temeljni koncept u svijetu 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 mijenja stanje nekih vanjskih resursa.

Pogledajmo pobliže proces stvaranja implementacije u Kubernetesu:

  • Kontroler implementacije (uključen u kube-controller-manager) prima informacije o postavljanju i stvara ReplicaSet.
  • ReplicaSet stvara dvije replike (dva modula) na temelju ovih informacija, ali ti moduli još nisu zakazani.
  • Planer raspoređuje mahune i dodaje informacije o čvorovima njihovim YAML-ovima.
  • Kubelets mijenja vanjske resurse (recimo Docker).

Zatim se cijeli ovaj niz ponavlja obrnutim redoslijedom: kubelet provjerava spremnike, izračunava status mahuna i šalje ga natrag. Kontroler ReplicaSet prima status i ažurira stanje skupa replika. Ista stvar se događa s Deployment Controllerom i korisnik konačno dobiva ažurirani (trenutni) status.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Shell-operator

Ispostavilo se da se Kubernetes temelji na zajedničkom radu različitih kontrolera (Kubernetes operateri su također kontroleri). Postavlja se pitanje kako uz minimalan trud stvoriti vlastitog operatera? I tu u pomoć dolazi onaj koji smo razvili ljuska-operator. Omogućuje administratorima sustava stvaranje vlastitih izjava koristeći poznate metode.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Jednostavan primjer: kopiranje tajni

Pogledajmo jednostavan primjer.

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

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

Sada kada je zadatak formuliran, vrijeme je da ga počnemo implementirati korištenjem shell-operatora. Ali prvo vrijedi reći nekoliko riječi o samom operateru školjke.

Kako radi shell-operator

Kao i druga radna opterećenja u Kubernetesu, shell-operator radi u vlastitom modulu. U ovoj mahuni u imeniku /hooks pohranjuju se izvršne datoteke. To mogu biti skripte u Bashu, Pythonu, Rubyju itd. Takve izvršne datoteke nazivamo kukicama (kuke).

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s 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.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Kako shell-operator zna koji hook pokrenuti i kada? Poanta je da svaka udica ima dvije faze. Tijekom pokretanja, shell-operator pokreće sve kuke 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 vezujući kontekst (obvezujući kontekst) - podaci u JSON formatu, o čemu ćemo detaljnije govoriti u nastavku.

Izrada operatora u Bashu

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

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

#!/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 objekti su nam potrebni. U našem slučaju, moramo pratiti:

  • izvorna tajna za promjene;
  • sve imenske prostore u klasteru, tako da znate koji od njih imaju pridruženu oznaku;
  • ciljne tajne kako biste osigurali da su sve sinkronizirane s izvornom tajnom.

Pretplatite se na tajni izvor

Konfiguracija vezanja za njega je prilično jednostavna. Imenom označavamo da nas zanima Secret mysecret u imenskom prostoru default:

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s 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 obvezujući kontekst:

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

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

Praćenje imenskih prostora

Sada se morate pretplatiti na prostore imena. Da bismo to učinili, navodimo sljedeću konfiguraciju vezanja:

- 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, u konfiguraciji se pojavilo novo polje s imenom jqFilter. Kao što mu ime govori, jqFilter filtrira sve nepotrebne informacije i stvara novi JSON objekt s poljima koja nas zanimaju. Priključak sa sličnom konfiguracijom primit će sljedeći kontekst vezivanja:

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Sadrži niz filterResults za svaki imenski prostor u klasteru. Booleova varijabla hasLabel označava da li je oznaka pridružena danom prostoru imena. Selektor keepFullObjectsInMemory: false označava da nema potrebe čuvati kompletne objekte u memoriji.

Praćenje ciljnih tajni

Pretplaćujemo se na sve tajne koje imaju navedenu napomenu managed-secret: "yes" (ovo su naš cilj 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 prostora imena i parametra resourceVersion. Posljednji parametar proslijeđen je napomeni prilikom stvaranja tajne: omogućuje vam usporedbu verzija tajni i njihovo ažuriranje.

Ovako konfigurirana kuka će, kada se izvrši, primiti tri gore opisana konteksta vezivanja. Mogu se smatrati nekom vrstom snimke (snimak) Klastera.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Na temelju svih ovih podataka može se razviti osnovni algoritam. Iterira kroz sve imenske prostore i:

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

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Implementacija algoritma u Bashu možete preuzeti u našem spremišta s primjerima.

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

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

Primjer 1: Unošenje promjena u ConfigMap

Pogledajmo raspored koji se sastoji od tri mahune. Podovi koriste ConfigMap za pohranu neke konfiguracije. Kada su podovi pokrenuti, ConfigMap je bio u određenom stanju (nazovimo ga v.1). Sukladno tome, sve mahune koriste ovu određenu verziju ConfigMapa.

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

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Kako ih mogu natjerati da prijeđu na novi ConfigMap (v.2)? Odgovor je jednostavan: koristite predložak. Dodajmo odjeljku bilješku kontrolne sume template Konfiguracije implementacije:

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Kao rezultat toga, ovaj će se kontrolni zbroj registrirati u svim modulima i bit će isti kao onaj za implementaciju. Sada samo trebate ažurirati napomenu kada se promijeni ConfigMap. I shell-operator dobro dolazi u ovom slučaju. Sve što trebate učiniti je programirati kuka koja će se pretplatiti na ConfigMap i ažurirati kontrolni zbroj.

Ako korisnik napravi promjene na ConfigMap, operater ljuske će to primijetiti i ponovno izračunati kontrolni zbroj. Nakon čega će magija Kubernetesa stupiti na scenu: orkestrator će ubiti pod, stvoriti novi, pričekati da postane Ready, i prelazi na sljedeći. Kao rezultat toga, Deployment će se sinkronizirati i prebaciti na novu verziju ConfigMapa.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Primjer 2: Rad s prilagođenim definicijama resursa

Kao što znate, Kubernetes vam omogućuje stvaranje prilagođenih tipova objekata. Na primjer, možete stvoriti vrstu MysqlDatabase. Recimo da ova vrsta ima dva parametra metapodataka: name и namespace.

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

Imamo Kubernetes klaster s 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 s MySQL poslužiteljem i sinkronizirajući željena i promatrana stanja klastera.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Primjer 3: Nadgledanje mreže klastera

Kao što znate, korištenje pinga je najjednostavniji način za nadzor mreže. U ovom primjeru pokazat ćemo kako implementirati takav nadzor pomoću shell-operatora.

Prije svega, morat ćete se pretplatiti na čvorove. Operater ljuske treba ime i IP adresu svakog čvora. Uz njihovu pomoć, on će pingati 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: [] sprječ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žuriranje popisa čvorova) Zakazano - svake minute, kako propisuje polje schedule.

Sada se postavlja pitanje, kako točno znamo za probleme poput gubitka 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 popis čvorova, dobivamo 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 stazi navedenoj u varijabli okruženja $METRICS_PATH.

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

Mehanizam čekanja

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

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

Srećom, shell-operator ima ugrađeni mehanizam čekanja. Svi se događaji stavljaju u red čekanja i obrađuju sekvencijalno.

Ilustrirajmo to primjerima. Recimo da imamo dvije udice. Prvi događaj ide prvoj udici. Nakon završetka obrade, red se pomiče naprijed. Sljedeća tri događaja preusmjeravaju se na drugu kuku - uklanjaju se iz reda čekanja i unose u njega u "paketu". To je kuka prima niz događaja — ili, točnije, niz obvezujućih konteksta.

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

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s 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.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Sve što trebate učiniti je konfigurirati polje u skladu s tim queue u konfiguraciji vezanja. Ako naziv reda čekanja nije naveden, kuka se pokreće na zadanom redu čekanja (default). Ovaj mehanizam čekanja omogućuje vam potpuno rješavanje svih problema upravljanja resursima pri radu s kukicama.

Zaključak

Objasnili smo što je shell-operator, pokazali kako se može koristiti za brzo i jednostavno kreiranje Kubernetes operatora i dali smo 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 GitHubu. Ne ustručavajte se kontaktirati nas s pitanjima: možete ih raspraviti u posebnom Telegram grupa (na ruskom) ili in ovaj forum (na engleskom).

A ako vam se svidjelo, uvijek nam je drago vidjeti nova izdanja/PR/zvjezdice na GitHubu, gdje, usput, možete pronaći i druge zanimljivi projekti. Među njima vrijedi istaknuti addon-operator, koji je stariji brat shell-operatora. Ovaj uslužni program koristi Helm grafikone za instaliranje dodataka, može isporučiti ažuriranja i nadzirati različite parametre/vrijednosti grafikona, kontrolira proces instalacije grafikona, a također ih može mijenjati kao odgovor na događaje u klasteru.

Ići? bas! Upoznajte operatera školjke (recenzija i video izvješće s KubeCon EU'2020)

Video zapisi i slajdovi

Video s nastupa (~23 minute):


Prezentacija izvješća:

PS

Pročitajte i na našem blogu:

Izvor: www.habr.com

Dodajte komentar