Introduktion af shell-operator: Det er lige blevet nemmere at oprette operatører til Kubernetes

Der har allerede været artikler på vores blog, der taler om operatørfunktioner i Kubernetes og hvor skriv selv en simpel operatør. Denne gang vil vi gerne præsentere vores Open Source-løsning, som tager oprettelsen af ​​operatører til et super-let niveau - tjek ud shell-operatør!

Hvorfor?

Ideen om en shell-operator er ret enkel: abonner på begivenheder fra Kubernetes-objekter, og når disse begivenheder modtages, start et eksternt program, der giver det information om begivenheden:

Introduktion af shell-operator: Det er lige blevet nemmere at oprette operatører til Kubernetes

Behovet for det opstod, da der under driften af ​​klynger begyndte at dukke op små opgaver, som vi rigtig gerne ville automatisere på den rigtige måde. Alle disse små opgaver blev løst ved hjælp af simple bash-scripts, selvom det, som du ved, er bedre at skrive operatorer i Golang. Det er klart, at det ville være ineffektivt at investere i fuldskalaudvikling af en operatør til hver så lille opgave.

Operatør på 15 minutter

Lad os se på et eksempel på, hvad der kan automatiseres i en Kubernetes-klynge, og hvordan shell-operatøren kan hjælpe. Et eksempel kunne være følgende: replikering af en hemmelighed for at få adgang til docker-registret.

Pods, der bruger billeder fra et privat register, skal i deres manifest indeholde et link til en hemmelighed med data for adgang til registreringsdatabasen. Denne hemmelighed skal oprettes i hvert navneområde, før du opretter pods. Dette kan gøres manuelt, men hvis vi opsætter dynamiske miljøer, så bliver navnerummet for én applikation meget. Og hvis der heller ikke er 2-3 ansøgninger... bliver antallet af hemmeligheder meget stort. Og en ting mere om hemmeligheder: Jeg vil gerne ændre nøglen til at få adgang til registreringsdatabasen fra tid til anden. Til sidst, manuelle betjeninger som en løsning fuldstændig ineffektiv — vi er nødt til at automatisere oprettelsen og opdateringen af ​​hemmeligheder.

Simpel automatisering

Lad os skrive et shell-script, der kører en gang hvert N sekund og tjekker navneområder for tilstedeværelsen af ​​en hemmelighed, og hvis der ikke er nogen hemmelighed, så oprettes den. Fordelen ved denne løsning er, at den ligner et shell-script i cron – en klassisk og forståelig tilgang til alle. Ulempen er, at der i intervallet mellem dets lanceringer kan oprettes et nyt navneområde, og i nogen tid vil det forblive uden en hemmelighed, hvilket vil føre til fejl i lanceringen af ​​pods.

Automatisering med shell-operator

For at vores script skal fungere korrekt, skal den klassiske cron-lancering erstattes med en lancering, når der tilføjes et navneområde: i dette tilfælde kan du oprette en hemmelighed, før du bruger den. Lad os se, hvordan man implementerer dette ved hjælp af shell-operator.

Lad os først se på scriptet. Scripts i shell-operator-termer kaldes hooks. Hver krog, når den køres med et flag --config informerer shell-operatøren om sine bindinger, dvs. på hvilke arrangementer det skal lanceres. I vores tilfælde vil vi bruge onKubernetesEvent:

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

Det er beskrevet her, at vi er interesserede i at tilføje begivenheder (add) objekter af typen namespace.

Nu skal du tilføje koden, der vil blive udført, når hændelsen indtræffer:

#!/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

Store! Resultatet blev et lille smukt manuskript. For at "genoplive" det, er der to trin tilbage: klargør billedet og start det i klyngen.

Forberedelse af et billede med en krog

Hvis du ser på scriptet, kan du se, at kommandoerne er brugt kubectl и jq. Det betyder, at billedet skal have følgende ting: vores hook, en shell-operator, der vil overvåge hændelser og køre hook, og de kommandoer, der bruges af hook (kubectl og jq). Hub.docker.com har allerede et færdigt billede, hvori shell-operator, kubectl og jq er pakket ind. Tilbage er blot at tilføje en simpel krog 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

Løber i en klynge

Lad os se på krogen igen og denne gang skrive ned, hvilke handlinger og med hvilke objekter den udfører i klyngen:

  1. abonnerer på begivenheder til oprettelse af navnerum;
  2. opretter en hemmelighed i andre navnerum end den, hvor den er lanceret.

Det viser sig, at den pod, hvori vores billede vil blive lanceret, skal have tilladelser til at udføre disse handlinger. Dette kan gøres ved at oprette din egen ServiceAccount. Tilladelsen skal ske i form af ClusterRole og ClusterRoleBinding, pga vi er interesserede i objekter fra hele klyngen.

Den endelige beskrivelse i YAML vil se nogenlunde sådan ud:

---
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

Du kan starte det samlede billede som en simpel implementering:

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

For nemheds skyld oprettes et separat navneområde, hvor shell-operatoren vil blive lanceret, og de oprettede manifester vil blive anvendt:

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

Det er alt: shell-operatoren starter, abonnerer på begivenheder til oprettelse af navnerum og kører hooken, når det er nødvendigt.

Introduktion af shell-operator: Det er lige blevet nemmere at oprette operatører til Kubernetes

Således et simpelt shell-script blev til en rigtig operatør for Kubernetes og fungerer som en del af en klynge. Og alt dette uden den komplekse proces med at udvikle operatører i Golang:

Introduktion af shell-operator: Det er lige blevet nemmere at oprette operatører til Kubernetes

Der er en anden illustration af denne sag...Introduktion af shell-operator: Det er lige blevet nemmere at oprette operatører til Kubernetes

Vi vil afsløre dens betydning mere detaljeret i en af ​​de følgende publikationer.

filtrering

Sporing af objekter er godt, men der er ofte behov for at reagere på ændring af nogle objektegenskaber, for eksempel for at ændre antallet af replikaer i Deployment eller for at ændre objektetiketter.

Når en begivenhed ankommer, modtager shell-operatøren JSON-manifestet for objektet. Vi kan vælge de egenskaber, der interesserer os i denne JSON, og køre krogen kun når de skifter. Der er et felt til dette jqFilter, hvor du skal angive det jq-udtryk, der skal anvendes på JSON-manifestet.

For at reagere på ændringer i etiketter for implementeringsobjekter skal du f.eks. filtrere feltet labels ud af banen metadata. Konfigurationen bliver sådan her:

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

Dette jqFilter-udtryk forvandler Deployments lange JSON-manifest til kort JSON med etiketter:

Introduktion af shell-operator: Det er lige blevet nemmere at oprette operatører til Kubernetes

shell-operator vil kun køre krogen, når denne korte JSON ændres, og ændringer til andre egenskaber vil blive ignoreret.

Hook launch kontekst

Hook-konfigurationen giver dig mulighed for at angive flere muligheder for begivenheder - for eksempel 2 muligheder for begivenheder fra Kubernetes og 2 tidsplaner:

{"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"
]}

En lille digression: ja, shell-operator understøtter kører crontab stil scripts. Flere detaljer kan findes i dokumentation.

For at skelne hvorfor krogen blev lanceret, opretter shell-operatoren en midlertidig fil og sender stien til den i en variabel til krogen BINDING_CONTEXT_TYPE. Filen indeholder en JSON-beskrivelse af årsagen til at køre krogen. For eksempel vil krogen hvert 10. minut køre med følgende indhold:

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

... og på mandag starter det med dette:

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

for onKubernetesEvent Der vil være flere JSON-triggere, fordi den indeholder en beskrivelse af objektet:

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

Indholdet af felterne kan forstås ud fra deres navne, og flere detaljer kan læses i dokumentation. Et eksempel på at få et ressourcenavn fra et felt resourceName at bruge jq er allerede blevet vist i en hook, der kopierer hemmeligheder:

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

Du kan få andre felter på lignende måde.

Hvad er det næste?

I projektdepotet, i /eksempler mapper, er der eksempler på kroge, der er klar til at køre på en klynge. Når du skriver dine egne kroge, kan du bruge dem som grundlag.

Der er understøttelse af indsamling af metrics ved hjælp af Prometheus - de tilgængelige metrics er beskrevet i afsnittet METRIK.

Som du måske kan gætte, er shell-operatoren skrevet i Go og distribueret under en Open Source-licens (Apache 2.0). Vi vil være taknemmelige for enhver udviklingsbistand projekt på GitHub: og stjerner, og problemer, og pull-anmodninger.

Ved at løfte sløret af hemmeligholdelse, vil vi også informere dig om, at shell-operatør er lille del af vores system, der kan holde tilføjelser installeret i Kubernetes-klyngen opdateret og udføre forskellige automatiske handlinger. Læs mere om dette system fortalte bogstaveligt talt på mandag på HighLoad++ 2019 i St. Petersborg - vi vil snart offentliggøre videoen og transskriptionen af ​​denne rapport.

Vi har en plan om at åbne op for resten af ​​dette system: addon-operatøren og vores samling af kroge og moduler. Forresten, addon-operator er det allerede tilgængelig på github, men dokumentationen for det er stadig på vej. Udgivelsen af ​​samlingen af ​​moduler er planlagt til sommer.

Bliv hængende!

PS

Læs også på vores blog:

Kilde: www.habr.com

Tilføj en kommentar