Taun iki, konferensi Eropa utama ing Kubernetes - KubeCon + CloudNativeCon Europe 2020 - virtual. Nanging, owah-owahan ing format kasebut ora nyegah kita menehi omongan sing wis direncanakake kanthi dawa "Go? Bash! Ketemu Shell-operator", darmabakti kanggo proyek Open Source kita. .
Artikel iki, adhedhasar dhiskusi, presents pendekatan kanggo simplifying proses nggawe operator kanggo Kubernetes lan nuduhake carane sampeyan bisa nggawe dhewe karo minimal gaweyan nggunakake cangkang-operator.

nepangaken (~ 23 menit ing basa Inggris, luwih informatif tinimbang artikel) lan ringkesan utama ing wangun teks. Ayo budal!
Ing Flant, kita terus ngoptimalake lan ngotomatisasi kabeh. Dina iki, kita bakal ngomong babagan konsep liyane sing nyenengake. ketemu: skrip cangkang asli awan!
Ayo dadi miwiti karo konteks ing ngendi kabeh iki kedados, sanadyan: Kubernetes.
Kubernetes API lan Controllers
API ing Kubernetes bisa dianggep minangka server file kanthi direktori kanggo saben jinis obyek. Obyek (sumber daya) ing server iki diwakili dening file YAML. Kajaba iku, server duwe API dhasar sing ngidini sampeyan nindakake telung perkara:
- kanggo nampa sumber daya miturut jinis lan jeneng;
- pangowahan sumber daya (ing kasus iki, server mung nyimpen obyek "bener" - kabeh sing salah dibentuk utawa sing dimaksudake kanggo direktori liyane dibuwang);
- trek kanggo sumber daya (ing kasus iki, pangguna langsung nampa versi saiki / dianyari).
Dadi Kubernetes tumindak minangka server file (kanggo manifests YAML) kanthi telung cara dhasar (ya, ana liyane, nanging saiki bakal dilewati).

Masalahe yaiku server mung bisa nyimpen informasi. Kanggo nggawe iku bisa, sampeyan kudu controller — konsep paling penting lan dhasar kaloro ing donya Kubernetes.
Ana rong jinis utama pengontrol. Sing pertama njupuk informasi saka Kubernetes, ngolah kasebut miturut logika nested lan bali menyang K8s. Sing nomer loro njupuk informasi saka Kubernetes, nanging, ora kaya jinis pisanan, ngganti kahanan sawetara sumber daya eksternal.
Ayo dideleng kanthi luwih cetha babagan proses nggawe Deployment ing Kubernetes:
- Pengontrol Penyebaran (kalebu ing
kube-controller-manager) entuk informasi babagan Deployment lan nggawe ReplicaSet. - ReplicaSet nggawe rong replika (loro pods) adhedhasar informasi iki, nanging pods iki durung dijadwal.
- Penjadwal jadwal pods lan nambah informasi simpul menyang YAMLs.
- Kubelets nggawe owahan kanggo sumber daya external (omong, Docker).
Banjur kabeh urutan mbaleni mbalikke: kubelet mriksa kontaner, ngetung status pod lan dikirim maneh. ReplicaSet Controller nampa status lan nganyari negara saka pesawat replika. Mengkono uga karo Deployment Controller, lan pangguna pungkasane nampa status sing dianyari (saiki).

Shell-operator
Pranyata Kubernetes adhedhasar karya gabungan saka macem-macem pengontrol (operator Kubernetes uga pengontrol). Pitakonan muncul, carane nggawe operator dhewe kanthi gaweyan minimal? Lan iki teka kanggo ngluwari sing dikembangake . Iki ngidini administrator sistem nggawe operator dhewe nggunakake cara sing wis dikenal.
Conto prasaja: nyalin rahasia
Ayo padha ndeleng conto prasaja.
Ayo kita duwe klompok Kubernetes. Wis papan jeneng default karo sawetara Rahasia mysecret. Kajaba iku, ana papan jeneng liyane ing kluster kasebut. Sawetara wong duwe label khusus sing ditempelake. Tujuane yaiku nyalin Rahasia menyang ruang jeneng kanthi label.
Tugas kasebut rumit amarga kasunyatan manawa spasi jeneng anyar bisa katon ing kluster, lan sawetara bisa uga duwe label iki. Ing tangan liyane, nalika label dibusak, Rahasia uga kudu dibusak. Kajaba iku, Rahasia kasebut uga bisa diganti: ing kasus iki, Rahasia anyar kudu disalin menyang kabeh ruang jeneng kanthi label. Yen Rahasia ora sengaja dibusak ing sembarang namespace, operator kita kudu langsung mulihake.
Saiki tugas wis dirumusake, wektune kanggo miwiti ngleksanakake nggunakake shell-operator. Nanging pisanan, sawetara tembung babagan shell-operator dhewe.
Carane shell-operator dianggo
Kaya beban kerja Kubernetes liyane, shell-operator mlaku ing pod dhewe. Ing pod kasebut, ing direktori /hooks file eksekusi disimpen. Iki bisa dadi skrip ing Bash, Python, Ruby, lan liya-liyane. Kita nyebut file eksekusi kasebut minangka pancing (pancingan).

Shell-operator langganan acara Kubernetes lan mbukak pancingan iki kanggo nanggepi acara kita kudu.

Carane shell-operator ngerti kang pancing kanggo mbukak lan nalika? Bab iku saben pancing duwe rong tahap. Sajrone wiwitan, shell-operator mbukak kabeh pancingan karo argumen --config - iki tataran konfigurasi. Lan sawise iku, pancingan diluncurake kanthi cara normal - kanggo nanggepi acara sing bakal ditindakake. Ing kasus sing terakhir, pancing nampa konteks naleni (konteks mengikat) - data ing format JSON, sing bakal kita bahas luwih rinci ing ngisor iki.
Nggawe operator ing Bash
Saiki kita siap kanggo implementasine. Kanggo nindakake iki, kita kudu nulis rong fungsi (kanthi cara, disaranake perpustakaan , sing ndadekake gampang nulis pancingan ing Bash):
- sing pisanan dibutuhake kanggo tahap konfigurasi - ngasilake konteks ikatan;
- Sing nomer loro ngemot logika utama pancing.
#!/bin/bash
source /shell_lib.sh
function __config__() {
cat << EOF
configVersion: v1
# BINDING CONFIGURATION
EOF
}
function __main__() {
# THE LOGIC
}
hook::run "$@"
Langkah sabanjure yaiku mutusake obyek apa sing dibutuhake. Ing kasus kita, kita kudu nglacak:
- rahasia sumber kanggo owah-owahan;
- kabeh namespaces ing kluster, kanggo ngerti sing duwe label ditempelake;
- rahasia target kanggo mesthekake yen kabeh padha ing sync karo rahasia sumber.
Langganan sumber rahasia
Konfigurasi naleni kanggo iku cukup prasaja. Kita nemtokake manawa kita kasengsem ing Rahasia kanthi jeneng kasebut mysecret ing namespace default:

function __config__() {
cat << EOF
configVersion: v1
kubernetes:
- name: src_secret
apiVersion: v1
kind: Secret
nameSelector:
matchNames:
- mysecret
namespace:
nameSelector:
matchNames: ["default"]
group: main
EOF
Akibaté, pancing bakal micu nalika rahasia sumber diganti (src_secret) lan entuk konteks ikatan ing ngisor iki:

Nalika sampeyan bisa ndeleng, ngemot jeneng lan kabeh obyek.
Nglacak spasi jeneng
Saiki kita kudu langganan namespaces. Kanggo nindakake iki, kita nemtokake konfigurasi ikatan ing ngisor iki:
- name: namespaces
group: main
apiVersion: v1
kind: Namespace
jqFilter: |
{
namespace: .metadata.name,
hasLabel: (
.metadata.labels // {} |
contains({"secret": "yes"})
)
}
group: main
keepFullObjectsInMemory: false
Kaya sing sampeyan ngerteni, lapangan anyar sing jenenge wis katon ing konfigurasi jqFilter. Kaya jenenge, jqFilter nyaring kabeh informasi sing ora perlu lan nggawe obyek JSON anyar karo lapangan sing menarik kanggo kita. Pancing kanthi konfigurasi kasebut bakal nampa konteks ikatan ing ngisor iki:

Isine array filterResults kanggo saben namespace ing kluster. Variabel Boolean hasLabel nuduhake apa label ditempelake ing namespace diwenehi. Pamilih keepFullObjectsInMemory: false nuduhake yen ana ora perlu kanggo nyimpen obyek lengkap ing memori.
Nelusuri Target Rahasia
Kita langganan kabeh Rahasia sing duwe set anotasi managed-secret: "yes" (iki target kita 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
Ing kasus iki jqFilter nyaring kabeh informasi kajaba namespace lan parameter resourceVersion. Parameter pungkasan dikirim menyang anotasi nalika rahasia digawe: ngidini sampeyan mbandhingake versi rahasia lan tetep anyar.
A pancing diatur kaya iki bakal, nalika kaleksanan, nampa telung konteks naleni diterangake ing ndhuwur. Sampeyan bisa nganggep minangka jinis snapshot (gambar asli seko) kluster.

Adhedhasar kabeh informasi kasebut, algoritma dhasar bisa dikembangake. Iku iterates liwat kabeh namespaces lan:
- yen
hasLabelprakaratruekanggo ruang jeneng saiki:- mbandhingake rahasia global karo sing lokal:
- yen padha - ora nindakake apa-apa;
- yen padha beda - performs
kubectl replaceutawacreate;
- mbandhingake rahasia global karo sing lokal:
- yen
hasLabelprakarafalsekanggo ruang jeneng saiki:- nggawe manawa Rahasia ora ana ing ruang jeneng sing diwenehake:
- yen Rahasia lokal saiki - mbusak nggunakake
kubectl delete; - yen Rahasia lokal ora ditemokake - ora nindakake apa-apa.
- yen Rahasia lokal saiki - mbusak nggunakake
- nggawe manawa Rahasia ora ana ing ruang jeneng sing diwenehake:

sampeyan bisa ngundhuh saka kita .
Mangkene carane kita bisa nggawe kontroler Kubernetes sing prasaja nggunakake 35 baris konfigurasi YAML lan jumlah kode Bash sing padha! Tugas saka cangkang-operator iku kanggo dasi mau bebarengan.
Nanging, nyalin rahasia ora mung area aplikasi sarana kasebut. Ing ngisor iki sawetara conto liyane sing bakal nuduhake apa sing bisa ditindakake.
Conto 1: Nggawe owahan menyang ConfigMap
Ayo nimbang Deployment sing dumadi saka telung pods. Pods nggunakake ConfigMap kanggo nyimpen sawetara konfigurasi. Nalika pods diwiwiti, ConfigMap ing sawetara negara (ayo nelpon v.1). Mulane, kabeh pod nggunakake versi ConfigMap iki.
Saiki umpamane ConfigMap wis diganti (v.2). Nanging, pods isih bakal nggunakake versi lawas saka ConfigMap (v.1):

Carane nggawe wong ngalih menyang ConfigMap anyar (v.2)? Jawaban iki prasaja: nggunakake cithakan. Ayo ditambahake anotasi checksum menyang bagean kasebut template Konfigurasi panyebaran:

Akibaté, kabeh pods bakal duwe checksum iki, lan bakal padha karo Deployment. Saiki sampeyan mung kudu nganyari anotasi nalika ConfigMap diganti. Lan cangkang-operator banget migunani ing kasus iki. Kabeh sing perlu kanggo program pancing sing bakal langganan ConfigMap lan nganyari checksum.
Yen pangguna nggawe owahan ing ConfigMap, shell-operator bakal sok dong mirsani lan ngitung maneh checksum. Sawise iku, sihir Kubernetes bakal dimainake: orkestra bakal mateni pod, nggawe sing anyar, ngenteni nganti dadi. Ready, lan pindhah menyang sabanjure. Akibaté, Deployment bakal nyinkronake lan pindhah menyang versi anyar saka ConfigMap.

Conto 2: Nggarap Definisi Sumber Daya Khusus
Kaya sing wis dingerteni, Kubernetes ngidini sampeyan nggawe jinis (jinis) obyek khusus. Contone, sampeyan bisa nggawe jinis MysqlDatabase. Contone, jinis iki duwe rong parameter metadata: name и namespace.
apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
name: foo
namespace: bar
Kita duwe kluster Kubernetes kanthi ruang jeneng sing beda ing ngendi kita bisa nggawe database MySQL. Ing kasus iki, shell-operator bisa digunakake kanggo ngawasi sumber daya MysqlDatabase, sambungan menyang server MySQL lan sinkronisasi negara sing dikarepake lan diamati saka kluster.

Conto 3: Ngawasi Jaringan Kluster
Kaya sing sampeyan ngerteni, nggunakake ping minangka cara paling gampang kanggo ngawasi jaringan. Ing conto iki, kita bakal nuduhake carane ngleksanakake pemantauan kasebut nggunakake shell-operator.
Kaping pisanan, sampeyan kudu langganan node. Operator cangkang mbutuhake jeneng lan alamat IP saben simpul. Iki bakal digunakake kanggo ping simpul kasebut.
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: [] nyegah pancing supaya ora bisa dipecat kanggo nanggepi acara apa wae (yaiku nanggepi kelenjar sing diganti, ditambahake, utawa dicopot). Nanging, iku bakal diluncurake (lan nganyari dhaptar simpul) ing jadwal - saben menit, minangka lapangan prescribes schedule.
Saiki muncul pitakonan, kepiye carane ngerti babagan masalah kaya packet loss? Ayo ndeleng kode kasebut:
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
}
Kita terusake dhaptar simpul, entuk jeneng lan alamat IP, ping lan ngirim asil menyang Prometheus. Shell-operator bisa ngekspor metrik menyang Prometheus, nyimpen menyang file sing ana miturut path sing ditemtokake ing variabel lingkungan $METRICS_PATH.
Sampeyan bisa nggawe operator kanggo ngawasi jaringan prasaja ing kluster.
Mekanisme antrian
Artikel iki ora bakal lengkap tanpa njlèntrèhaké mekanisme penting liyane dibangun ing cangkang-operator. Mbayangno sing executes sawetara pancing kanggo nanggepi acara ing kluster.
- Apa mengkono yen ing wektu sing padha ana masalah ing kluster? siji maneh acara?
- Bakal Nihan-operator mbukak Kayata liyane pancing?
- Apa yen, sebutno, limang acara kedadeyan ing kluster bebarengan?
- Bakal shell-operator proses mau ing podo karo?
- Kepiye babagan sumber daya sing digunakake kayata memori lan CPU?
Untunge, shell-operator duwe mekanisme antrian sing dibangun. Kabeh acara diantrekake lan diproses kanthi urutan.
Ayo digambarake nganggo conto. Ayo nganggep yen kita duwe rong pancing. Acara pisanan menyang pancing pisanan. Sawise pangolahan rampung, antrian maju. Telung acara sabanjure diterusake menyang pancing kapindho - ditarik saka antrian lan dikirim menyang "batch". yaiku, pancing nampa Uploaded acara - utawa, luwih tepat, macem-macem konteks naleni.
Uga iki acara bisa digabung dadi siji gedhe. Parameter kasebut tanggung jawab kanggo iki. group ing konfigurasi naleni.

Sampeyan bisa nggawe nomer antrian / pancingan lan macem-macem kombinasi. Contone, siji antrian bisa nganggo loro pancingan, utawa kosok balene.

Sampeyan mung kudu nyetel lapangan sing cocog. queue ing konfigurasi naleni. Yen ora ana jeneng antrian sing ditemtokake, pancing kasebut diluncurake ing antrian standar (default). Mekanisme antrian kasebut ngidini kanggo ngrampungake kabeh masalah manajemen sumber daya nalika nggarap pancing.
kesimpulan
Kita nerangake apa shell-operator, nuduhake carane bisa digunakake kanggo nggawe operator Kubernetes kanthi cepet lan gampang, lan menehi sawetara conto panggunaan.
Informasi rinci babagan shell-operator, uga pandhuan cepet babagan carane nggunakake, kasedhiya ing cocog . Aja ragu-ragu kanggo hubungi kita karo pitakonan: sampeyan bisa ngrembug ing khusus (ing basa Rusia) utawa ing (ing basa Inggris).
Lan yen sampeyan seneng, kita mesthi seneng ndeleng masalah anyar / PR / lintang ing GitHub, ing ngendi sampeyan bisa nemokake liyane Antarane wong-wong mau, iku worth nyorot , yaiku sedulur tuwa saka shell-operator. Utilitas iki nggunakake grafik Helm kanggo nginstal tambahan, bisa ngirim nganyari lan ngawasi macem-macem paramèter / nilai grafik, ngontrol proses instalasi grafik, lan uga bisa ngowahi kanggo nanggepi acara ing kluster.

Video lan minger
Video saka pagelaran (~23 menit):

Presentasi laporan:
PS
Waca uga ing blog kita:
- «";
- «";
- «";
- «.
Source: www.habr.com
