Shell-operator yntrodusearje: operators meitsje foar Kubernetes is krekt makliker wurden

D'r binne al artikels op ús blog west oer praat operatormooglikheden yn Kubernetes en hoe skriuw in ienfâldige operator sels. Dizze kear wolle wy ús Open Source-oplossing oan jo oandacht presintearje, dy't it oanmeitsjen fan operators nei in supermaklik nivo bringt - check out shell-operator!

Wêrom?

It idee fan in shell-operator is frij simpel: abonnearje op eveneminten fan Kubernetes-objekten, en as dizze eveneminten wurde ûntfongen, lansearje in ekstern programma, it leverjen fan ynformaasje oer it evenemint:

Shell-operator yntrodusearje: operators meitsje foar Kubernetes is krekt makliker wurden

It ferlet dêrfoar ûntstie doe't der by de eksploitaasje fan klusters lytse taken begûnen te ferskinen dy't wy echt op de goede manier automatisearje woene. Al dizze lytse taken waarden oplost mei ienfâldige bash-skripts, hoewol, lykas jo witte, it better is om operators yn Golang te skriuwen. Fansels soe ynvestearje yn folsleine ûntwikkeling fan in operator foar elke sa'n lytse taak net effektyf wêze.

Operator yn 15 minuten

Litte wy nei in foarbyld sjen fan wat kin wurde automatisearre yn in Kubernetes-kluster en hoe't de shell-operator kin helpe. In foarbyld soe it folgjende wêze: in geheim replikearje om tagong te krijen ta it docker-register.

Pods dy't ôfbyldings brûke fan in privee register moatte yn har manifest in keppeling befetsje nei in geheim mei gegevens foar tagong ta it register. Dit geheim moat makke wurde yn elke nammeromte foardat jo pods meitsje. Dit kin mei de hân dien wurde, mar as wy dynamyske omjouwings ynstelle, dan sil de nammeromte foar ien applikaasje in soad wurde. En as der ek gjin 2-3 oanfragen binne... wurdt it tal geheimen hiel grut. En noch ien ding oer geheimen: ik wol de kaai feroarje om fan tiid ta tiid tagong te krijen ta it register. Úteinlik, hânmjittich operaasjes as oplossing folslein net effektyf - wy moatte it oanmeitsjen en bywurkjen fan geheimen automatisearje.

Ienfâldige automatisearring

Litte wy in shellskript skriuwe dat ien kear elke N sekonden rint en nammeromten kontrolearret op de oanwêzigens fan in geheim, en as der gjin geheim is, dan wurdt it makke. It foardiel fan dizze oplossing is dat it liket op in shell-skript yn cron - in klassike en begryplike oanpak foar elkenien. It neidiel is dat yn it ynterval tusken har lansearringen in nije nammeromte kin wurde oanmakke en in skoft sil it sûnder geheim bliuwe, wat sil liede ta flaters by it lansearjen fan pods.

Automatisearring mei shell-operator

Foar ús skript om goed te wurkjen, moat de klassike cron-lansearring wurde ferfongen troch in lansearring as in nammeromte wurdt tafoege: yn dit gefal kinne jo in geheim meitsje foardat jo it brûke. Litte wy sjen hoe't jo dit ymplementearje mei help fan shell-operator.

Litte wy earst nei it skript sjen. Skripten yn termen fan shell-operator wurde haken neamd. Elke heak doe't rinne mei in flagge --config ynformearret de shell-operator oer syn bindingen, d.w.s. op hokker eveneminten it moat wurde lansearre. Yn ús gefal sille wy brûke onKubernetesEvent:

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

It wurdt hjir beskreaun dat wy ynteressearre binne yn it tafoegjen fan eveneminten (add) objekten fan type namespace.

No moatte jo de koade tafoegje dy't sil wurde útfierd as it evenemint bart:

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

Grut! It resultaat wie in lyts, moai skript. Om it te "werlibjen" binne d'r twa stappen oer: tariede de ôfbylding en lansearje it yn it kluster.

It tarieden fan in ôfbylding mei in heak

As jo ​​nei it skript sjogge, kinne jo sjen dat de kommando's wurde brûkt kubectl и jq. Dit betsjut dat de ôfbylding de folgjende dingen moat hawwe: ús hook, in shell-operator dy't harkje nei eveneminten en de hook útfiere, en de kommando's dy't brûkt wurde troch de hook (kubectl en jq). Hub.docker.com hat al in klearmakke ôfbylding wêryn shell-operator, kubectl en jq binne ferpakt. Alles wat oerbliuwt is in ienfâldige heak ta te foegjen 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

Running yn in kluster

Litte wy nochris nei de heak sjen en dizze kear opskriuwe hokker aksjes en mei hokker objekten it útfiert yn it kluster:

  1. abonnearret op nammeromte skepping eveneminten;
  2. makket in geheim yn oare nammeromten as dejinge wêr't it lansearre wurdt.

It docht bliken dat de pod wêryn ús ôfbylding sil wurde lansearre tagongsrjochten moat hawwe om dizze aksjes te dwaan. Dit kin dien wurde troch jo eigen ServiceAccount oan te meitsjen. De tastimming moat dien wurde yn 'e foarm fan ClusterRole en ClusterRoleBinding, om't wy binne ynteressearre yn objekten út it hiele kluster.

De definitive beskriuwing yn YAML sil der sa útsjen:

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

Jo kinne de gearstalde ôfbylding starte as in ienfâldige ynset:

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

Foar gemak wurdt in aparte nammeromte makke wêr't de shell-operator sil wurde lansearre en de oanmakke manifesten sille tapast wurde:

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

Dat is alles: de shell-operator sil begjinne, abonnearje op eveneminten foar skepping fan nammeromte en de heak útfiere as it nedich is.

Shell-operator yntrodusearje: operators meitsje foar Kubernetes is krekt makliker wurden

sa, in ienfâldich shell-skript feroare yn in echte operator foar Kubernetes en wurket as ûnderdiel fan in kluster. En dit alles sûnder it komplekse proses fan it ûntwikkeljen fan operators yn Golang:

Shell-operator yntrodusearje: operators meitsje foar Kubernetes is krekt makliker wurden

D'r is in oare yllustraasje oer dizze saak ...Shell-operator yntrodusearje: operators meitsje foar Kubernetes is krekt makliker wurden

Wy sille har betsjutting yn mear detail iepenbierje yn ien fan 'e folgjende publikaasjes.

filtering

Tracking foarwerpen is goed, mar der is faak in ferlet om te reagearjen op feroarjen fan guon foarwerp eigenskippen, bygelyks, om it oantal replika's yn Deployment te feroarjen of om objektetiketten te feroarjen.

As in evenemint oankomt, ûntfangt de shell-operator it JSON-manifest fan it objekt. Wy kinne de eigenskippen selektearje dy't ús ynteressearje yn dizze JSON en de heak útfiere allinnich as se feroarje. Dêr is in fjild foar jqFilter, wêr't jo de jq-ekspresje moatte opjaan dy't tapast wurde sil op it JSON-manifest.

Bygelyks, om te reagearjen op feroarings yn labels foar Deployment-objekten, moatte jo it fjild filterje labels út it fjild metadata. De konfiguraasje sil sa wêze:

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

Dizze jqFilter-ekspresje feroaret it lange JSON-manifest fan Deployment yn koarte JSON mei labels:

Shell-operator yntrodusearje: operators meitsje foar Kubernetes is krekt makliker wurden

shell-operator sil allinne rinne de heak doe't dizze koarte JSON feroarings, en feroarings oan oare eigenskippen sille wurde negearre.

Hook launch kontekst

De hook-konfiguraasje lit jo ferskate opsjes foar eveneminten opjaan - bygelyks 2 opsjes foar eveneminten fan Kubernetes en 2 skema's:

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

In lytse digresje: ja, shell-operator stipet draait crontab styl skripts. Mear details kinne fûn wurde yn dokumintaasje.

Om te ûnderskieden wêrom't de heak lansearre is, makket de shell-operator in tydlik bestân en jout it paad dernei troch yn in fariabele nei de heak BINDING_CONTEXT_TYPE. It bestân befettet in JSON-beskriuwing fan 'e reden foar it útfieren fan de heak. Bygelyks, elke 10 minuten sil de heak rinne mei de folgjende ynhâld:

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

... en moandei begjint it mei dit:

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

foar onKubernetesEvent D'r sille mear JSON-triggers wêze, om't it befettet in beskriuwing fan it objekt:

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

De ynhâld fan 'e fjilden kin wurde begrepen út har nammen, en mear details kinne wurde lêzen yn dokumintaasje. In foarbyld fan it krijen fan in boarnenamme út in fjild resourceName it brûken fan jq is al werjûn yn in heak dy't geheimen replikearret:

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

Jo kinne oare fjilden op in fergelykbere manier krije.

Wat is folgjende?

Yn it projekt repository, yn /foarbylden mappen, Der binne foarbylden fan heakken dy't klear binne om te rinnen op in kluster. By it skriuwen fan jo eigen heakken kinne jo se as basis brûke.

D'r is stipe foar it sammeljen fan metriken mei Prometheus - de beskikbere metriken wurde beskreaun yn 'e seksje METRICS.

Lykas jo miskien riede, is de shell-operator skreaun yn Go en ferspraat ûnder in Open Source-lisinsje (Apache 2.0). Wy sille tankber wêze foar elke ûntwikkelingsbystân projekt op GitHub: en stjerren, en problemen, en pull fersiken.

Lifting de sluier fan geheimhâlding, wy sille ek ynformearje jo dat shell-operator is lyts diel fan ús systeem dat tafoegings ynstalleare yn it Kubernetes-kluster bywurke hâlde kin en ferskate automatyske aksjes útfiere. Lês mear oer dit systeem ferteld letterlik op moandei op HighLoad++ 2019 yn Sint Petersburg - wy sille ynkoarten de fideo en transkripsje fan dit rapport publisearje.

Wy hawwe in plan om de rest fan dit systeem te iepenjen: de addon-operator en ús kolleksje fan haken en modules. Trouwens, addon-operator is al beskikber op github, mar de dokumintaasje dêrfoar is noch ûnderweis. De frijlitting fan 'e kolleksje fan modules is pland foar de simmer.

Bliuw op 'e hichte!

PS

Lês ek op ús blog:

Boarne: www.habr.com

Add a comment