ProHoster > Blog > Amministrazione > Vai? Bash! Incuntrà l'operatore di shell (revisione è video rapportu da KubeCon EU'2020)
Vai? Bash! Incuntrà l'operatore di shell (revisione è video rapportu da KubeCon EU'2020)
Quist'annu, a principale cunferenza europea di Kubernetes - KubeCon + CloudNativeCon Europe 2020 - era virtuale. Tuttavia, un tali cambiamentu di furmatu ùn ci hà impeditu di purtà u nostru rapportu longu pianificatu "Vai? Bash! Meet the Shell-operator" dedicatu à u nostru prughjettu Open Source shell-operatore.
Questu articulu, ispiratu da a discussione, presenta un approcciu per simplificà u prucessu di creazione di l'operatori per Kubernetes è mostra cumu pudete fà u vostru propiu cù u minimu sforzu cù un operatore di shell.
Introducendu video di u rapportu (~ 23 minuti in inglese, notevolmente più informattivu cà l'articulu) è l'estrattu principale da ellu in forma di testu. Vai !
À Flant ottimisimu constantemente è automatizemu tuttu. Oghje avemu da parlà di un altru cuncettu passiunanti. Incontru: scripting shell nativu di nuvola!
In ogni casu, cuminciamu cù u cuntestu in quale tuttu questu succede: Kubernetes.
API Kubernetes è controllers
L'API in Kubernetes pò esse rapprisintatu cum'è un tipu di servitore di file cù repertorii per ogni tipu d'ughjettu. L'uggetti (risorse) in stu servitore sò rapprisintati da i schedari YAML. Inoltre, u servitore hà una API basica chì vi permette di fà trè cose:
uttene risorsa per u so tipu è u nome;
cambià risorsa (in questu casu, u servitore guarda solu l'uggetti "corretti" - tutti i formati incorrectamente o destinati à altri cartulari sò scartati);
pista per a risorsa (in questu casu, l'utilizatore riceve immediatamente a so versione attuale / aghjurnata).
Cusì, Kubernetes agisce cum'è un tipu di servitore di file (per manifesti YAML) cù trè metudi basi (sì, in realtà ci sò altri, ma l'avemu omessi per avà).
U prublema hè chì u servitore pò almacenà solu l'infurmazioni. Per fà u travagliu avete bisognu controller - u sicondu cuncettu più impurtante è fundamentale in u mondu di Kubernetes.
Ci sò dui tippi principali di cuntrolli. U primu piglia l'infurmazioni da Kubernetes, u processa secondu a logica nidificata, è torna à K8s. U sicondu pigghia infurmazione da Kubernetes, ma, à u cuntrariu di u primu tipu, cambia u statu di qualchi risorse esterni.
Fighjemu un ochju più vicinu à u prucessu di creazione di una implementazione in Kubernetes:
Controller di implementazione (cumpresu in kube-controller-manager) riceve infurmazione nantu à u Deployment è crea un ReplicaSet.
ReplicaSet crea duie rèpliche (dui pods) basatu annantu à questa infurmazione, ma sti pods ùn sò micca pianificati.
U pianificatore pianifica pods è aghjunghje infurmazioni di nodu à i so YAML.
Kubelets facenu cambiamenti à una risorsa esterna (dice Docker).
Allora sta sequenza sana hè ripetuta in l'ordine inversu: u kubelet cuntrolla i cuntenituri, calcula l'estatus di u pod è rinvia. U controller ReplicaSet riceve u statutu è aghjurnà u statu di u set di replica. A listessa cosa succede cù u Controller di Deployment è l'utilizatore finalmente riceve u statu aghjurnatu (attuali).
Shell-operatore
Ci hè chì Kubernetes hè basatu annantu à u travagliu cumunu di diversi controllers (l'operatori di Kubernetes sò ancu cuntrolli). A quistione sorge, cumu creà u vostru propiu operatore cù u minimu sforzu? È quì quellu chì avemu sviluppatu vene in salvezza shell-operatore. Permette à l'amministratori di u sistema di creà e so propiu dichjarazioni cù metudi familiari.
Esempiu simplice: cupià i sicreti
Fighjemu un esempiu simplice.
Diciamu chì avemu un cluster Kubernetes. Havi un spaziu di nomi default cù qualchi Secret mysecret. Inoltre, ci sò altri spazii di nomi in u cluster. Certi di elli anu una etichetta specifica attaccata à elli. U nostru scopu hè di copià Secret in namespaces cù una etichetta.
U compitu hè cumplicatu da u fattu chì i novi spazii di nomi ponu appare in u cluster, è alcuni di elli ponu avè sta etichetta. Per d 'altra banda, quandu l'etichetta hè sguassata, Secret deve esse ancu eliminata. In più di questu, u Secretu stessu pò ancu cambià: in questu casu, u novu Secret deve esse copiatu in tutti i spazii di nomi cù etichette. Se Secret hè sguassatu accidintali in ogni spaziu di nomi, u nostru operatore deve restaurà immediatamente.
Avà chì u compitu hè statu formulatu, hè ora di cumincià à implementà cù l'operatore di shell. Ma prima vale a pena dì uni pochi di parolle nantu à l'operatore di shell stessu.
Cumu funziona l'operatore di shell
Cum'è l'altri carichi di travagliu in Kubernetes, l'operatore di shell funziona in u so propiu pod. In questu pod in u cartulare /hooks i fugliali eseguibili sò almacenati. Questi ponu esse script in Bash, Python, Ruby, etc. Chjamemu tali file eseguibili ganci (anziani).
L'operatore Shell si abbona à l'avvenimenti Kubernetes è eseguisce questi ganci in risposta à quelli avvenimenti chì avemu bisognu.
Cumu l'operatore di shell sapi quale ganciu per eseguisce è quandu? U puntu hè chì ogni ganciu hà duie tappe. Durante l'iniziu, l'operatore di shell esegue tutti i ganci cù un argumentu --config Questu hè u stadiu di cunfigurazione. E dopu, i ganci sò lanciati in modu normale - in risposta à l'avvenimenti à quale sò attaccati. In l'ultimu casu, u ganciu riceve u cuntestu di ubligatoriu (cuntestu ubligatoriu) - dati in u formatu JSON, chì avemu da parlà in più detail sottu.
Fà un operatore in Bash
Avà simu pronti per l'implementazione. Per fà questu, avemu bisognu di scrive duie funzioni (per via, ricumandemu a biblioteca shell_lib, chì simplifica assai i ganci di scrittura in Bash):
u primu hè necessariu per a tappa di cunfigurazione - mostra u cuntestu di ubligatoriu;
u sicondu cuntene a logica principale di u ganciu.
#!/bin/bash
source /shell_lib.sh
function __config__() {
cat << EOF
configVersion: v1
# BINDING CONFIGURATION
EOF
}
function __main__() {
# THE LOGIC
}
hook::run "$@"
U prossimu passu hè di decide chì l'uggetti avemu bisognu. In u nostru casu, avemu bisognu di seguità:
sicretu fonte per i cambiamenti;
tutti i namespaces in u cluster, cusì chì sapete quale anu una etichetta attaccata à elli;
sicreti di destinazione per assicurà chì sò tutti in sincronia cù u sicretu fonte.
Abbonate à a fonte secreta
A cunfigurazione di ubligatoriu per questu hè abbastanza simplice. Indichemu chì avemu interessatu in Secret cù u nome mysecret in namespace default:
Comu pudete vede, un novu campu hè apparsu in a cunfigurazione cù u nome jqFilter. Cum'è u so nome suggerisce, jqFilter filtra tutte l'infurmazioni innecessarii è crea un novu oggettu JSON cù i campi chì sò d'interessu per noi. Un ganciu cù una cunfigurazione simili riceverà u cuntestu di ubligatoriu seguente:
Contene un array filterResults per ogni namespace in u cluster. Variabile booleana hasLabel indica se una etichetta hè attaccata à un spaziu di nome datu. Selettore keepFullObjectsInMemory: false indica chì ùn ci hè bisognu di mantene l'uggetti cumpleti in memoria.
Segui i secreti di destinazione
Avemu sottumessi à tutti i Secrets chì anu una annotazione specifica managed-secret: "yes" (questi sò u nostru scopu dst_secrets):
In questu casu jqFilter filtra tutte l'infurmazioni eccettu u namespace è u paràmetru resourceVersion. L'ultimu paràmetru hè passatu à l'annotazione quandu crea u sicretu: permette di paragunà e versioni di sicreti è mantene a data.
Un ganciu cunfiguratu in questu modu riceverà, quandu eseguitu, i trè cuntesti di ubligatoriu descritti sopra. Puderanu esse pensati cum'è una spezia di snapshot (una snapshot) cluster.
Basatu nantu à tutte queste informazioni, un algoritmu di basa pò esse sviluppatu. Itera in tutti i spazii di nomi è:
si hasLabel tràttanu true per u spaziu di nomi attuale:
compara u sicretu glubale cù u lucale:
s'elli sò listessi, ùn faci nunda;
si sò diffirenti - eseguisce kubectl replace o create;
si hasLabel tràttanu false per u spaziu di nomi attuale:
assicura chì Secret ùn hè micca in u namespace datu:
se u Sicretu lucale hè presente, sguassate u usu kubectl delete;
se u Sicretu lucale ùn hè micca rilevatu, ùn face nunda.
Hè cusì chì pudemu creà un semplice controller Kubernetes usendu 35 linee di cunfigurazione YAML è circa a stessa quantità di codice Bash! U travagliu di l'operatore di shell hè di ligà inseme.
Tuttavia, a copia di i secreti ùn hè micca l'unicu spaziu di applicazione di l'utilità. Eccu uni pochi di più esempi per dimustrà ciò ch'ellu hè capaci di fà.
Esempiu 1: Fà cambiamenti à ConfigMap
Fighjemu un Implantamentu custituitu di trè pods. I pods utilizanu ConfigMap per almacenà una certa cunfigurazione. Quandu i pods sò stati lanciati, ConfigMap era in un certu statu (chjamemu v.1). Per quessa, tutti i pods usanu sta versione particulare di ConfigMap.
Avà assumemu chì u ConfigMap hà cambiatu (v.2). Tuttavia, i pods utilizanu a versione precedente di ConfigMap (v.1):
Cumu possu fà passà à u novu ConfigMap (v.2) ? A risposta hè simplice: utilizate un mudellu. Aghjunghjemu una annotazione di checksum à a sezione template Configurazioni di implementazione:
In u risultatu, questu checksum serà registratu in tutti i pods, è serà u listessu cum'è quellu di Deployment. Avà basta à aghjurnà l'annotazione quandu u ConfigMap cambia. È l'operatore di shell hè utile in questu casu. Tuttu ciò chì duvete fà hè u prugramma un ganciu chì abbonarà à u ConfigMap è aghjurnà u checksum.
Se l'utilizatore face cambiamenti à u ConfigMap, l'operatore di shell li noterà è ricalcolerà u checksum. Dopu chì a magia di Kubernetes entrerà in ghjocu: l'orchestratore ucciderà u pod, creà un novu, aspittà chì diventerà. Ready, è passa à u prossimu. In u risultatu, Deployment sincronizà è passà à a nova versione di ConfigMap.
Esempiu 2: U travagliu cù Definizioni di Risorse Personalizzate
Comu sapete, Kubernetes permette di creà tipi d'oggetti persunalizati. Per esempiu, pudete creà tipu MysqlDatabase. Diciamu chì stu tipu hà dui parametri di metadata: name и namespace.
apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
name: foo
namespace: bar
Avemu un cluster Kubernetes cù spazii di nomi diffirenti in quale pudemu creà basa di dati MySQL. In questu casu, l'operatore di shell pò esse usatu per seguità e risorse MysqlDatabase, cunnessendu à u servitore MySQL è sincronizà i stati desiderati è osservati di u cluster.
Esempiu 3: Monitoring Network Cluster
Comu sapete, l'usu di ping hè u modu più simplice di monitorà una reta. In questu esempiu, mostreremu cumu implementà un tali monitoraghju cù l'operatore di shell.
Prima di tuttu, vi tuccherà à subscribe à nodes. L'operatore di shell hà bisognu di u nome è l'indirizzu IP di ogni node. Cù u so aiutu, farà ping sti nodi.
Parameter executeHookOnEvent: [] impedisce à u ganciu di eseguisce in risposta à qualsiasi avvenimentu (vale à dì, in risposta à cambià, aghjunghje, sguassà nodi). Tuttavia, ellu correrà (è aghjurnà a lista di i nodi) Pianificatu - ogni minutu, cum'è prescrittu da u campu schedule.
Avà hè a quistione, cumu esattamente sapemu di prublemi cum'è a perdita di pacchetti? Fighjemu un ochju à u codice:
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
}
Iteremu à traversu a lista di nodi, uttene i so nomi è l'indirizzi IP, ping è mandate i risultati à Prometheus. L'operatore Shell pò esportà metriche à Prometheus, salvendu in un schedariu situatu secondu u percorsu specificatu in a variabile d'ambiente $METRICS_PATH.
Eccu accussì pudete fà un operatore per un seguimentu simplice di a rete in un cluster.
Meccanisimu di fila
Questu articulu ùn saria micca cumpletu senza discrive un altru mecanismu impurtante integratu in l'operatore di shell. Imagine chì eseguisce un tipu di ganciu in risposta à un avvenimentu in u cluster.
Chì succede se, à u stessu tempu, qualcosa succede in u cluster? unu di più avvenimentu?
L'operatore di shell eseguirà un'altra istanza di u ganciu?
E se, per dì, cinque avvenimenti accadenu in u cluster à una volta?
L'operatore di shell li processerà in parallelu ?
E risorse cunsumate cum'è memoria è CPU?
Fortunatamente, l'operatore di shell hà un mecanismu di fila integratu. Tutti l'avvenimenti sò in fila è processati in sequenza.
Illustremu questu cù esempi. Diciamu chì avemu dui ganci. U primu avvenimentu va à u primu ganciu. Quandu u so prucessu hè cumpletu, a fila avanza. I prossimi trè avvenimenti sò ridiretti à u sicondu ganciu - sò sguassati da a fila è intruti in questu in un "bundle". Hè ganciu riceve una serie di avvenimenti - o, più precisamente, una serie di cuntesti vincolanti.
Ancu questi l'avvenimenti ponu esse cumminati in un grande. U paràmetru hè rispunsevule per questu group in a cunfigurazione di ubligatoriu.
Pudete creà ogni quantità di fila / ganci è e so diverse cumminazzioni. Per esempiu, una fila pò travaglià cù dui ganci, o viceversa.
Tuttu ciò chì duvete fà hè cunfigurà u campu in cunseguenza queue in a cunfigurazione di ubligatoriu. Se un nome di fila ùn hè micca specificatu, u ganciu corre nantu à a fila predeterminata (default). Stu mecanismu di fila permette di risolve cumplettamente tutti i prublemi di gestione di risorse quandu travagliate cù ganci.
cunchiusioni
Avemu spiegatu ciò chì hè un operatore di shell, hà dimustratu cumu pò esse usatu per creà rapidamente è senza sforzu operatori Kubernetes, è hà datu parechji esempi di u so usu.
L'infurmazioni detallate nantu à l'operatore di shell, è ancu un tutorialu rapidu nantu à cumu aduprà, hè dispunibule in u currispundente. repository nantu à GitHub. Ùn esitate à cuntattateci cù e dumande: pudete discutiri in un speciale Gruppu Telegram (in russo) o in stu foru (in inglese).
È s'ellu ci hè piaciutu, simu sempre felici di vede novi prublemi / PR / stelle nantu à GitHub, induve, per via, pudete truvà altri. prughjetti interessanti. À mezu à elli, vale a pena enfasi addun-operatore, chì hè u fratellu maiò di shell-operator. Questa utilità usa i grafici Helm per installà add-ons, pò furnisce l'aghjurnamenti è monitorà diversi parametri / valori di chart, cuntrolla u prucessu di stallazione di charts, è pò ancu mudificà in risposta à l'avvenimenti in u cluster.