Ide dari operator shell cukup sederhana: berlangganan event dari objek Kubernetes, dan ketika event ini diterima, luncurkan program eksternal, berikan informasi tentang event tersebut:
Kebutuhan akan hal ini muncul ketika, selama pengoperasian cluster, tugas-tugas kecil mulai muncul yang benar-benar ingin kami otomatisasi dengan cara yang benar. Semua tugas kecil ini diselesaikan dengan menggunakan skrip bash sederhana, meskipun, seperti yang Anda tahu, lebih baik menulis operator di Golang. Tentu saja, berinvestasi dalam pengembangan operator skala penuh untuk setiap tugas kecil seperti itu tidak akan efektif.
Operator dalam 15 menit
Mari kita lihat contoh apa yang dapat diotomatisasi dalam cluster Kubernetes dan bagaimana operator shell dapat membantu. Contohnya adalah sebagai berikut: mereplikasi rahasia untuk mengakses registri buruh pelabuhan.
Pod yang menggunakan image dari registri pribadi harus berisi tautan ke rahasia dengan data untuk mengakses registri di manifesnya. Rahasia ini harus dibuat di setiap namespace sebelum membuat pod. Hal ini dapat dilakukan secara manual, namun jika kita mengatur lingkungan dinamis, maka namespace untuk satu aplikasi akan menjadi banyak. Dan kalau yang aplikasinya juga tidak 2-3... jumlah rahasianya jadi banyak sekali. Dan satu hal lagi tentang rahasia: Saya ingin mengubah kunci untuk mengakses registri dari waktu ke waktu. Pada akhirnya, operasi manual sebagai solusi sepenuhnya tidak efektif — kita perlu mengotomatiskan pembuatan dan pembaruan rahasia.
Otomatisasi sederhana
Mari kita menulis skrip shell yang berjalan setiap N detik sekali dan memeriksa namespace untuk mengetahui keberadaan rahasia, dan jika tidak ada rahasia, maka rahasia itu dibuat. Keuntungan dari solusi ini adalah tampilannya seperti skrip shell di cron - pendekatan klasik dan dapat dimengerti oleh semua orang. Kelemahannya adalah dalam interval antara peluncurannya, namespace baru dapat dibuat dan untuk beberapa waktu tetap tanpa rahasia, yang akan menyebabkan kesalahan dalam peluncuran pod.
Otomatisasi dengan operator shell
Agar skrip kami berfungsi dengan benar, peluncuran cron klasik perlu diganti dengan peluncuran ketika namespace ditambahkan: dalam hal ini, Anda dapat membuat rahasia sebelum menggunakannya. Mari kita lihat bagaimana mengimplementasikannya menggunakan operator shell.
Pertama, mari kita lihat skripnya. Skrip dalam istilah operator shell disebut hooks. Setiap kait saat dijalankan dengan bendera --config memberi tahu operator shell tentang pengikatannya, mis. tentang acara apa yang harus diluncurkan. Dalam kasus kami, kami akan menggunakan onKubernetesEvent:
#!/bin/bash
if [[ $1 == "--config" ]] ; then
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "namespace",
"event":["add"]
}
]}
EOF
fi
Di sini dijelaskan bahwa kami tertarik untuk menambahkan acara (add) objek bertipe namespace.
Sekarang Anda perlu menambahkan kode yang akan dieksekusi ketika peristiwa tersebut terjadi:
#!/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
Besar! Hasilnya adalah naskah yang kecil dan indah. Untuk “menghidupkannya kembali”, ada dua langkah yang tersisa: menyiapkan image dan meluncurkannya di cluster.
Mempersiapkan gambar dengan kail
Jika Anda melihat skripnya, Anda dapat melihat bahwa perintah-perintah tersebut digunakan kubectl и jq. Ini berarti bahwa gambar tersebut harus memiliki hal-hal berikut: hook kita, operator shell yang akan memantau kejadian dan menjalankan hook, dan perintah yang digunakan oleh hook (kubectl dan jq). Hub.docker.com sudah memiliki image siap pakai yang mengemas operator shell, kubectl, dan jq. Yang tersisa hanyalah menambahkan pengait sederhana Dockerfile:
Mari kita lihat hooknya lagi dan kali ini tuliskan tindakan apa dan dengan objek apa yang dilakukannya di cluster:
berlangganan acara pembuatan namespace;
membuat rahasia di ruang nama selain tempat peluncurannya.
Ternyata pod tempat gambar kita akan diluncurkan harus memiliki izin untuk melakukan tindakan ini. Ini dapat dilakukan dengan membuat ServiceAccount Anda sendiri. Izin tersebut harus dilakukan dalam bentuk ClusterRole dan ClusterRoleBinding, karena kami tertarik pada objek dari seluruh cluster.
Deskripsi akhir di YAML akan terlihat seperti ini:
Itu saja: operator shell akan mulai, berlangganan acara pembuatan namespace dan menjalankan hook bila diperlukan.
Dengan demikian, skrip shell sederhana berubah menjadi operator nyata untuk Kubernetes dan bekerja sebagai bagian dari cluster. Dan semua ini tanpa proses rumit dalam pengembangan operator di Golang:
Ada ilustrasi lain mengenai hal ini...
Maknanya akan kami ungkapkan lebih detail dalam salah satu publikasi berikut.
penyaringan
Melacak objek memang bagus, tetapi sering kali ada kebutuhan untuk bereaksi mengubah beberapa properti objek, misalnya, untuk mengubah jumlah replika di Deployment atau mengubah label objek.
Ketika suatu peristiwa tiba, operator shell menerima manifes JSON dari objek tersebut. Kita dapat memilih properti yang kita minati di JSON ini dan menjalankan hook hanya ketika mereka berubah. Ada bidang untuk ini jqFilter, di mana Anda perlu menentukan ekspresi jq yang akan diterapkan ke manifes JSON.
Misalnya, untuk merespons perubahan label pada objek Deployment, Anda perlu memfilter bidang tersebut labels keluar lapangan metadata. Konfigurasinya akan seperti ini:
Penyimpangan kecil: ya, dukungan operator shell menjalankan skrip gaya crontab. Detail lebih lanjut dapat ditemukan di dokumentasi.
Untuk membedakan mengapa hook diluncurkan, operator shell membuat file sementara dan meneruskan path ke file tersebut dalam variabel ke hook BINDING_CONTEXT_TYPE. File tersebut berisi deskripsi JSON tentang alasan menjalankan hook. Misalnya, setiap 10 menit hook akan berjalan dengan konten berikut:
Isi dari field-field tersebut dapat dipahami dari namanya, dan lebih jelasnya dapat dibaca di dokumentasi. Contoh mendapatkan nama sumber daya dari suatu bidang resourceName menggunakan jq telah ditampilkan di hook yang mereplikasi rahasia:
jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH
Anda bisa mendapatkan bidang lain dengan cara serupa.
Apa selanjutnya?
Di repositori proyek, di /contoh direktori, terdapat contoh hook yang siap dijalankan pada cluster. Saat menulis hook Anda sendiri, Anda bisa menggunakannya sebagai dasar.
Ada dukungan untuk mengumpulkan metrik menggunakan Prometheus - metrik yang tersedia dijelaskan di bagian ini METRIK.
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 pembangunan apa pun proyek di GitHub: dan bintang, dan masalah, dan permintaan tarik.
Mengangkat tabir kerahasiaan, kami juga akan memberi tahu Anda bahwa operator shell adalah kecil bagian dari sistem kami yang dapat terus memperbarui add-on yang terpasang di cluster Kubernetes dan melakukan berbagai tindakan otomatis. Baca lebih lanjut tentang sistem ini diberitahu secara harfiah pada hari Senin di HighLoad++ 2019 di St. Petersburg - kami akan segera mempublikasikan video dan transkrip laporan ini.
Kami memiliki rencana untuk membuka sisa sistem ini: operator tambahan dan koleksi kait dan modul kami. Omong-omong, addon-operator sudah ada tersedia di github, namun dokumentasinya masih dalam proses. Pelepasan koleksi modul direncanakan pada musim panas.