Memperkenalkan shell-operator: membuat operator untuk Kubernetes semakin mudah

Sudah ada artikel di blog kita bercakap tentang keupayaan pengendali dalam Kubernetes dan bagaimana tulis sendiri operator mudah. Kali ini kami ingin membentangkan kepada perhatian anda penyelesaian Sumber Terbuka kami, yang membawa penciptaan pengendali ke tahap yang sangat mudah - lihat pengendali shell!

Mengapa?

Idea pengendali shell agak mudah: langgan acara dari objek Kubernetes, dan apabila acara ini diterima, lancarkan program luaran, memberikannya maklumat tentang acara itu:

Memperkenalkan shell-operator: membuat operator untuk Kubernetes semakin mudah

Keperluan untuk itu timbul apabila, semasa operasi kluster, tugas-tugas kecil mula kelihatan bahawa kami benar-benar mahu mengautomasikan dengan cara yang betul. Semua tugas kecil ini diselesaikan menggunakan skrip bash mudah, walaupun, seperti yang anda ketahui, adalah lebih baik untuk menulis operator di Golang. Jelas sekali, melabur dalam pembangunan skala penuh pengendali untuk setiap tugas kecil itu akan menjadi tidak berkesan.

Operator dalam 15 minit

Mari lihat contoh perkara yang boleh diautomatikkan dalam kelompok Kubernetes dan cara pengendali shell boleh membantu. Contohnya adalah seperti berikut: mereplikasi rahsia untuk mengakses pendaftaran docker.

Pod yang menggunakan imej daripada pendaftaran peribadi mesti mengandungi dalam manifesnya pautan ke rahsia dengan data untuk mengakses pendaftaran. Rahsia ini mesti dibuat dalam setiap ruang nama sebelum membuat pod. Ini boleh dilakukan secara manual, tetapi jika kita menyediakan persekitaran dinamik, maka ruang nama untuk satu aplikasi akan menjadi banyak. Dan jika tidak ada juga 2-3 permohonan... bilangan rahsia menjadi sangat besar. Dan satu lagi perkara tentang rahsia: Saya ingin menukar kunci untuk mengakses pendaftaran dari semasa ke semasa. Akhirnya, operasi manual sebagai penyelesaian sama sekali tidak berkesan — kita perlu mengautomasikan penciptaan dan pengemaskinian rahsia.

Automasi mudah

Mari tulis skrip shell yang dijalankan sekali setiap N saat dan semak ruang nama untuk kehadiran rahsia, dan jika tiada rahsia, maka ia dicipta. Kelebihan penyelesaian ini ialah ia kelihatan seperti skrip shell dalam cron - pendekatan klasik dan mudah difahami oleh semua orang. Kelemahannya ialah dalam selang waktu antara pelancarannya, ruang nama baharu boleh dibuat dan untuk beberapa waktu ia akan kekal tanpa rahsia, yang akan membawa kepada ralat dalam melancarkan pod.

Automasi dengan pengendali shell

Untuk skrip kami berfungsi dengan betul, pelancaran cron klasik perlu digantikan dengan pelancaran apabila ruang nama ditambahkan: dalam kes ini, anda boleh mencipta rahsia sebelum menggunakannya. Mari lihat bagaimana untuk melaksanakan ini menggunakan shell-operator.

Pertama, mari kita lihat skrip. Skrip dalam istilah pengendali shell dipanggil cangkuk. Setiap cangkuk apabila dijalankan dengan bendera --config memberitahu pengendali shell tentang pengikatannya, i.e. mengenai acara apa yang patut dilancarkan. Dalam kes kami, kami akan menggunakan onKubernetesEvent:

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

Diterangkan di sini bahawa kami berminat untuk menambah acara (add) objek jenis namespace.

Sekarang anda perlu menambah kod yang akan dilaksanakan apabila acara itu berlaku:

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

Hebat! Hasilnya ialah skrip yang kecil dan cantik. Untuk "menghidupkannya semula", terdapat dua langkah lagi: sediakan imej dan lancarkannya dalam kelompok.

Menyediakan imej dengan cangkuk

Jika anda melihat skrip, anda boleh melihat bahawa arahan digunakan kubectl и jq. Ini bermakna imej mesti mempunyai perkara berikut: cangkuk kami, pengendali cangkerang yang akan memantau acara dan menjalankan cangkuk, dan arahan yang digunakan oleh cangkuk (kubectl dan jq). Hub.docker.com sudah mempunyai imej siap sedia di mana shell-operator, kubectl dan jq dibungkus. Yang tinggal hanyalah menambah cangkuk mudah 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

Berlari dalam kelompok

Mari kita lihat cangkuk sekali lagi dan kali ini tuliskan tindakan apa dan dengan objek apa yang dilakukannya dalam kelompok:

  1. melanggan acara penciptaan ruang nama;
  2. mencipta rahsia dalam ruang nama selain daripada tempat ia dilancarkan.

Ternyata pod tempat imej kami akan dilancarkan mesti mempunyai kebenaran untuk melakukan tindakan ini. Ini boleh dilakukan dengan mencipta Akaun Perkhidmatan anda sendiri. Kebenaran mesti dilakukan dalam bentuk ClusterRole dan ClusterRoleBinding, kerana kami berminat dengan objek daripada keseluruhan kluster.

Penerangan akhir dalam YAML akan kelihatan seperti ini:

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

Anda boleh melancarkan imej yang dipasang sebagai Deployment yang mudah:

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

Untuk kemudahan, ruang nama yang berasingan dibuat di mana pengendali shell akan dilancarkan dan manifes yang dibuat akan digunakan:

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

Itu sahaja: pengendali shell akan bermula, melanggan acara penciptaan ruang nama dan menjalankan cangkuk apabila diperlukan.

Memperkenalkan shell-operator: membuat operator untuk Kubernetes semakin mudah

Oleh itu, skrip shell mudah bertukar menjadi pengendali sebenar untuk Kubernetes dan berfungsi sebagai sebahagian daripada kluster. Dan semua ini tanpa proses yang kompleks untuk membangunkan pengendali di Golang:

Memperkenalkan shell-operator: membuat operator untuk Kubernetes semakin mudah

Terdapat satu lagi ilustrasi mengenai perkara ini...Memperkenalkan shell-operator: membuat operator untuk Kubernetes semakin mudah

Kami akan mendedahkan maksudnya dengan lebih terperinci dalam salah satu penerbitan berikut.

penapisan

Menjejak objek adalah baik, tetapi selalunya terdapat keperluan untuk bertindak balas menukar beberapa sifat objek, sebagai contoh, untuk menukar bilangan replika dalam Deployment atau untuk menukar label objek.

Apabila acara tiba, pengendali shell menerima manifes JSON objek. Kita boleh memilih sifat yang menarik minat kita dalam JSON ini dan menjalankan cangkuk sahaja apabila mereka berubah. Terdapat medan untuk ini jqFilter, di mana anda perlu menentukan ungkapan jq yang akan digunakan pada manifes JSON.

Contohnya, untuk bertindak balas terhadap perubahan dalam label untuk objek Deployment, anda perlu menapis medan labels keluar dari padang metadata. Konfigurasi akan menjadi seperti ini:

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

Ungkapan jqFilter ini menukar manifes JSON yang panjang Deployment menjadi JSON pendek dengan label:

Memperkenalkan shell-operator: membuat operator untuk Kubernetes semakin mudah

shell-operator hanya akan menjalankan cangkuk apabila JSON pendek ini berubah, dan perubahan pada sifat lain akan diabaikan.

Konteks pelancaran cangkuk

Konfigurasi cangkuk membolehkan anda menentukan beberapa pilihan untuk acara - contohnya, 2 pilihan untuk acara daripada Kubernetes dan 2 jadual:

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

Penyimpangan kecil: ya, shell-operator menyokong menjalankan skrip gaya crontab. Butiran lanjut boleh didapati di dokumentasi.

Untuk membezakan sebab cangkuk dilancarkan, pengendali shell mencipta fail sementara dan menghantar laluan kepadanya dalam pembolehubah kepada cangkuk BINDING_CONTEXT_TYPE. Fail itu mengandungi penerangan JSON tentang sebab menjalankan cangkuk. Sebagai contoh, setiap 10 minit cangkuk akan berjalan dengan kandungan berikut:

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

... dan pada hari Isnin ia akan bermula dengan ini:

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

Untuk onKubernetesEvent Akan ada lebih banyak pencetus JSON, kerana ia mengandungi penerangan tentang objek:

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

Kandungan medan boleh difahami daripada namanya, dan butiran lanjut boleh dibaca dokumentasi. Contoh mendapatkan nama sumber daripada medan resourceName menggunakan jq telah ditunjukkan dalam cangkuk yang mereplikasi rahsia:

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

Anda boleh mendapatkan medan lain dengan cara yang sama.

Apa seterusnya?

Dalam repositori projek, dalam /contoh direktori, terdapat contoh cangkuk yang sedia untuk dijalankan pada kelompok. Apabila menulis cangkuk anda sendiri, anda boleh menggunakannya sebagai asas.

Terdapat sokongan untuk mengumpul metrik menggunakan Prometheus - metrik yang tersedia diterangkan dalam bahagian METRIK.

Seperti yang anda mungkin rasa, pengendali shell ditulis dalam Go dan diedarkan di bawah lesen Sumber Terbuka (Apache 2.0). Kami akan berterima kasih atas sebarang bantuan pembangunan projek di GitHub: dan bintang, dan isu, dan permintaan tarik.

Mengangkat tabir kerahsiaan, kami juga akan memberitahu anda bahawa shell-operator adalah kecil sebahagian daripada sistem kami yang boleh memastikan alat tambah dipasang dalam kelompok Kubernetes terkini dan melakukan pelbagai tindakan automatik. Baca lebih lanjut mengenai sistem ini diberitahu secara literal pada hari Isnin di HighLoad++ 2019 di St. Petersburg - kami akan menerbitkan video dan transkrip laporan ini tidak lama lagi.

Kami mempunyai rancangan untuk membuka seluruh sistem ini: pengendali tambahan dan koleksi cangkuk dan modul kami. By the way, addon-operator sudah pun tersedia di github, tetapi dokumentasi untuknya masih dalam proses. Pengeluaran koleksi modul dirancang untuk musim panas.

Tinggal!

PS

Baca juga di blog kami:

Sumber: www.habr.com

Beli pengehosan yang boleh dipercayai untuk tapak dengan perlindungan DDoS, pelayan VPS VDS 🔥 Beli pengehosan laman web yang boleh dipercayai dengan perlindungan DDoS, pelayan VPS VDS | ProHoster