Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Këtë vit, konferenca kryesore evropiane e Kubernetes - KubeCon + CloudNativeCon Europe 2020 - ishte virtuale. Megjithatë, një ndryshim i tillë në format nuk na pengoi të dorëzonim raportin tonë të planifikuar prej kohësh “Shko? Bash! Njihuni me operatorin Shell” kushtuar projektit tonë me kod të hapur shell-operator.

Ky artikull, i frymëzuar nga fjalimi, paraqet një qasje për thjeshtimin e procesit të krijimit të operatorëve për Kubernetes dhe tregon se si mund ta bëni vetë me përpjekje minimale duke përdorur një operator guaskë.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

duke prezantuar video e raportit (~23 minuta në anglisht, dukshëm më informues se artikulli) dhe ekstrakti kryesor prej tij në formë teksti. Shkoni!

Në Flant ne vazhdimisht optimizojmë dhe automatizojmë gjithçka. Sot do të flasim për një koncept tjetër emocionues. Takohen: skriptimi i guaskës së brendshme në renë kompjuterike!

Megjithatë, le të fillojmë me kontekstin në të cilin ndodh e gjithë kjo: Kubernetes.

Kubernetes API dhe kontrollorët

API në Kubernetes mund të përfaqësohet si një lloj serveri skedarësh me direktori për çdo lloj objekti. Objektet (burimet) në këtë server përfaqësohen nga skedarët YAML. Përveç kësaj, serveri ka një API bazë që ju lejon të bëni tre gjëra:

  • marr burimi sipas llojit dhe emrit të tij;
  • ndryshim burimi (në këtë rast, serveri ruan vetëm objekte "korrekte" - të gjitha ato të formuara gabimisht ose të destinuara për drejtoritë e tjera janë hedhur poshtë);
  • udhë për burimin (në këtë rast, përdoruesi merr menjëherë versionin e tij aktual/të përditësuar).

Kështu, Kubernetes vepron si një lloj serveri skedarësh (për manifestet YAML) me tre metoda themelore (po, në fakt ka të tjera, por ne do t'i heqim ato për momentin).

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Problemi është se serveri mund të ruajë vetëm informacione. Për ta bërë atë të funksionojë ju duhet kontrollues - koncepti i dytë më i rëndësishëm dhe themelor në botën e Kubernetes.

Ekzistojnë dy lloje kryesore të kontrolluesve. I pari merr informacion nga Kubernetes, e përpunon atë sipas logjikës së mbivendosur dhe e kthen atë në K8. E dyta merr informacion nga Kubernetes, por, ndryshe nga lloji i parë, ndryshon gjendjen e disa burimeve të jashtme.

Le të hedhim një vështrim më të afërt në procesin e krijimit të një vendosjeje në Kubernetes:

  • Kontrolluesi i vendosjes (përfshirë në kube-controller-manager) merr informacion në lidhje me Deployment dhe krijon një ReplicaSet.
  • ReplicaSet krijon dy kopje (dy pods) bazuar në këtë informacion, por këto pods nuk janë planifikuar ende.
  • Planifikuesi planifikon pods dhe shton informacionin e nyjeve në YAML-të e tyre.
  • Kubelets bëjnë ndryshime në një burim të jashtëm (të themi Docker).

Pastaj e gjithë kjo sekuencë përsëritet në rend të kundërt: kubelet kontrollon kontejnerët, llogarit statusin e pod dhe e kthen atë. Kontrolluesi ReplicaSet merr statusin dhe përditëson gjendjen e grupit të kopjeve. E njëjta gjë ndodh me Deployment Controller dhe përdoruesi më në fund merr statusin e përditësuar (aktual).

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Shell-operator

Rezulton se Kubernetes bazohet në punën e përbashkët të kontrolluesve të ndryshëm (operatorët Kubernetes janë gjithashtu kontrollues). Shtrohet pyetja, si të krijoni operatorin tuaj me përpjekje minimale? Dhe këtu vjen në shpëtim ai që kemi zhvilluar shell-operator. Ai i lejon administratorët e sistemit të krijojnë deklaratat e tyre duke përdorur metoda të njohura.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Shembull i thjeshtë: kopjimi i sekreteve

Le të shohim një shembull të thjeshtë.

Le të themi se kemi një grup Kubernetes. Ka një hapësirë ​​emri default me disa sekrete mysecret. Përveç kësaj, ka hapësira të tjera emrash në grup. Disa prej tyre kanë një etiketë specifike të bashkangjitur me to. Qëllimi ynë është të kopjojmë Sekretin në hapësirat e emrave me një etiketë.

Detyra është e ndërlikuar nga fakti se hapësirat e reja të emrave mund të shfaqen në grup, dhe disa prej tyre mund të kenë këtë etiketë. Nga ana tjetër, kur etiketa fshihet, Sekreti gjithashtu duhet të fshihet. Përveç kësaj, vetë Sekreti mund të ndryshojë gjithashtu: në këtë rast, Sekreti i ri duhet të kopjohet në të gjitha hapësirat e emrave me etiketa. Nëse Sekreti fshihet aksidentalisht në ndonjë hapësirë ​​emri, operatori ynë duhet ta rivendosë atë menjëherë.

Tani që detyra është formuluar, është koha për të filluar zbatimin e saj duke përdorur operatorin shell. Por së pari ia vlen të thuash disa fjalë për vetë operatorin e guaskës.

Si funksionon operatori i guaskës

Ashtu si ngarkesat e tjera të punës në Kubernetes, operatori i guaskës funksionon në podin e vet. Në këtë pod në drejtori /hooks skedarët e ekzekutueshëm ruhen. Këto mund të jenë skripta në Bash, Python, Ruby, etj. Ne i quajmë skedarë të tillë të ekzekutueshëm grepa (grepa).

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Operatori i Shell abonohet në ngjarjet e Kubernetes dhe i drejton këto grepa në përgjigje të atyre ngjarjeve që na duhen.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Si e di operatori i guaskës se cilin grep duhet të ekzekutojë dhe kur? Çështja është se çdo goditje ka dy faza. Gjatë nisjes, operatori i guaskës ekzekuton të gjitha grepa me një argument --config Kjo është faza e konfigurimit. Dhe pas saj, grepa lëshohen në mënyrën normale - në përgjigje të ngjarjeve të cilave u janë bashkangjitur. Në rastin e fundit, grepi merr kontekstin lidhës (kontekst detyrues) - të dhëna në format JSON, për të cilat do të flasim më në detaje më poshtë.

Bërja e një operatori në Bash

Tani jemi gati për zbatim. Për ta bërë këtë, ne duhet të shkruajmë dy funksione (nga rruga, ne rekomandojmë biblioteka shell_lib, e cila thjeshton shumë shkrimin e grepave në Bash):

  • e para është e nevojshme për fazën e konfigurimit - shfaq kontekstin e lidhjes;
  • e dyta përmban logjikën kryesore të grepit.

#!/bin/bash

source /shell_lib.sh

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

function __main__() {
  # THE LOGIC
}

hook::run "$@"

Hapi tjetër është të vendosim se cilat objekte na duhen. Në rastin tonë, duhet të gjurmojmë:

  • sekret burim për ndryshime;
  • të gjitha hapësirat e emrave në grup, në mënyrë që të dini se cilat prej tyre kanë një etiketë të bashkangjitur;
  • synoni sekretet për të siguruar që ato të jenë të gjitha në sinkron me sekretin burimor.

Regjistrohu në burimin sekret

Konfigurimi i lidhjes për të është mjaft i thjeshtë. Ne tregojmë se jemi të interesuar për Secret me emrin mysecret në hapësirën e emrave default:

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga 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

Si rezultat, grepi do të aktivizohet kur të ndryshojë sekreti i burimit (src_secret) dhe merrni kontekstin e mëposhtëm detyrues:

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Siç mund ta shihni, ai përmban emrin dhe të gjithë objektin.

Mbajtja e gjurmëve të hapësirave të emrave

Tani duhet të abonoheni në hapësirat e emrave. Për ta bërë këtë, ne specifikojmë konfigurimin e mëposhtëm të lidhjes:

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

Siç mund ta shihni, një fushë e re është shfaqur në konfigurim me emrin jqFilter. Siç sugjeron edhe emri i tij, jqFilter filtron të gjitha informacionet e panevojshme dhe krijon një objekt të ri JSON me fushat që janë me interes për ne. Një goditje me një konfigurim të ngjashëm do të marrë kontekstin e mëposhtëm lidhës:

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Ai përmban një grup filterResults për çdo hapësirë ​​emri në grup. Variabli Boolean hasLabel tregon nëse një emërtim është i bashkangjitur në një hapësirë ​​të caktuar emri. Përzgjedhësi keepFullObjectsInMemory: false tregon se nuk ka nevojë të mbahen objekte të plota në kujtesë.

Ndjekja e sekreteve të objektivit

Ne abonojmë të gjitha Sekretet që kanë një shënim të specifikuar managed-secret: "yes" (këto janë objektivi ynë 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

Në këtë rast, jqFilter filtron të gjithë informacionin përveç hapësirës së emrave dhe parametrit resourceVersion. Parametri i fundit iu kalua shënimit kur krijoni sekretin: ju lejon të krahasoni versionet e sekreteve dhe t'i mbani ato të përditësuara.

Një goditje e konfiguruar në këtë mënyrë, kur të ekzekutohet, do të marrë tre kontekstet lidhëse të përshkruara më sipër. Ato mund të mendohen si një lloj fotografie (fotografi i çastit) grumbull.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Bazuar në të gjitha këto informacione, mund të zhvillohet një algoritëm bazë. Ai përsëritet në të gjitha hapësirat e emrave dhe:

  • nëse hasLabel çështjet true për hapësirën aktuale të emrave:
    • krahason sekretin global me atë lokal:
      • nëse janë të njëjta, nuk bën asgjë;
      • nëse ndryshojnë - ekzekuton kubectl replace ose create;
  • nëse hasLabel çështjet false për hapësirën aktuale të emrave:
    • sigurohet që Sekreti nuk është në hapësirën e emrit të dhënë:
      • nëse sekreti lokal është i pranishëm, fshijeni atë duke përdorur kubectl delete;
      • nëse sekreti lokal nuk zbulohet, ai nuk bën asgjë.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Zbatimi i algoritmit në Bash ju mund të shkarkoni në tonë depo me shembuj.

Kështu mundëm të krijonim një kontrollues të thjeshtë Kubernetes duke përdorur 35 rreshta të konfigurimit YAML dhe afërsisht të njëjtën sasi të kodit Bash! Detyra e operatorit të guaskës është t'i lidhë ato së bashku.

Sidoqoftë, kopjimi i sekreteve nuk është fusha e vetme e aplikimit të shërbimit. Këtu janë disa shembuj të tjerë për të treguar se çfarë është ai i aftë.

Shembulli 1: Bërja e ndryshimeve në ConfigMap

Le të shohim një vendosje të përbërë nga tre pods. Pods përdorin ConfigMap për të ruajtur disa konfigurime. Kur podet u lansuan, ConfigMap ishte në një gjendje të caktuar (le ta quajmë v.1). Prandaj, të gjitha pods përdorin këtë version të veçantë të ConfigMap.

Tani le të supozojmë se ConfigMap ka ndryshuar (v.2). Megjithatë, pods do të përdorin versionin e mëparshëm të ConfigMap (v.1):

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Si mund t'i bëj ata të kalojnë në ConfigMap-in e ri (v.2)? Përgjigja është e thjeshtë: përdorni një shabllon. Le të shtojmë një shënim kontrolli në seksion template Konfigurimet e vendosjes:

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Si rezultat, kjo shumë kontrolli do të regjistrohet në të gjitha pods dhe do të jetë e njëjtë me atë të Deployment. Tani ju vetëm duhet të përditësoni shënimin kur ndryshon ConfigMap. Dhe operatori i guaskës është i dobishëm në këtë rast. E tëra çfarë ju duhet të bëni është të programoni një goditje që do të regjistrohet në ConfigMap dhe do të përditësojë kontrollin.

Nëse përdoruesi bën ndryshime në ConfigMap, operatori i guaskës do t'i vërejë ato dhe do të rillogarisë shumën e kontrollit. Pas së cilës magjia e Kubernetes do të hyjë në lojë: orkestratori do të vrasë podin, do të krijojë një të re, do të presë që ajo të bëhet Ready, dhe kalon në tjetrin. Si rezultat, Deployment do të sinkronizohet dhe do të kalojë në versionin e ri të ConfigMap.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Shembulli 2: Puna me përkufizimet e burimeve të personalizuara

Siç e dini, Kubernetes ju lejon të krijoni lloje të personalizuara të objekteve. Për shembull, ju mund të krijoni lloj MysqlDatabase. Le të themi se ky lloj ka dy parametra të meta të dhënave: name и namespace.

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

Ne kemi një grup Kubernetes me hapësira të ndryshme emrash në të cilat mund të krijojmë baza të të dhënave MySQL. Në këtë rast shell-operator mund të përdoret për të gjurmuar burimet MysqlDatabase, duke i lidhur ato me serverin MySQL dhe duke sinkronizuar gjendjet e dëshiruara dhe të vëzhguara të grupit.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Shembulli 3: Monitorimi i Rrjetit Cluster

Siç e dini, përdorimi i ping është mënyra më e thjeshtë për të monitoruar një rrjet. Në këtë shembull do të tregojmë se si të zbatohet një monitorim i tillë duke përdorur operatorin e guaskës.

Para së gjithash, do t'ju duhet të abonoheni në nyjet. Operatori shell ka nevojë për emrin dhe adresën IP të secilës nyje. Me ndihmën e tyre, ai do t'i pingojë këto nyje.

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

Parametër executeHookOnEvent: [] parandalon funksionimin e grepit në përgjigje të ndonjë ngjarjeje (d.m.th., në përgjigje të ndryshimit, shtimit, fshirjes së nyjeve). Megjithatë, ai do të kandidojë (dhe përditësoni listën e nyjeve) I planifikuar - çdo minutë, siç përcaktohet nga fusha schedule.

Tani lind pyetja, si i dimë saktësisht problemet si humbja e paketave? Le t'i hedhim një sy kodit:

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
}

Ne përsërisim listën e nyjeve, marrim emrat e tyre dhe adresat IP, i bëjmë ping dhe i dërgojmë rezultatet te Prometheus. Operatori Shell mund të eksportojë metrikë te Prometheus, duke i ruajtur ato në një skedar të vendosur sipas shtegut të specifikuar në variablin e mjedisit $METRICS_PATH.

Ja kështu ju mund të krijoni një operator për monitorim të thjeshtë të rrjetit në një grup.

Mekanizmi i radhës

Ky artikull do të ishte i paplotë pa përshkruar një mekanizëm tjetër të rëndësishëm të integruar në operatorin e guaskës. Imagjinoni që ai ekzekuton një lloj goditjeje në përgjigje të një ngjarjeje në grup.

  • Çfarë ndodh nëse, në të njëjtën kohë, ndodh diçka në grup? nje me shume ngjarje?
  • A do të ekzekutojë operatori i guaskës një shembull tjetër të goditjes?
  • Po sikur, të themi, pesë ngjarje të ndodhin në grup menjëherë?
  • A do t'i përpunojë ato paralelisht operatori i guaskës?
  • Po në lidhje me burimet e konsumuara si memoria dhe CPU?

Për fat të mirë, operatori i guaskës ka një mekanizëm të integruar të radhës. Të gjitha ngjarjet janë në radhë dhe përpunohen në mënyrë sekuenciale.

Le ta ilustrojmë këtë me shembuj. Le të themi se kemi dy grepa. Ngjarja e parë shkon në goditjen e parë. Pasi të përfundojë përpunimi i tij, radha shkon përpara. Tre ngjarjet e ardhshme ridrejtohen në grepin e dytë - ato hiqen nga radha dhe futen në të në një "pako". Kjo eshte hook merr një sërë ngjarjesh - ose, më saktë, një sërë kontekstesh të detyrueshme.

Edhe këto ngjarjet mund të kombinohen në një të madhe. Parametri është përgjegjës për këtë group në konfigurimin e lidhjes.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Ju mund të krijoni çdo numër radhësh/grepash dhe kombinime të ndryshme të tyre. Për shembull, një radhë mund të funksionojë me dy grepa, ose anasjelltas.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

E tëra çfarë ju duhet të bëni është të konfiguroni fushën në përputhje me rrethanat queue në konfigurimin e lidhjes. Nëse emri i radhës nuk është specifikuar, grepa funksionon në radhën e paracaktuar (default). Ky mekanizëm i radhës ju lejon të zgjidhni plotësisht të gjitha problemet e menaxhimit të burimeve kur punoni me grepa.

Përfundim

Ne shpjeguam se çfarë është një operator guaskë, treguam se si mund të përdoret për të krijuar shpejt dhe pa mundim operatorë Kubernetes dhe dhamë disa shembuj të përdorimit të tij.

Informacioni i detajuar rreth operatorit të guaskës, si dhe një tutorial i shpejtë se si ta përdorni atë, janë në dispozicion në përkatësin depo në GitHub. Mos hezitoni të na kontaktoni me pyetje: ju mund t'i diskutoni ato në një speciale Grupi i telegramit (në rusisht) ose në ky forum (në Anglisht).

Dhe nëse ju pëlqeu, ne jemi gjithmonë të lumtur të shohim çështje të reja/PR/yje në GitHub, ku, meqë ra fjala, mund të gjeni të tjera projekte interesante. Midis tyre vlen të theksohet shtesë-operator, i cili është vëllai i madh i operatorit të guaskës. Ky mjet përdor diagramet Helm për të instaluar shtesa, mund të japë përditësime dhe të monitorojë parametra/vlera të ndryshme të grafikut, kontrollon procesin e instalimit të grafikëve dhe gjithashtu mund t'i modifikojë ato në përgjigje të ngjarjeve në grup.

Shkoni? Bash! Takoni operatorin e guaskës (rishikim dhe raport video nga KubeCon EU'2020)

Video dhe sllajde

Video nga performanca (~23 minuta):


Prezantimi i raportit:

PS

Lexoni edhe në blogun tonë:

Burimi: www.habr.com

Shto një koment