Sudah ada artikel di blog kami tentang
kemampuan operator di Kubernetes dan cara
menulis operator sederhana sendiri . Kali ini kami ingin menyampaikan kepada Anda solusi Open Source kami, yang membawa kreasi operator ke tingkat yang sangat mudah - berkenalan dengan
operator shell !
Mengapa
Gagasan operator shell cukup sederhana: berlangganan acara dari objek Kubernetes, dan ketika menerima acara ini, mulai program eksternal, berikan informasi tentang acara tersebut:

Perlunya muncul bersama kami ketika, selama operasi cluster, tugas-tugas kecil mulai tampak bahwa kami benar-benar ingin mengotomatisasi dengan cara yang benar. Semua tugas kecil ini diselesaikan dengan bantuan skrip bash sederhana, meskipun, seperti yang Anda tahu, operator lebih baik ditulis dalam Golang. Jelas, berinvestasi dalam pengembangan operator skala penuh untuk setiap tugas kecil seperti itu tidak efisien.
Operator dalam 15 menit
Mari kita lihat contoh apa yang dapat diotomatiskan dalam kluster Kubernetes dan bagaimana operator shell akan membantu. Contohnya adalah sebagai berikut: menduplikasi rahasia untuk mengakses register buruh pelabuhan.
Pod yang menggunakan gambar dari registri pribadi harus berisi dalam manifesnya tautan ke rahasia dengan data untuk mengakses registri. Rahasia ini harus dibuat di setiap namespace sebelum membuat pod. Sangat mungkin untuk melakukan ini secara manual, tetapi jika kita mengatur lingkungan yang dinamis, maka namespace untuk satu aplikasi akan menjadi banyak. Dan jika aplikasi juga bukan 2-3 ... jumlah rahasia menjadi sangat besar. Dan satu hal lagi tentang rahasia: Saya ingin mengubah kunci untuk mengakses registri dari waktu ke waktu. Akibatnya,
operasi manual sebagai solusi sama
sekali tidak efektif - Anda perlu mengotomatiskan pembuatan dan pemutakhiran rahasia.
Otomatisasi mudah
Kami akan menulis skrip shell yang berjalan sekali setiap N detik dan memeriksa rahasia namespace, dan jika tidak ada rahasia, maka itu dibuat. Keuntungan dari solusi ini adalah ia terlihat seperti skrip shell di cron - pendekatan klasik dan mudah dipahami. Downside adalah bahwa dalam interval antara peluncurannya namespace baru dapat dibuat dan untuk beberapa waktu akan tetap tanpa rahasia, yang akan menyebabkan kesalahan dalam meluncurkan pod.
Otomasi dengan shell-operator
Agar skrip kami berfungsi dengan benar, peluncuran cron klasik perlu diganti dengan peluncuran ketika acara namespace ditambahkan: dalam hal ini, Anda dapat mengatur untuk membuat rahasia sebelum menggunakannya. Mari kita lihat bagaimana mengimplementasikan ini menggunakan shell-operator.
Pertama, mari kita parsing skrip. Skrip dalam hal shell-operator disebut kait. Setiap kait saat startup dengan flag
--config
memberi tahu operator shell tentang binding-nya, mis. oleh acara apa yang perlu diluncurkan. Dalam kasus kami, kami akan menggunakan
onKubernetesEvent
:
Dijelaskan di sini bahwa kami tertarik pada acara untuk menambahkan (
add
) objek dari
namespace
.
Sekarang Anda perlu menambahkan kode yang akan dieksekusi ketika acara terjadi:
Hebat! Hasilnya adalah sebuah skrip kecil yang indah. Untuk "menghidupkan kembali" itu, dua langkah tetap: untuk menyiapkan gambar dan menjalankannya di cluster.
Mempersiapkan gambar dengan kail
Jika Anda melihat skrip, Anda dapat melihat bahwa perintah
kubectl
dan
jq
. Ini berarti bahwa gambar harus memiliki hal-hal berikut: kait kami, operator shell yang akan memantau acara dan menjalankan kait, serta perintah yang digunakan oleh kait (kubectl dan jq).
Hub.docker.com sudah memiliki gambar siap pakai di mana shell-operator, kubectl dan jq dikemas. Tetap menambahkan pengait dengan
Dockerfile
sederhana:
$ 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
Peluncuran cluster
Sekali lagi, mari kita lihat hook dan kali ini tuliskan tindakan apa dan dengan objek apa yang dilakukan di cluster:
- Berlangganan acara namespace
- menciptakan rahasia di ruang nama selain tempat menjalankannya.
Ternyata pod di mana gambar kita akan diluncurkan harus memiliki izin untuk tindakan ini. Ini dapat dilakukan dengan membuat ServiceAccount Anda sendiri. Izin harus dibuat dalam bentuk ClusterRole dan ClusterRoleBinding, karena kami tertarik pada objek dari seluruh cluster.
Deskripsi akhir dalam YAML adalah sesuatu 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 dapat menjalankan gambar yang dirakit dalam bentuk Penerapan sederhana:
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 kenyamanan, namespace terpisah dibuat di mana shell-operator akan diluncurkan dan manifes yang dibuat diterapkan:
$ 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 saja: operator shell akan mulai, berlangganan acara pembuatan namespace dan mulai kail bila perlu.

Dengan demikian,
skrip shell sederhana berubah menjadi operator nyata untuk Kubernetes dan berfungsi sebagai bagian integral dari kluster. Dan semua ini - tanpa proses rumit mengembangkan operator di Golang:

Penyaringan
Melacak objek itu baik, tetapi sering kali perlu merespons
perubahan dalam beberapa properti objek , misalnya, pada perubahan jumlah replika di Deployment, atau pada perubahan label objek.
Ketika suatu peristiwa tiba, operator shell menerima manifes JSON objek. Anda dapat memilih properti yang menarik bagi kami di JSON ini dan menjalankan hook
hanya ketika mereka berubah. Untuk melakukan ini, bidang
jqFilter
, di mana Anda perlu menentukan ekspresi jq yang akan diterapkan pada manifes JSON.
Misalnya, untuk menanggapi perubahan label pada objek Penempatan, Anda perlu memfilter bidang
labels
dari bidang
metadata
. Konfigurasi akan seperti ini:
cat <<EOF { "onKubernetesEvent": [ { "kind": "deployment", "event":["update"], "jqFilter": ".metadata.labels" } ]} EOF
Ungkapan ini di jqFilter mengubah manifest JSON panjang Deployment menjadi JSON pendek dengan label:

Shell-operator hanya akan memicu pengait ketika JSON pendek ini berubah dan perubahan pada properti lainnya diabaikan.
Konteks peluncuran hook
Konfigurasi hook memungkinkan Anda menentukan beberapa opsi untuk acara - misalnya, 2 opsi untuk acara dari Kubernetes dan 2 jadwal:
{"onKubernetesEvent":[ {"name":"OnCreatePod", "kind": "pod", "event":["add"] }, {"name":"OnModifiedNamespace", "kind": "namespace", "event":["update"], "jqFilter": ".metadata.labels" } ], "schedule": [ { "name":"every 10 min", "crontab":"0 */10 * * * *" }, {"name":"on Mondays at 12:10", "crontab": "0 10 12 * * 1" ]}
Penyimpangan kecil: ya, operator shell mendukung menjalankan skrip gaya crontab . Anda dapat membaca lebih lanjut di dokumentasi .Untuk membedakan mengapa hook diluncurkan, operator shell membuat file sementara dan meneruskan path ke
BINDING_CONTEXT_TYPE
di variabel
BINDING_CONTEXT_TYPE
. File tersebut berisi deskripsi JSON tentang alasan pengait dimulai. Misalnya, setiap 10 menit sebuah pengait akan dimulai dengan konten berikut:
[{ "binding": "every 10 min"}]
... dan pada hari Senin akan dimulai dengan ini:
[{ "binding": "every 10 min"}, { "binding": "on Mondays at 12:10"}]
Untuk
onKubernetesEvent
akan ada lebih banyak JSON yang dipecat sejak itu itu berisi deskripsi objek:
[ { "binding": "onCreatePod", "resourceEvent": "add", "resourceKind": "pod", "resourceName": "foo", "resourceNamespace": "bar" } ]
Isi kolom dapat dipahami dari namanya, dan lebih terinci - baca di
dokumentasi . Contoh untuk mendapatkan nama sumber daya dari bidang
resourceName
menggunakan jq telah ditunjukkan di sebuah pengait yang mereplikasi rahasia:
jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH
Demikian pula, Anda bisa mendapatkan bidang yang tersisa.
Apa selanjutnya
Di repositori proyek, di
direktori / contoh , ada contoh kait yang siap dijalankan di kluster. Saat menulis kait Anda, Anda dapat menganggapnya sebagai dasar.
Ada dukungan untuk mengumpulkan metrik menggunakan Prometheus - metrik yang tersedia ditulis di bagian
METRICS .
Seperti yang Anda duga, operator shell ditulis dalam Go dan didistribusikan di bawah lisensi Open Source (Apache 2.0). Kami akan berterima kasih atas bantuan apa pun dalam mengembangkan
proyek di GitHub : tanda bintang, masalah, dan menarik permintaan.
Membuka tabir kerahasiaan, kami juga menginformasikan bahwa operator-shell adalah bagian
kecil dari sistem kami, yang dapat terus memperbarui pengaya yang dipasang di kluster Kubernetes dan melakukan berbagai tindakan otomatis. Kami
berbicara tentang sistem ini secara lebih rinci pada hari Senin di HighLoad ++ 2019 di St. Petersburg - video dan transkrip laporan ini akan segera diterbitkan.
Kami memiliki rencana untuk membuka sisa sistem ini: addon-operator dan koleksi kait dan modul kami. Omong-omong, addon-operator sudah
tersedia di GitHub , tetapi dokumentasi untuknya masih dalam proses. Pelepasan koleksi modul direncanakan di musim panas.
Tetap disini!
PS
Baca juga di blog kami: