Enkonduko de shell-operator: krei operatorojn por Kubernetes simple fariĝis pli facila

En nia blogo jam aperis artikoloj pri kiuj parolas funkciigistkapabloj en Kubernetes kaj kiel skribu mem simplan operatoron. Ĉi-foje ni ŝatus prezenti al via atento nian Malfermfontan solvon, kiu portas la kreadon de operatoroj al superfacila nivelo - kontrolu ŝelo-funkciigisto!

Kial?

La ideo de ŝel-funkciigisto estas sufiĉe simpla: abonu eventojn de Kubernetes-objektoj, kaj kiam ĉi tiuj eventoj estas ricevitaj, lanĉu eksteran programon, provizante ĝin per informoj pri la evento:

Enkonduko de shell-operator: krei operatorojn por Kubernetes simple fariĝis pli facila

La bezono de ĝi estiĝis kiam, dum la funkciado de aretoj, komencis aperi malgrandaj taskoj, kiujn ni vere volis aŭtomatigi en la ĝusta maniero. Ĉiuj ĉi tiuj malgrandaj taskoj estis solvitaj per simplaj bash-skriptoj, kvankam, kiel vi scias, estas pli bone skribi operatorojn en Golang. Evidente, investi en plenskala evoluo de funkciigisto por ĉiu tia malgranda tasko estus neefika.

Operaciisto en 15 minutoj

Ni rigardu ekzemplon pri tio, kio povas esti aŭtomatigita en Kubernetes-areto kaj kiel la ŝelo-funkciigisto povas helpi. Ekzemplo estus la sekva: reprodukti sekreton por aliri la docker-registron.

Pods kiuj uzas bildojn de privata registro devas enhavi en sia manifesto ligon al sekreto kun datumoj por aliro al la registro. Ĉi tiu sekreto devas esti kreita en ĉiu nomspaco antaŭ krei podojn. Ĉi tio povas esti farita permane, sed se ni agordas dinamikajn mediojn, tiam la nomspaco por unu aplikaĵo fariĝos multe. Kaj se ankaŭ ne estas 2-3 aplikoj... la nombro da sekretoj fariĝas tre granda. Kaj ankoraŭ unu afero pri sekretoj: mi ŝatus ŝanĝi la ŝlosilon por aliri la registron de tempo al tempo. Fine, manaj operacioj kiel solvo tute senefika — ni devas aŭtomatigi la kreadon kaj ĝisdatigon de sekretoj.

Simpla aŭtomatigo

Ni skribu ŝelan skripton, kiu funkcias unufoje ĉiujn N sekundojn kaj kontrolas nomspacojn por la ĉeesto de sekreto, kaj se ne ekzistas sekreto, tiam ĝi estas kreita. La avantaĝo de ĉi tiu solvo estas, ke ĝi aspektas kiel ŝela skripto en cron - klasika kaj komprenebla aliro por ĉiuj. La malavantaĝo estas, ke en la intervalo inter ĝiaj lanĉoj nova nomspaco povas esti kreita kaj dum iom da tempo ĝi restos sen sekreto, kio kondukos al eraroj en lanĉado de podoj.

Aŭtomatigo kun ŝelo-funkciigisto

Por ke nia skripto funkciu ĝuste, la klasika kron-lanĉo devas esti anstataŭigita per lanĉo kiam nomspaco estas aldonita: en ĉi tiu kazo, vi povas krei sekreton antaŭ ol uzi ĝin. Ni vidu kiel efektivigi ĉi tion uzante shell-operator.

Unue, ni rigardu la skripton. Skriptoj en ŝel-funkciigistoperiodoj estas nomitaj hokoj. Ĉiu hoko kiam kuras kun flago --config informas la ŝel-funkciigiston pri ĝiaj ligadoj, t.e. pri kiaj eventoj ĝi devus esti lanĉita. En nia kazo ni uzos onKubernetesEvent:

#!/bin/bash
if [[ $1 == "--config" ]] ; then
cat <<EOF
{
"onKubernetesEvent": [
  { "kind": "namespace",
    "event":["add"]
  }
]}
EOF
fi

Estas priskribite ĉi tie, ke ni interesiĝas pri aldoni eventojn (add) objektoj de tipo namespace.

Nun vi devas aldoni la kodon, kiu estos efektivigita kiam la evento okazos:

#!/bin/bash
if [[ $1 == "--config" ]] ; then
  # конфигурация
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "namespace",
  "event":["add"]
}
]}
EOF
else
  # реакция:
  # узнать, какой namespace появился
  createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
  # создать в нём нужный секрет
  kubectl create -n ${createdNamespace} -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  ...
data:
  ...
EOF
fi

Bonege! La rezulto estis malgranda, bela manuskripto. Por "revivigi" ĝin, restas du paŝoj: prepari la bildon kaj lanĉi ĝin en la areto.

Preparante bildon per hoko

Se vi rigardas la skripton, vi povas vidi, ke la komandoj estas uzataj kubectl и jq. Ĉi tio signifas, ke la bildo devas havi la jenajn aferojn: nian hokon, ŝel-funkciigiston, kiu kontrolos eventojn kaj ruligos la hokon, kaj la komandojn uzatajn de la hoko (kubectl kaj jq). Hub.docker.com jam havas pretan bildon en kiu shell-operator, kubectl kaj jq estas pakitaj. Restas nur aldoni simplan hokon Dockerfile:

$ cat Dockerfile
FROM flant/shell-operator:v1.0.0-beta.1-alpine3.9
ADD namespace-hook.sh /hooks

$ docker build -t registry.example.com/my-operator:v1 . 
$ docker push registry.example.com/my-operator:v1

Kurante en areto

Ni rigardu la hokon denove kaj ĉi-foje skribu kiajn agojn kaj per kiaj objektoj ĝi plenumas en la areto:

  1. abonas eventojn pri nomspaco;
  2. kreas sekreton en nomspacoj krom tiu, kie ĝi estas lanĉita.

Rezultas, ke la pod, en kiu nia bildo estos lanĉita, devas havi permesojn por fari ĉi tiujn agojn. Ĉi tio povas esti farita kreante vian propran Servan Konton. La permeso devas esti farita en la formo de ClusterRole kaj ClusterRoleBinding, ĉar ni interesiĝas pri objektoj el la tuta areto.

La fina priskribo en YAML aspektos kiel ĉi tio:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: monitor-namespaces-acc

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: monitor-namespaces
rules:
- apiGroups: [""]
  resources: ["namespaces"]
  verbs: ["get", "watch", "list"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list", "create", "patch"]

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: monitor-namespaces
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: monitor-namespaces
subjects:
  - kind: ServiceAccount
    name: monitor-namespaces-acc
    namespace: example-monitor-namespaces

Vi povas lanĉi la kunvenitan bildon kiel simpla Deplojo:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-operator
spec:
  template:
    spec:
      containers:
      - name: my-operator
        image: registry.example.com/my-operator:v1
      serviceAccountName: monitor-namespaces-acc

Por komforto, aparta nomspaco estas kreita kie la ŝelo-funkciigisto estos lanĉita kaj la kreitaj manifestoj estos aplikitaj:

$ kubectl create ns example-monitor-namespaces
$ kubectl -n example-monitor-namespaces apply -f rbac.yaml
$ kubectl -n example-monitor-namespaces apply -f deployment.yaml

Jen ĉio: la ŝel-funkciigisto komenciĝos, abonos eventojn pri kreado de nomspaco kaj rulos la hokon kiam necese.

Enkonduko de shell-operator: krei operatorojn por Kubernetes simple fariĝis pli facila

Tiel, simpla ŝel-skripto fariĝis reala operatoro por Kubernetes kaj funkcias kiel parto de areto. Kaj ĉio ĉi sen la kompleksa procezo de evoluigado de funkciigistoj en Golang:

Enkonduko de shell-operator: krei operatorojn por Kubernetes simple fariĝis pli facila

Estas alia ilustraĵo pri ĉi tiu afero...Enkonduko de shell-operator: krei operatorojn por Kubernetes simple fariĝis pli facila

Ni malkaŝos ĝian signifon pli detale en unu el la sekvaj eldonaĵoj.

Filtrado

Spurado de objektoj estas bona, sed ofte necesas reagi ŝanĝante iujn objektojn, ekzemple, por ŝanĝi la nombron da kopioj en Deployment aŭ por ŝanĝi objektotikedojn.

Kiam okazaĵo alvenas, la ŝelo-funkciigisto ricevas la JSON-manifeston de la objekto. Ni povas elekti la ecojn, kiuj interesas nin en ĉi tiu JSON kaj ruli la hokon nur kiam ili ŝanĝiĝas. Estas kampo por ĉi tio jqFilter, kie vi devas specifi la jq-esprimon, kiu estos aplikita al la JSON-manifesto.

Ekzemple, por respondi al ŝanĝoj en etikedoj por Deploj-objektoj, vi devas filtri la kampon labels ekster la kampo metadata. La agordo estos tia:

cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "deployment",
  "event":["update"],
  "jqFilter": ".metadata.labels"
}
]}
EOF

Ĉi tiu jqFilter-esprimo igas la longan JSON manifeston de Deployment en mallongan JSON kun etikedoj:

Enkonduko de shell-operator: krei operatorojn por Kubernetes simple fariĝis pli facila

shell-operator nur ruligos la hokon kiam ĉi tiu mallonga JSON ŝanĝiĝos, kaj ŝanĝoj al aliaj trajtoj estos ignoritaj.

Hoko lanĉa kunteksto

La hoka agordo permesas vin specifi plurajn eblojn por eventoj - ekzemple 2 ebloj por eventoj de Kubernetes kaj 2 horaroj:

{"onKubernetesEvent":[
  {"name":"OnCreatePod",
  "kind": "pod",
  "event":["add"]
  },
  {"name":"OnModifiedNamespace",
  "kind": "namespace",
  "event":["update"],
  "jqFilter": ".metadata.labels"
  }
],
"schedule": [
{ "name":"every 10 min",
  "crontab":"* */10 * * * *"
}, {"name":"on Mondays at 12:10",
"crontab": "* 10 12 * * 1"
]}

Malgranda deturniĝo: jes, shell-operator subtenas rulante crontab-stilaj skriptoj. Pliaj detaloj troveblas en dokumentado.

Por distingi kial la hoko estis lanĉita, la ŝelo-funkciigisto kreas provizoran dosieron kaj pasas la vojon al ĝi en variablo al la hoko. BINDING_CONTEXT_TYPE. La dosiero enhavas JSON-priskribon de la kialo por funkcii la hokon. Ekzemple, ĉiujn 10 minutojn la hoko funkcios kun la sekva enhavo:

[{ "binding": "every 10 min"}]

... kaj lunde komenciĝos per ĉi tio:

[{ "binding": "every 10 min"}, { "binding": "on Mondays at 12:10"}]

Por onKubernetesEvent Estos pli da JSON-eksigiloj, ĉar ĝi enhavas priskribon de la objekto:

[
 {
 "binding": "onCreatePod",
 "resourceEvent": "add",
 "resourceKind": "pod",
 "resourceName": "foo",
 "resourceNamespace": "bar"
 }
]

La enhavo de la kampoj estas kompreneblaj el iliaj nomoj, kaj pli da detaloj legeblas dokumentado. Ekzemplo de ricevado de rimeda nomo de kampo resourceName uzi jq jam estis montrita en hoko kiu reproduktas sekretojn:

jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH

Vi povas akiri aliajn kampojn en simila maniero.

Kio sekvas?

En la projektdeponejo, en /examples dosierujoj, ekzistas ekzemploj de hokoj, kiuj estas pretaj por funkcii sur areto. Skribante viajn proprajn hokojn, vi povas uzi ilin kiel bazon.

Estas subteno por kolekti metrikojn per Prometheus - la disponeblaj metrikoj estas priskribitaj en la sekcio METRIKO.

Kiel vi povas supozi, la ŝel-funkciigisto estas skribita en Go kaj distribuita sub Malferma Fonta permesilo (Apache 2.0). Ni estos dankemaj pro ajna disvolva helpo projekto en GitHub: kaj steloj, kaj temoj, kaj tiri petojn.

Levante la vualon de sekreteco, ni ankaŭ informos vin, ke ŝelo-funkciigisto estas небольшая parto de nia sistemo, kiu povas ĝisdatigi aldonaĵojn instalitajn en la Kubernetes-grupo kaj plenumi diversajn aŭtomatajn agojn. Legu pli pri ĉi tiu sistemo rakontis laŭvorte lundon ĉe HighLoad++ 2019 en Sankt-Peterburgo - ni baldaŭ publikigos la videon kaj transskribon de ĉi tiu raporto.

Ni havas planon malfermi la reston de ĉi tiu sistemo: la aldon-funkciigisto kaj nia kolekto de hokoj kaj moduloj. Cetere, addon-operatoro jam estas disponebla ĉe github, sed la dokumentaro por ĝi estas ankoraŭ survoje. La liberigo de la kolekto de moduloj estas planita por la somero.

Restu agordita!

PS

Legu ankaŭ en nia blogo:

fonto: www.habr.com

Aldoni komenton