Go? Bash! Tutvuge shell-operatoriga (ĂŒlevaade ja video KubeCon EU'2020 ettekandest)

Sel aastal toimus Euroopa peamine Kubernetes'i konverents KubeCon + CloudNativeCon Europe 2020 virtuaalselt. Siiski ei takistanud see formaadi muutus meid esitlemast juba ammu plaanitud ettekannet „Go? Bash! Tutvuge Shell-operatoriga”, mis on pĂŒhendatud meie Open Source projektile. shell-operator.

Selles artiklis, mis pÔhineb ettekandel, esitatakse lÀhenemine Kubernetes'i operaatorite loomise protsessi lihtsustamiseks ja nÀidatakse, kuidas shell-operator'i abil saab minimaalse vaevaga luua omaenda operaatori.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Tutvustame ettekande video vaatamiseks (~23 minutit inglise keeles, selgelt informatiivsem kui artikkel) ja pÔhisisu sellest tekstivormis. Alustame!

Me „Flante'is” optimeerime ja automatiseerime pidevalt. TĂ€na rÀÀgime veel ĂŒhest pĂ”nevast kontseptsioonist. Tere tulemast: cloud-native shell-skriptimine!

Kuid alustame kontekstist, milles see kĂ”ik aset leiab — Kubernetes’est.

Kubernetes API ja kontrollijad

Kubernetes'es vĂ”ib API-d kujutada kui mingisugust failiserverit, kus igat tĂŒĂŒpi objektide jaoks on katalogid. Selle serveri objektid (ressursid) on esitatud YAML-failidena. Lisaks on serveril baas-API, mis vĂ”imaldab teha kolme asja:

  • saama ressursi jĂ€rgi selle kind'i ja nime;
  • muutma ressurssi (samal ajal server salvestab ainult "Ă”igeid" objekte — kĂ”ik valesti vormistatud vĂ”i teiste kaustade jaoks mÀÀratud objektid jĂ€etakse kĂ”rvale);
  • jĂ€lgida ressursi (sel juhul saab kasutaja kohe selle praeguse/uuendatud versiooni).

Seega toimib Kubernetes nagu failiserver (YAML-manifestide jaoks) kolme pÔhimeetodiga (jah, tegelikult on ka teisi, aga neid me praegu ei kÀsitle).

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Probleem on selles, et server oskab ainult teavet salvestada. Selle töötamiseks on vajalik kontroller — teine olulisus ja fundamentaalsus Kubernetes'e maailmas.

Erinevad kaks peamist kontrollerite tĂŒĂŒpi. Esimene vĂ”tab teavet Kubernetes'est, töötleb seda vastavalt sisemise loogika jĂ€rgi ja tagastab K8s-ile. Teine — vĂ”tab teavet Kubernetes'est, kuid erinevalt esimesest tĂŒĂŒbist muudab vĂ€listes ressurssides olekut.

Vaatame lĂ€hemalt Kubernetes'st Deployment’i loomise protsessi:

  • Deployment Controller (mis kuulub kube-controller-manager) saab teavet Deployment’i kohta ja loob ReplicaSet’i.
  • ReplicaSet loob selle teabe pĂ”hjal kaks koopiat (kahte pod'i), kuid need pod'id veel ei planeeritud.
  • Planeerija planeerib pod'e ja lisab nende YAML-idesse teavet sĂ”lmede kohta.
  • Kubelet'id teevad muudatusi vĂ€listes ressurssides (nĂ€iteks Dockeris).

SeejÀrel kordub kogu see jÀrjestus vastupidises jÀrjekorras: kubelet kontrollib konteinerite olekut, arvutab pod'i staatuse ja saadab selle tagasi. ReplicaSeti kontrollija saab staatuse ja vÀrskendab replikate kogumi olekut. Sama toimub Deployment Controlleriga, ja kasutaja saab lÔpuks vÀrskendatud (praeguse) staatuse.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Shell-operator

Kubernetes'e aluseks on erinevate kontrollijate koostöö (Kubernetes'e operaatorid on samuti kontrollijad). Kuidas luua oma operaator minimaalse vaevaga? Siin tuleb appi meie vĂ€lja töötatud shell-operator. See vĂ”imaldab sĂŒsteemiadministraatoritel luua oma operaatorid, kasutades tuttavaid meetodeid.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Lihtne nÀide: saladuste kopeerimine

Vaatame lihtsat nÀidet.

Oletame, et meil on Kubernetes'e klaster. Seal on nimesĂŒsteem default mingi Secret'iga mysecret. Lisaks on klastris ka teisi nimiruume. MĂ”nedele neist on kinnitatud teatud silt. Meie eesmĂ€rk on kopeerida Secret nimiruumidesse, kus on see silt.

Ülesanne muutub keerulisemaks, kuna klastris vĂ”ivad tekkida uued nimiruumid, ja mĂ”nel neist vĂ”ib olla see silt. Teiselt poolt, sildi eemaldamisel peab Secret ka eemaldama. Lisaks vĂ”ib ka ise Secret muutuda: sel juhul peab uus Secret olema kopeeritud kĂ”igisse nimiruumidesse, kus on sildid. Kui Secret juhuslikult mĂ”nes nimiruumis eemaldatakse, peab meie operaator selle kohe taastama.

NĂŒĂŒd, kui ĂŒlesanne on sĂ”nastatud, on aeg alustada selle elluviimist shell-operatori abil. Kuid esmalt tuleks öelda paar sĂ”na shell-operatori kohta.

Shell-operatori tööpÔhimÔtted

Nagu teised töökoormused Kuberneteses, töötab shell-operator oma pod’is. Selles pod’is asub kataloog /hooks , kus hoitakse tĂ€idetavaid faile. Need vĂ”ivad olla Bash, Python, Ruby jne skripte. Selliseid tĂ€idetavaid faile nimetame hook'ideks (hooks).

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

). Shell-operator subscribe'ib Kuberneteses toimuvatele sĂŒndmustele ja kĂ€ivitab neid hook'e vastusena neile sĂŒndmustele, mis meid huvitavad.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Kuidas shell-operator teab, millal ja millist hook'i kĂ€ivitada? Iga hook'il on kaks etappi. Shell-operator kĂ€ivitab hook'id koos argumendiga alustatud etapis --config — see on seadistamise etapp. PĂ€rast seda kĂ€ivituvad hook'id tavaliselt — vastuseks sĂŒndmustele, millega nad on seotud. Viimases juhul saab hook sidumise konteksti (binding context) — andmed JSON-formaadis, millest rÀÀgime lĂ€hemalt allpool.

Teeme Bash'is operaatorit

NĂŒĂŒd oleme valmis teostuseks. Selleks peame kirjutama kaks funktsiooni (mĂ€rkusena soovitame raamatukogu shell_lib, mis lihtsustab hook'ide kirjutamist Bash'is):

  • esimene on vajalik seadistamise etapis — see kuvab sidumise konteksti;
  • teine sisaldab hook'i pĂ”hiloogikat.

#!/bin/bash

source /shell_lib.sh

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

function __main__() {
  # THE LOGIC
}

hook::run "$@"

J siguiente etapas — kindlaks teha, milliseid objekte vajame. Meie puhul on vajalik jĂ€lgida:

  • salajase allika muudatused;
  • kĂ”iki namespace'e klastris, et teada, millistele neist on kleebis kinnitatud;
  • salajased sihid, et veenduda, et kĂ”ik need on sĂŒnkroonitud salajase allikaga.

Liitume salajase allikaga

Binding configuration on sellele on piisavalt lihtne. Me nÀitame, et meid huvitab saladus nimega mysecret nimeserveris default:

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

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

KokkuvÔttes kÀivitatakse hook, kui saladuse allikas muutub (src_secret) ja saab jÀrgmise binding context'i:

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Nagu nÀete, sisaldab see nime ja objekti tervikuna.

JĂ€lgime nimesid

NĂŒĂŒd peame registreeruma nimedele. Selleks nĂ€itame jĂ€rgmist binding configuration'i:

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

Nagu nĂ€ete, on konfiguratsioonis uus vĂ€li nimega jqFilter. Kuidas tema nimi ĂŒtleb, jqFilter filtreerib kogu ĂŒleliigse teabe ja loob uue JSON objekti, mille vĂ€ljad on meie jaoks huvitavad. Hook sellise konfiguratsiooniga saab jĂ€rgmise binding context'i:

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

See sisaldab massiivi filterResults iga klastris asuva nime jaoks. Boolean muutuja hasLabel nĂ€itab, kas silt on antud nimede ruumiga seotud. Valija keepFullObjectsInMemory: false ĂŒtleb, et pole vaja hoida tĂ€isobjekte mĂ€lus.

JĂ€lgime sihtsaladusi

Tellime kÔiki salajasi, millel on mÀÀratud annotatsioon managed-secret: "yes" (need on meie sihttou 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

Sel juhul jqFilter filtreerib kogu teabe vÀlja, vÀlja arvatud nimede ruum ja parameeter resourceVersion. Viimane parameeter anti annotatsioonis, kui saladus loodi: see vÔimaldab vÔrrelda saladuste versioone ja hoida neid ajakohasena.

Hook, mis on selliselt seadistatud, saab tĂ”husalt kolme konteksti sidumist, nagu eespool kirjeldatud. Neid vĂ”ib esitada kui teatud tĂŒĂŒpi hetkeseis (snapshot) klastri.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Kogu selle teabe pÔhjal saab vÀlja töötada pÔhialgoritmi. See lÀbib kÔik nimede ruumid ja:

  • kui hasLabel vÀÀrtus true praeguse nimede ruumi jaoks:
    • vĂ”rdleb globaalset saladust kohaliku:
      • kui nad on samad — ei tee midagi;
      • kui nad erinevad — tĂ€idab kubectl asendada vĂ”i create;
  • kui hasLabel vÀÀrtus false praeguse nimede ruumi jaoks:
    • veendub, et Secret ei ole selles nimespetsiifis:
      • kui kohalik Secret on olemas — kustutab selle kubectl delete;
      • kui kohalik Secret ei leidu — ei tee midagi.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Bash'i algoritmi rakendamine saate alla laadida meie nÀidiste hoidlast.

Nii suudame luua lihtsa Kubernetes'i juhtkontrolleri, kasutades 35 rida YAML-konfide ja umbes sama palju Bash'i koodi! Shell-operaatori ĂŒlesanne on need kokku siduda.

Kuid saladuste kopeerimine ei ole ainus rakendus, millega utiliit tegeleb. Siin on veel paar nÀidet, mis nÀitavad, milleks see vÔimeline on.

NĂ€ide 1: muudatuste tegemine ConfigMap'is

Vaadakem Deployment'i, mis koosneb kolmest pod'ist. Pod'id kasutavad ConfigMap'i teatud konfigureerimise talletamiseks. Pod'ide kÀivitamise ajal oli ConfigMap mingis seisundis (nimetame seda v.1). Seega kasutavad kÔik pod'id just seda ConfigMap'i versiooni.

NĂŒĂŒd eeldame, et ConfigMap on muutunud (v.2). Kuid pod'id jĂ€tkuvalt kasutavad vana ConfigMap'i versiooni (v.1):

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Kuidas saavutada, et nad ĂŒleminek uuele ConfigMap'ile (v.2)? Vastus on lihtne: kasutada templati. Lisame annotatsiooni koos kontrollsummaga sektsiooni template Deployment'i konfiguratsioon:

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Tulemusena on kĂ”igis pod'ides selline kontrollsumma, nagu Deployment'il. NĂŒĂŒd tuleb lihtsalt annotatsiooni uuendada, kui ConfigMap muutub. Ja shell-operator on selle puhul suurepĂ€rane lahendus. KĂ”ik, mis on vajalik — programmeerida hook, mis registreerib end ConfigMap'i ning uuendab kontrollsummat.

Kui kasutaja teeb ConfigMap'is muudatusi, mĂ€rkab shell-operator neid ning arvutab kontrollsummat uuesti. SeejĂ€rel astub mĂ€ngu Kubernetes'i maagia: orkestreerija tapab pod'i, loob uue, ootab, kuni see muutub Valmis, ja liigub edasi. Tulemusena sĂŒnkroniseeritakse Deployment ja liigub uuele ConfigMap'i versioonile.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

NÀide 2: töö Custom Resource Definitions'iga

Nagu teada, vĂ”imaldab Kubernetes luua kohandatud tĂŒĂŒpe (kinds) objekte. NĂ€iteks, vĂ”ib luua tĂŒĂŒbi MysqlDatabase.Oletame, et sellel tĂŒĂŒbil on kaks metadata-parameetrit: name ja namespace.

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

Meil on Kubernetes klastri, millel on erinevad nimeruumi, kus saame luua MySQL andmebaase. Sel juhul saab shell-operatorit kasutada ressursside jĂ€lgimiseks MysqlDatabase., nende ĂŒhenduste jĂ€lgimiseks MySQL serveriga ja soovitud ning jĂ€lgitud klastriseisundite sĂŒnkroniseerimiseks.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

NÀide 3: klastrivÔrgu jÀlgimine

Nagu teada, on ping'i kasutamine kÔige lihtsam viis vÔrgu jÀlgimiseks. Selles nÀites nÀitame, kuidas sellist jÀlgimist rakendada shell-operatori abil.

Esiteks on vaja abonente registreerida sÔlmedele. Shell-operator vajab iga sÔlme nime ja IP-aadressi. Nende abil saavad nad neid sÔlmi pingida.

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

Parameeter executeHookOnEvent: [] takistab hĂŒĂŒde kĂ€ivitamist vastusena igasugustele sĂŒndmustele (st sĂ”lmede muutmise, lisamise vĂ”i kustutamise vastusena). Siiski kĂ€ivitub ta (ja uuendab sĂ”lmede loetelu) ajakava jĂ€rgi — iga minut, nagu on ette nĂ€htud vĂ€ljas schedule.

NĂŒĂŒd tekib kĂŒsimus, kuidas me saame teada probleemidest, nagu pakettide kaotus? Vaatame koodile:

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
}

Me kÀime lÀbi sÔlmede loendi, saame nende nimed ja IP-aadressid, pingime ja edastame tulemused Prometheusse. Shell-operator oskab eksportida mÔÔdikud Prometheusesse, salvestades need faili, mis asub keskkonnamuutuja $METRICS_PATH.

Nii see abil saab teha operaatorit lihtsaks vÔrgu jÀlgimiseks klastris.

Queue mehhanism

See artikkel oleks puudulik, kui ei mainiks veel ĂŒht olulist mehhanismi, mis on integreeritud shell-operatorisse. Kujutage ette, et see kĂ€ivitab mingi huki vastusena klastris toimunud sĂŒndmusele.

  • Mis juhtub, kui samal ajal klastris toimub veel ĂŒks sĂŒndmus?
  • Kas shell-operator kĂ€ivitab veel ĂŒhe huki eksemplari?
  • Ja mis siis, kui klastris toimub korraga, ĂŒtleme, viis sĂŒndmust?
  • Kas shell-operator töötleb neid paralleelselt?
  • Ent kuidas on lood ressursside, nagu mĂ€lu ja CPU, tarbimisega?

Õnneks on shell-operatoris olemas sisseehitatud jĂ€rjekordade mehhanism. KĂ”ik sĂŒndmused paigutatakse jĂ€rjekorda ja töödeldakse jĂ€rjestikku.

Illustreerime seda nĂ€idete abil. Oletame, et meil on kaks hooki. Esimene sĂŒndmus tĂ”mmatakse esimeselt hookilt. PĂ€rast töötlemise lĂ”petamist edeneb jĂ€rjekord edasi. JĂ€rgmised kolm sĂŒndmust suunatakse teisele hookile — need tĂ”mmatakse jĂ€rjekorrast ja edastatakse sellele 'kogusena'. Seega hook saab sĂŒndmuste massiivi — vĂ”i tĂ€psemalt öeldes, sidumise konteksti massiivi.

Samuti saab neid sĂŒndmusi kombineerida ĂŒhte suurde. Selle eest vastutab parameeter grupp sidumise konfiguratsioonis.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Saate luua suvalise arvu jĂ€rjekordi/hooke ja nende erinevaid kombinatsioone. NĂ€iteks vĂ”ib ĂŒks jĂ€rjekord töötada kahe hookiga vĂ”i vastupidi.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

KÔik, mida tuleb teha, on vastavalt seadistada queue sidumise konfiguratsiooni vÀli. Kui jÀrjekorra nime ei ole mÀÀratud, kÀivitatakse hook vaikimisi jÀrjekorras (default). Selline jÀrjekordade mehhanism lahendab tÀielikult kÔik ressursihalduse probleemid hookidega töötamisel.

KokkuvÔte

RÀÀkisime, mis on shell-operator, nÀitasime, kuidas selle abil saab kiiresti ja vaevatasu luua Kubernetes'e operaattoreid, ning tÔime esile mitmeid nÀiteid selle kasutamisest.

Üksikasjalik teave shell-operatori kohta ning lĂŒhike juhend selle kasutamiseks on saadaval vastavas GitHubi repostaariumist. Ära kĂ”hkle meiega kĂŒsimuste osas ĂŒhendust vĂ”tta: neid saab arutada eraldi Telegrami grupis (vene keeles) vĂ”i selles foorumis (inglise keeles).

Ja kui see meeldis - oleme alati rÔÔmsad uutest issues/PR/tĂ€htedest GitHubis, kus muide, leiad ka teisi huvitavaid projekte. Nendest tasub esile tĂ”sta addon-operator, mis on shell-operatori vanem vend. See utiliit kasutab Helm'i chart'e laienduste installimiseks, suudab edastada uuendusi ja jĂ€lgida erinevaid parameetreid/vÀÀrtuseid chart'ides, kontrollib chart'ide installimise protsessi ja suudab neid modifitseerida vastusena klastris toimuvatele sĂŒndmustele.

Go? Bash! Tere tulemast shell-operatori (ĂŒlevaade ja ettekande video KubeCon EU'2020-lt)

Video ja slaidid

Esituse video (~23 minutit):

Vaata videot

Ettekande esitlus:

P.S.

Lugege ka meie blogist:

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster