Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Dëst Joer war déi wichtegst europäesch Kubernetes Konferenz - KubeCon + CloudNativeCon Europe 2020 - virtuell. Esou eng Ännerung vum Format huet eis awer net verhënnert eise laang geplangte Bericht „Go? Bash! Trefft de Shell-Bedreiwer" gewidmet fir eisen Open Source Projet Shell-Operateur.

Dësen Artikel, inspiréiert vum Gespréich, stellt eng Approche fir de Prozess ze vereinfachen fir Bedreiwer fir Kubernetes ze kreéieren a weist wéi Dir Äert eegent mat minimalem Effort mat engem Shell-Bedreiwer maache kënnt.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Aféierung Video vum Bericht (~ 23 Minutten op Englesch, merkbar méi informativ wéi den Artikel) an den Haaptextrakt dovun an Textform. Gitt!

Bei Flant optimiséieren an automatiséieren mir permanent alles. Haut wäerte mir iwwer en anert spannend Konzept schwätzen. Treffen: Cloud-native Shell Scripting!

Fänke mer awer mam Kontext un, an deem dat alles geschitt: Kubernetes.

Kubernetes API a Controller

D'API zu Kubernetes kann als eng Zort Dateiserver mat Verzeichnisser fir all Typ vun Objet duergestallt ginn. Objekter (Ressourcen) op dësem Server ginn duerch YAML Dateien vertruede. Zousätzlech huet de Server eng Basis API déi Iech erlaabt dräi Saachen ze maachen:

  • kréien Ressource duerch seng Aart an Numm;
  • änneren Ressource (an dësem Fall späichert de Server nëmmen "korrekt" Objeten - all falsch geformt oder geduecht fir aner Verzeichnisser ginn verworf);
  • Streck fir d'Ressource (an dësem Fall kritt de Benotzer direkt seng aktuell/aktualiséiert Versioun).

Sou Akten Kubernetes als eng Zort Fichier Server (fir YAML Manifestatiounen) mat dräi Basis Methoden (jo, eigentlech ginn et anerer, mä mir wäerten se fir de Moment ewech).

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

De Problem ass datt de Server nëmmen Informatioun späichere kann. Fir et ze schaffen braucht Dir Controller - dat zweet wichtegst a fundamentalt Konzept an der Welt vu Kubernetes.

Et ginn zwou Haaptarten vu Controller. Déi éischt hëlt Informatioun vu Kubernetes, veraarbecht se no nested Logik, a bréngt se zréck op K8s. Déi zweet hëlt Informatioun vu Kubernetes, awer, am Géigesaz zum éischten Typ, ännert den Zoustand vun e puer externe Ressourcen.

Loosst eis de Prozess méi no kucken fir en Deployment a Kubernetes ze kreéieren:

  • Deployment Controller (abegraff an kube-controller-manager) kritt Informatioun iwwer Deployment a kreéiert e ReplicaSet.
  • ReplicaSet kreéiert zwee Repliken (zwee Pods) baséiert op dëser Informatioun, awer dës Pods sinn nach net geplangt.
  • De Scheduler plangt Pods a füügt Nodeinformatioun un hir YAMLs.
  • Kubelets maachen Ännerungen op eng extern Ressource (soen Docker).

Da gëtt dës ganz Sequenz an ëmgedréint Uerdnung widderholl: de Kubelet kontrolléiert d'Container, berechent de Status vum Pod a schéckt se zréck. De ReplicaSet Controller kritt de Status an aktualiséiert den Zoustand vum Replica Set. Datselwecht geschitt mam Deployment Controller an de Benotzer kritt endlech den aktualiséierten (aktuelle) Status.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Shell-Operateur

Et stellt sech eraus datt Kubernetes op der gemeinsamer Aarbecht vu verschiddene Controller baséiert (Kubernetes Bedreiwer sinn och Controller). D'Fro stellt sech, wéi Dir Ären eegene Bedreiwer mat minimalem Effort erstellt? An hei kënnt deen deen mir entwéckelt hunn zur Rettung Shell-Operateur. Et erlaabt Systemadministratoren hir eege Aussoe mat vertraute Methoden ze kreéieren.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Einfach Beispill: Geheimnisser kopéieren

Loosst eis en einfacht Beispill kucken.

Loosst eis soen datt mir e Kubernetes Cluster hunn. Et huet en Nummraum default mat e puer Geheimnis mysecret. Zousätzlech ginn et aner Nummraim am Cluster. E puer vun hinnen hunn e spezifesche Label verbonnen. Eist Zil ass Secret an Nummraim mat engem Label ze kopéieren.

D'Aufgab ass komplizéiert vun der Tatsaach, datt nei Nummraim am Stärekoup erschéngen, an e puer vun hinnen kënnen dëse Label hunn. Op der anerer Säit, wann de Label geläscht gëtt, sollt Secret och geläscht ginn. Zousätzlech kann d'Geheimnis selwer och änneren: an dësem Fall muss deen neie Geheimnis op all Nummraim mat Etiketten kopéiert ginn. Wann Secret zoufälleg an engem Nummraum geläscht gëtt, soll eise Bedreiwer et direkt restauréieren.

Elo datt d'Aufgab formuléiert ass, ass et Zäit et mat der Shell-Bedreiwer ze implementéieren. Awer als éischt ass et derwäert e puer Wierder iwwer de Shell-Bedreiwer selwer ze soen.

Wéi Shell-Bedreiwer funktionnéiert

Wéi aner Aarbechtsbelaaschtungen a Kubernetes, leeft de Shell-Bedreiwer a sengem eegene Pod. An dësem Pod am Verzeechnes /hooks ausführbar Dateie gespäichert ginn. Dëst kënne Skripte a Bash, Python, Ruby, etc. Mir nennen esou ausféierbar Dateien Haken (erlaabt).

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Shell-Operateur abonnéiert op Kubernetes Eventer a leeft dës Haken als Äntwert op déi Eventer déi mir brauchen.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Wéi weess de Shell-Bedreiwer wéi en Hook ze lafen a wéini? De Punkt ass datt all Haken zwou Etappen huet. Wärend dem Startup leeft de Shell-Bedreiwer all Haken mat engem Argument --config Dëst ass d'Konfiguratiounsphase. An duerno ginn Haken op déi normal Manéier lancéiert - als Äntwert op d'Evenementer, op déi se verbonne sinn. Am leschte Fall kritt den Haken de bindende Kontext (verbindlechen Kontext) - Daten am JSON-Format, iwwer déi mir hei ënnen méi detailléiert schwätzen.

Maachen en Bedreiwer zu Bash

Elo si mir prett fir d'Ëmsetzung. Fir dëst ze maachen, musse mir zwou Funktiounen schreiwen (iwwregens, mir recommandéieren Bibliothéik shell_lib, wat d'Schreifhaken am Bash immens vereinfacht):

  • déi éischt ass néideg fir d'Konfiguratiounsstadium - et weist de bindende Kontext;
  • déi zweet enthält d'Haaptlogik vum Haken.

#!/bin/bash

source /shell_lib.sh

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

function __main__() {
  # THE LOGIC
}

hook::run "$@"

De nächste Schrëtt ass ze entscheeden wat fir Objete mir brauchen. An eisem Fall musse mir verfollegen:

  • Quell geheim fir Ännerungen;
  • all Nummraim am Stärekoup, fir datt Dir wësst op wéi engen e Label verbonnen ass;
  • Zilgeheimnisser fir sécherzestellen datt se all mat der Quellgeheimnis synchroniséiert sinn.

Abonnéiert Iech op déi geheim Quell

Bindungskonfiguratioun dofir ass ganz einfach. Mir weisen datt mir un Secret mam Numm interesséiert sinn mysecret am Nummraum default:

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu 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

Als Resultat gëtt den Hook ausgeléist wann d'Quellgeheimnis ännert (src_secret) a kritt de folgende verbindleche Kontext:

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Wéi Dir gesitt, enthält et den Numm an de ganzen Objet.

Verfollegt Nummraim

Elo musst Dir op Nummraim abonnéieren. Fir dëst ze maachen, spezifizéiere mir déi folgend verbindlech Konfiguratioun:

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

Wéi Dir gesitt, ass en neit Feld an der Konfiguratioun mam Numm opgetaucht jqFilter. Wéi säin Numm et scho seet, jqFilter filtert all onnéideg Informatioun aus a schafft en neien JSON-Objet mat de Felder déi eis interesséieren. En Haken mat enger ähnlecher Konfiguratioun kritt de folgende verbindleche Kontext:

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Et enthält eng Array filterResults fir all Nummraum am Cluster. Boolean Variabel hasLabel weist ob e Label un engem bestëmmte Nummraum befestegt ass. Wieler keepFullObjectsInMemory: false weist datt et net néideg ass komplett Objeten an der Erënnerung ze halen.

Tracking Zil Geheimnisser

Mir abonnéieren op all Geheimnisser déi eng Annotatioun uginn hunn managed-secret: "yes" (dëst sinn eist Zil 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

An dësem Fall jqFilter filtert all Informatioun ausser den Nummraum an de Parameter resourceVersion. De leschte Parameter gouf un d'Annotatioun iwwerginn wann Dir de Geheimnis erstallt: et erlaabt Iech Versioune vu Geheimnisser ze vergläichen an se um neiste Stand ze halen.

En Hook, dee sou konfiguréiert ass, kritt, wann se ausgefouert gëtt, déi dräi verbindlech Kontexter déi hei uewen beschriwwe ginn. Si kënnen als eng Aart Snapshot geduecht ginn (Snapshot) Cluster.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Baséierend op all dës Informatioun kann e Basisalgorithmus entwéckelt ginn. Et iteréiert iwwer all Nummraim an:

  • wann hasLabel Themen true fir den aktuellen Nummraum:
    • vergläicht de globale Geheimnis mam lokalen:
      • wa se d'selwecht sinn, mécht et näischt;
      • wa se ënnerscheeden - executéiert kubectl replace oder create;
  • wann hasLabel Themen false fir den aktuellen Nummraum:
    • mécht sécher datt Secret net am gegebenen Nummraum ass:
      • wann d'lokal Secret präsent ass, läschen et benotzt kubectl delete;
      • wann de lokale Geheimnis net entdeckt gëtt, mécht et näischt.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Ëmsetzung vum Algorithmus zu Bash Dir kënnt an eiser download Repositories mat Beispiller.

Dat ass wéi mir konnten en einfachen Kubernetes Controller erstellen mat 35 Linnen vun YAML Config an ongeféier déiselwecht Quantitéit vum Bash Code! D'Aarbecht vum Shell-Operateur ass se mateneen ze verbannen.

Wéi och ëmmer, Geheimnisse kopéieren ass net dat eenzegt Gebitt vun der Uwendung vum Utility. Hei sinn e puer méi Beispiller fir ze weisen wat hien fäeg ass.

Beispill 1: Ännerungen op ConfigMap maachen

Loosst eis eng Deployment kucken, déi aus dräi Pods besteet. Pods benotzen ConfigMap fir eng Konfiguratioun ze späicheren. Wann d'Pods lancéiert goufen, war ConfigMap an engem bestëmmten Zoustand (loosst eis et v.1 nennen). Deementspriechend benotzen all Pods dës speziell Versioun vu ConfigMap.

Loosst eis elo unhuelen datt de ConfigMap geännert huet (v.2). Wéi och ëmmer, d'Pods benotzen déi fréier Versioun vu ConfigMap (v.1):

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Wéi kann ech se kréien op déi nei ConfigMap (v.2) ze wiesselen? D'Äntwert ass einfach: Benotzt eng Schabloun. Loosst eis eng Checksum Annotatioun an d'Sektioun addéieren template Installatiounskonfiguratiounen:

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Als Resultat gëtt dës Checksum an all Pods registréiert, an et wäert d'selwecht sinn wéi dee vum Deployment. Elo musst Dir just d'Annotatioun aktualiséieren wann d'ConfigMap ännert. An de Shell-Bedreiwer kënnt an dësem Fall praktesch. Alles wat Dir maache musst ass ze programméieren en Hook deen de ConfigMap abonnéiert an d'Checksum aktualiséieren.

Wann de Benotzer Ännerungen un der ConfigMap mécht, wäert de Shell-Bedreiwer se bemierken an d'Kontrollsum nei berechnen. Duerno wäert d'Magie vu Kubernetes an d'Spill kommen: den Orchester wäert de Pod ëmbréngen, en neien erstellen, waart bis et gëtt Ready, a geet op déi nächst. Als Resultat wäert Deployment synchroniséieren a wiesselen op déi nei Versioun vu ConfigMap.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Beispill 2: Schafft mat Benotzerdefinéiert Ressource Definitiounen

Wéi Dir wësst, erlaabt Kubernetes Iech personaliséiert Aarte vun Objeten ze kreéieren. Zum Beispill kënnt Dir Aart kreéieren MysqlDatabase. Loosst eis soen datt dësen Typ zwee Metadatenparameter huet: name и namespace.

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

Mir hunn e Kubernetes Cluster mat verschiddenen Nummraim, an deenen mir MySQL Datenbanken erstellen kënnen. An dësem Fall kann Shell-Bedreiwer benotzt ginn fir Ressourcen ze verfolgen MysqlDatabase, se mat dem MySQL-Server ze verbannen an d'gewënscht an observéiert Staate vum Cluster ze synchroniséieren.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Beispill 3: Cluster Network Iwwerwachung

Wéi Dir wësst, Ping benotzen ass den einfachste Wee fir en Netzwierk ze iwwerwaachen. An dësem Beispill wäerte mir weisen wéi sou eng Iwwerwaachung mam Shell-Bedreiwer ëmgesat gëtt.

Als éischt musst Dir op Noden abonnéieren. De Shelloperateur brauch den Numm an d'IP Adress vun all Node. Mat hirer Hëllef wäert hien dës Noden pingelen.

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

Parameter executeHookOnEvent: [] verhënnert datt den Hook als Äntwert op all Event leeft (dat ass, als Äntwert op d'Ännerung, d'Addéieren, d'Läschen vun Noden). Allerdéngs huet hien wäert lafen (an update d'Lëscht vun den Noden) Geplangt - all Minutt, wéi vum Terrain virgeschriwwen schedule.

Elo stellt sech d'Fro, wéi genau wësse mir iwwer Probleemer wéi Paketverloscht? Loosst eis de Code kucken:

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
}

Mir iteréieren duerch d'Lëscht vun den Noden, kréien hir Nimm an IP Adressen, ping se a schécken d'Resultater op Prometheus. Shell-Operateur kann Metriken op Prometheus exportéieren, späichert se an e Fichier deen no dem Wee an der Ëmfeldvariabel spezifizéiert ass $METRICS_PATH.

Hei ass esou Dir kënnt en Bedreiwer maachen fir einfach Netzwierk Iwwerwaachung an engem Cluster.

Schlaang Mechanismus

Dësen Artikel wier onkomplett ouni en anere wichtege Mechanismus ze beschreiwen, deen an de Shell-Bedreiwer gebaut ass. Stellt Iech vir datt et eng Aart Hook ausféiert als Äntwert op en Event am Cluster.

  • Wat geschitt wann gläichzäiteg eppes am Cluster geschitt? ee méi event?
  • Wäert Shell-Bedreiwer eng aner Instanz vum Haken lafen?
  • Wat wann, soen, fënnef Evenementer op eemol am Stärekoup geschéien?
  • Wäert de Shell-Bedreiwer se parallel veraarbecht?
  • Wat iwwer verbrauchte Ressourcen wéi Erënnerung an CPU?

Glécklecherweis huet Shell-Bedreiwer en agebaute Schlaangmechanismus. All Eventer ginn an der Schlaang a sequenziell veraarbecht.

Loosst eis dat mat Beispiller illustréieren. Loosst eis soen datt mir zwee Haken hunn. Dat éischt Evenement geet op den éischten Hook. Wann seng Veraarbechtung fäerdeg ass, geet d'Schlaang no vir. Déi nächst dräi Eventer ginn op den zweeten Hook ëmgeleet - si ginn aus der Schlaang geläscht an an engem "Bündel" aginn. Dat ass Hook kritt eng ganz Rëtsch vun Eventer - oder, méi präzis, eng Rei vu verbindleche Kontexter.

Och dës Evenementer kënnen an eng grouss kombinéiert ginn. De Parameter ass dofir verantwortlech group an der verbindlecher Konfiguratioun.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Dir kënnt all Zuel vu Schlaangen / Haken an hir verschidde Kombinatioune erstellen. Zum Beispill kann eng Schlaang mat zwee Haken schaffen, oder vice versa.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Alles wat Dir maache musst ass d'Feld entspriechend ze konfiguréieren queue an der verbindlecher Konfiguratioun. Wann e Schlaangnumm net uginn ass, leeft den Hook op der Standardschlaang (default). Dëse Schlaangmechanismus erlaabt Iech all Ressourceverwaltungsproblemer komplett ze léisen wann Dir mat Haken schafft.

Konklusioun

Mir hunn erkläert wat e Shell-Operateur ass, gewisen wéi et ka benotzt ginn fir séier an ouni Ustrengung Kubernetes Bedreiwer ze kreéieren, an hunn e puer Beispiller vu senger Benotzung ginn.

Detailléiert Informatioun iwwer de Shell-Bedreiwer, wéi och e séieren Tutorial iwwer wéi Dir et benotzt, ass verfügbar an der entspriechender Repositories op GitHub. Zéckt net eis mat Froen ze kontaktéieren: Dir kënnt se an engem speziellen diskutéieren Telegram Grupp (op Russesch) oder an dësem Forum (op Englesch).

A wann Dir et gefall hutt, si mir ëmmer frou nei Emissiounen / PR / Stären op GitHub ze gesinn, wou Dir iwwregens anerer fannt interessant Projeten. Ënnert hinnen ass et derwäert ze markéieren addon-Operateur, wat de grousse Brudder vum Shell-Operateur ass. Dës Utility benotzt Helm Charts fir Add-ons z'installéieren, kann Updates liwweren a verschidde Diagrammparameter / Wäerter iwwerwaachen, kontrolléiert den Installatiounsprozess vun Charts, a kann se och änneren an Äntwert op Eventer am Cluster.

Gitt? Bash! Trefft de Shell-Bedreiwer (Iwwerpréiwung a Videobericht vu KubeCon EU'2020)

Videoen a Rutschen

Video vun der Leeschtung (~23 Minutten):


Presentatioun vum Rapport:

PS

Liest och op eisem Blog:

Source: will.com

Setzt e Commentaire