
Pada 8 April, di konferensi
Saint HighLoad ++ 2019 , dalam kerangka kerja bagian DevOps dan Operasi, sebuah laporan dibuat berjudul "Memperluas dan Melengkapi Kubernetes", yang dibuat oleh tiga karyawan Flant. Di dalamnya, kami berbicara tentang berbagai situasi di mana kami ingin memperluas dan melengkapi kemampuan Kubernetes, tetapi kami tidak menemukan solusi yang siap pakai dan sederhana. Solusi yang diperlukan muncul dalam bentuk proyek Open Source, dan presentasi ini juga didedikasikan untuk mereka.
Secara tradisi, kami senang menyajikan
video dengan laporan (50 menit, jauh lebih informatif daripada artikel) dan penekanan utama dalam bentuk teks. Ayo pergi!
K8s Kernel dan Add-on
Kubernetes mengubah pendekatan industri dan administrasi yang sudah lama ada:
- Berkat abstraksinya , kami tidak lagi beroperasi dengan konsep seperti mengonfigurasi konfigurasi atau menjalankan perintah (Chef, Ansible ...), tetapi menggunakan pengelompokan wadah, layanan, dll.
- Kami dapat menyiapkan aplikasi tanpa memikirkan nuansa platform spesifik tempat peluncurannya: bare metal, cloud salah satu penyedia, dll.
- Dengan K8, praktik terbaik untuk mengatur infrastruktur menjadi lebih mudah diakses dari sebelumnya: penskalaan, penyembuhan sendiri, toleransi kesalahan, dll.
Namun, tentu saja, semuanya tidak begitu mulus: dengan Kubernetes datang tantangan baru - mereka sendiri.
Kubernetes
bukan kombinasi yang menyelesaikan semua masalah semua pengguna.
Inti Kubernetes hanya bertanggung jawab untuk sekumpulan fungsi minimum yang diperlukan yang ada di
setiap kluster:

Dalam inti Kubernetes, satu set primitif dasar didefinisikan - untuk pengelompokan kontainer, mengatur lalu lintas, dan sebagainya. Kami membicarakannya lebih detail dalam sebuah
laporan 2 tahun yang lalu .

Di sisi lain, K8 menawarkan peluang besar untuk memperluas fungsi yang tersedia, yang membantu untuk menutup kebutuhan pengguna khusus lainnya. Administrator cluster bertanggung jawab atas penambahan Kubernetes, yang harus menginstal dan mengkonfigurasi semua yang diperlukan sehingga cluster mereka "menemukan bentuk yang tepat" [untuk menyelesaikan masalah spesifik mereka]. Tambahan apa ini? Mari kita lihat beberapa contoh.
Contoh penambahan
Setelah menginstal Kubernetes, kita mungkin akan terkejut bahwa jaringan, yang sangat diperlukan untuk interaksi pod baik di dalam node maupun di antara node, tidak bekerja dengan sendirinya. Inti Kubernetes tidak menjamin koneksi yang diperlukan - sebaliknya, inti Kubernetes menentukan
antarmuka jaringan (
CNI ) untuk add-on pihak ketiga. Kita harus menginstal salah satu dari tambahan ini, yang akan bertanggung jawab untuk konfigurasi jaringan.

Contoh dekat adalah solusi penyimpanan data (disk lokal, perangkat blok jaringan, Ceph ...). Awalnya, mereka berada di kernel, tetapi dengan munculnya
CSI, situasinya berubah menjadi serupa yang sudah dijelaskan: di Kubernetes, antarmuka, dan implementasinya, dalam modul pihak ketiga.
Di antara contoh lain:
- Pengendali masuk (untuk ulasan, lihat artikel terbaru kami ) .
- manajer sertifikat :

- Operator adalah seluruh kelas dari add-on (yang termasuk manajer sertifikat yang disebutkan), mereka mendefinisikan primitif (s) dan pengontrol (s). Logika pekerjaan mereka hanya dibatasi oleh imajinasi kita dan memungkinkan kita untuk mengubah komponen infrastruktur siap pakai (misalnya, DBMS) menjadi primitif, yang jauh lebih mudah untuk dikerjakan (daripada dengan satu set wadah dan pengaturannya). Sejumlah besar operator telah ditulis - meskipun banyak dari mereka belum siap untuk diproduksi, ini hanya masalah waktu:

- Metrik adalah ilustrasi lain tentang bagaimana Kubernetes memisahkan antarmuka (Metrik API) dari implementasi (add-on pihak ketiga seperti adaptor Prometheus, agen cluster Datadog ...).
- Untuk pemantauan dan statistik , di mana dalam praktiknya tidak hanya Prometheus dan Grafana yang dibutuhkan , tetapi juga metrik-negara-metrik, simpul-eksportir, dll.
Dan ini bukan daftar lengkap add-ons ... Misalnya, kami di Flant company saat ini menginstal
29 add-ons untuk setiap cluster Kubernetes (semuanya membuat total 249 objek Kubernetes). Sederhananya, kita tidak melihat kehidupan sebuah cluster tanpa tambahan.
Otomasi
Operator dirancang untuk mengotomatiskan operasi rutin yang kita hadapi setiap hari. Berikut adalah contoh kehidupan yang bagus untuk menulis operator:
- Ada registri pribadi (mis. Yang membutuhkan login) dengan gambar untuk aplikasi. Diasumsikan bahwa setiap pod terikat dengan rahasia khusus yang memungkinkan otentikasi dalam registri. Tugas kami adalah memastikan bahwa rahasia ini ditemukan di namespace, sehingga pod dapat mengunduh gambar. Mungkin ada banyak aplikasi (masing-masing membutuhkan rahasia), dan berguna untuk memperbarui rahasia itu sendiri secara berkala, sehingga opsi untuk membuka rahasia dengan tangan Anda menghilang. Di sini operator datang untuk menyelamatkan: kami membuat controller yang akan menunggu namespace muncul dan menambahkan rahasia ke namespace untuk acara ini.
- Misalkan akses default dari pod ke Internet dilarang. Tetapi kadang-kadang mungkin diperlukan: logis untuk mekanisme izin akses untuk bekerja hanya tanpa memerlukan keterampilan khusus, misalnya, dengan kehadiran label tertentu di namespace. Bagaimana operator akan membantu kami di sini? Kontroler dibuat yang mengharapkan label muncul di namespace dan menambahkan kebijakan yang sesuai untuk mengakses Internet.
- Situasi serupa: mari kita perlu menambahkan noda tertentu ke simpul jika memiliki label yang sama (dengan semacam awalan). Tindakan dengan operator jelas ...
Di gugus mana pun, perlu untuk menyelesaikan tugas-tugas rutin, dan melakukan ini
dengan benar - menggunakan operator.
Merangkum semua cerita yang dijelaskan, kami sampai pada kesimpulan bahwa
untuk pekerjaan yang nyaman di Kubernetes diperlukan : a) untuk
menginstal add-on , b) untuk
mengembangkan operator (untuk menyelesaikan tugas admin sehari-hari).
Bagaimana cara menulis pernyataan untuk Kubernetes?
Secara umum, skema ini sederhana:

... tetapi ternyata:
- API Kubernetes adalah hal yang agak non-sepele yang membutuhkan banyak waktu untuk dikuasai;
- pemrograman juga bukan untuk semua orang (Go dipilih sebagai bahasa pilihan karena ada kerangka kerja khusus untuk itu - Operator SDK );
- dengan kerangka kerja seperti itu, situasi serupa.
Intinya:
untuk menulis controller (operator), Anda harus
menghabiskan sumber daya yang signifikan untuk mempelajari materi. Ini akan dibenarkan untuk operator "besar" - katakanlah, untuk DBMS MySQL. Tetapi jika kita mengingat contoh-contoh yang dijelaskan di atas (mengungkap rahasia, mengakses pod ke Internet ...), yang juga ingin kita lakukan dengan benar, maka kita akan memahami bahwa upaya yang dilakukan akan lebih besar daripada hasil yang sekarang dibutuhkan:

Secara umum, dilema muncul: menghabiskan banyak sumber daya dan menemukan alat yang tepat untuk menulis pernyataan atau bertindak "dengan cara lama" (tetapi dengan cepat). Untuk mengatasinya - untuk menemukan kompromi di antara yang ekstrem ini - kami menciptakan proyek kami sendiri:
shell-operator (lihat juga pengumuman terbarunya tentang hub) .
Operator shell
Bagaimana cara kerjanya? Di cluster ada pod di mana Go-binary dengan shell-operator terletak. Satu set
kait disimpan di sebelahnya
(untuk lebih jelasnya, lihat di bawah) . Shell-operator itu sendiri berlangganan
acara -
acara tertentu di API Kubernetes, di mana ia meluncurkan kait terkait.
Bagaimana operator shell memahami kait mana yang harus dipicu dalam kejadian apa? Informasi ini diteruskan ke operator shell oleh pengait sendiri dan mereka membuatnya sangat sederhana.
Hook adalah skrip Bash atau file yang dapat dieksekusi lainnya yang mendukung argumen tunggal
--config
dan mengembalikan JSON sebagai responsnya. Yang terakhir menentukan objek mana yang menarik baginya dan peristiwa apa (untuk objek ini) harus bereaksi:

Saya akan mengilustrasikan implementasi shell-operator dari salah satu contoh kami - mengungkap rahasia untuk mengakses registry pribadi dengan gambar aplikasi. Ini terdiri dari dua tahap.
Latihan: 1. Menulis kail
Langkah pertama dalam hook adalah untuk memproses
--config
, menunjukkan bahwa kami tertarik pada namespace, dan secara khusus - saat pembuatannya:
[[ $1 == "--config" ]] ; then cat << EOF { "onKubernetesEvent": [ { "kind": "namespace", "event": ["add"] } ] } EOF …
Seperti apa logikanya? Cukup sederhana juga:
… else createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH) kubectl create -n ${createdNamespace} -f - << EOF Kind: Secret ... EOF fi
Langkah pertama adalah mencari tahu namespace mana yang telah dibuat, dan langkah kedua adalah membuat rahasia untuk namespace ini melalui
kubectl
.
Latihan: 2. Menyusun gambar
Tetap mentransfer kait yang dibuat ke operator shell - bagaimana melakukan ini? Shell-operator itu sendiri disediakan sebagai gambar Docker, jadi tugas kami adalah menambahkan hook ke direktori khusus pada gambar ini:
FROM flant/shell-operator:v1.0.0-beta.1 ADD my-handler.sh /hooks
Tetap mengumpulkan dan mendorongnya:
$ docker build -t registry.example.com/my-operator:v1 . $ docker push registry.example.com/my-operator:v1
Sentuhan terakhir adalah menyematkan gambar dalam sebuah cluster. Untuk melakukan ini, tulis
Penempatan :
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: my-operator spec: template: spec: containers: - name: my-operator image: registry.example.com/my-operator:v1 # 1 serviceAccountName: my-operator # 2
Di dalamnya, Anda perlu memperhatikan dua poin:
- Indikasi gambar yang baru saja dibuat;
- ini adalah komponen sistem yang (minimal) membutuhkan hak untuk berlangganan acara di Kubernetes dan untuk mengungkapkan rahasia berdasarkan namespace, jadi kami membuat ServiceAccount (dan seperangkat aturan) untuk hook.
Hasilnya - kami memecahkan masalah kami dengan cara yang
asli di Kubernetes, menciptakan operator untuk mengungkapkan rahasia.
Fitur-fitur shell-operator lainnya
Untuk membatasi objek dari jenis pilihan yang akan digunakan oleh kait,
Anda dapat memfilternya dengan memfilter menurut label tertentu (atau menggunakan
matchExpressions
):
"onKubernetesEvent": [ { "selector": { "matchLabels": { "foo": "bar", }, "matchExpressions": [ { "key": "allow", "operation": "In", "values": ["wan", "warehouse"], }, ], } … } ]
Sebuah
mekanisme deduplikasi disediakan, yang - menggunakan filter jq - memungkinkan Anda untuk mengkonversi objek JSON besar menjadi objek kecil, di mana hanya parameter-parameter yang tersisa yang ingin kami pantau perubahannya.
Ketika hook dipanggil, operator shell meneruskannya
data tentang objek , yang dapat digunakan untuk kebutuhan apa pun.
Peristiwa di mana kait dipicu tidak terbatas pada peristiwa Kubernetes: operator shell menyediakan dukungan untuk
memanggil kait tepat waktu (mirip dengan crontab dalam penjadwal tradisional), serta acara
onStartup khusus. Semua acara ini dapat digabungkan dan ditugaskan ke pengait yang sama.
Dan dua fitur lagi dari shell-operator:
- Ini bekerja secara tidak sinkron . Karena peristiwa Kubernetes (misalnya, pembuatan objek), peristiwa lainnya (misalnya, penghapusan objek yang sama) dapat terjadi di gugus, dan ini harus diperhitungkan dalam kaitan. Jika kait gagal, maka secara default akan dipanggil lagi sampai berhasil diselesaikan (perilaku ini dapat diubah).
- Ini mengekspor metrik untuk Prometheus, yang dengannya Anda dapat memahami apakah operator shell berfungsi, mencari tahu jumlah kesalahan untuk setiap kait, dan ukuran antrian saat ini.
Untuk meringkas bagian laporan ini:

Instalasi Pengaya
Untuk kerja yang nyaman dengan Kubernetes, kebutuhan untuk menginstal add-on juga disebutkan. Saya akan membicarakannya pada contoh cara perusahaan kami dengan cara kami melakukannya sekarang.
Kami mulai bekerja dengan Kubernetes dengan beberapa cluster, satu-satunya tambahan adalah Ingress. Itu perlu untuk meletakkannya di setiap cluster secara berbeda, dan kami membuat beberapa konfigurasi YAML untuk lingkungan yang berbeda: bare metal, AWS ...
Ada lebih banyak cluster - lebih banyak konfigurasi. Selain itu, kami meningkatkan konfigurasi ini sendiri, akibatnya menjadi sangat heterogen:

Untuk mengatur semuanya, kami mulai dengan sebuah skrip (
install-ingress.sh
), yang mengambil jenis cluster yang akan digunakan sebagai argumen, menghasilkan konfigurasi YAML yang diinginkan dan meluncurkannya ke Kubernetes.
Singkatnya, jalan kita selanjutnya dan argumen yang terkait dengannya adalah sebagai berikut:
- untuk bekerja dengan konfigurasi YAML, mesin template diperlukan (pada tahap pertama ini adalah sed sederhana);
- dengan peningkatan jumlah cluster, kebutuhan datang untuk pembaruan otomatis (solusi paling awal adalah dengan meletakkan skrip di Git, perbarui dengan cron, dan jalankan);
- skrip yang sama diperlukan untuk Prometheus (
install-prometheus.sh
), namun perlu dicatat bahwa skrip ini membutuhkan lebih banyak input data, serta penyimpanannya (dengan cara yang baik, terpusat dan dalam cluster), dan beberapa data (kata sandi) dapat secara otomatis dihasilkan :

- risiko memasukkan sesuatu yang salah ke semakin banyak kelompok terus meningkat, jadi kami menyadari bahwa para penginstal (mis., dua skrip: untuk Ingress dan Prometheus) memerlukan penyiapan panggung (beberapa cabang di Git, beberapa cron untuk memperbaruinya di yang sesuai: cluster stabil atau uji);
- menjadi sulit untuk bekerja dengan
kubectl apply
, karena tidak deklaratif dan hanya dapat membuat objek, tetapi tidak membuat keputusan tentang status mereka / menghapusnya; - kekurangan beberapa fungsi yang tidak kita sadari pada saat itu:
- kontrol penuh atas hasil pembaruan cluster,
- penentuan beberapa parameter secara otomatis (input untuk skrip instalasi) berdasarkan data yang dapat diperoleh dari kluster (penemuan),
- pengembangan logis dalam bentuk penemuan berkelanjutan.
Kami menyadari semua akumulasi pengalaman ini dalam kerangka proyek kami yang lain -
addon-operator .
Addon-operator
Ini didasarkan pada operator shell yang telah disebutkan. Seluruh sistem adalah sebagai berikut:
Untuk kait shell-operator ditambahkan:
- penyimpanan nilai
- Grafik helm
- komponen yang memantau repositori nilai-nilai dan - jika ada perubahan - meminta Helm untuk memutar kembali bagan.

Dengan demikian, kita dapat menanggapi suatu peristiwa di Kubernetes, meluncurkan sebuah hook, dan dari hook ini - buat perubahan pada repositori, setelah itu bagan akan dimuat ulang. Dalam skema yang dihasilkan, kami memilih satu set kait dan bagan menjadi satu komponen, yang kami sebut
modul :

Mungkin ada banyak modul, dan untuk itu kami menambahkan kait global, penyimpanan nilai global, dan komponen yang memantau penyimpanan global ini.
Sekarang sesuatu sedang terjadi di Kubernetes, kita dapat menanggapi ini dengan hook global dan mengubah sesuatu di repositori global. Perubahan ini akan diperhatikan dan akan menyebabkan rollback semua modul di kluster:

Skema ini memenuhi semua persyaratan untuk menginstal add-on yang diumumkan di atas:
- Helm bertanggung jawab atas standardisasi dan deklaratifitas.
- Masalah pembaruan-otomatis diselesaikan menggunakan hook global, yang masuk ke registri pada jadwal dan, jika melihat gambar baru dari sistem di sana, putar ulang itu (yaitu, "itu sendiri").
- Penyimpanan pengaturan di cluster diimplementasikan menggunakan ConfigMap , di mana data primer untuk penyimpanan dicatat (saat startup mereka dimuat ke penyimpanan).
- Masalah pembuatan kata sandi, penemuan dan penemuan berkelanjutan diselesaikan dengan menggunakan kait.
- Pementasan dicapai berkat tag yang didukung Docker di luar kotak.
- Hasilnya dipantau menggunakan metrik yang dengannya kami dapat memahami statusnya.
Seluruh sistem ini diimplementasikan sebagai biner tunggal di Go, yang disebut addon-operator. Berkat ini, skema ini terlihat lebih sederhana:

Komponen utama dalam diagram ini adalah satu set modul
(berwarna abu-abu di bawah) . Sekarang kita dapat menulis modul dengan sedikit usaha untuk add-on yang diinginkan dan memastikan bahwa itu akan dipasang di setiap cluster, akan diperbarui dan menanggapi peristiwa yang dibutuhkan dalam cluster.
Flant menggunakan
addon-operator di 70+ Kubernetes-cluster. Status saat ini adalah
versi alfa . Sekarang kami sedang mempersiapkan dokumentasi untuk merilis beta, tetapi untuk saat ini
, contoh tersedia di repositori, berdasarkan di mana Anda dapat membuat addon Anda.
Di mana mendapatkan modul addon-operator sendiri? Penerbitan perpustakaan kami adalah tahap berikutnya bagi kami, kami berencana untuk melakukannya di musim panas.
Video dan slide
Video dari kinerja (~ 50 menit):
Penyajian laporan:
PS
Laporan lain di blog kami:
Anda mungkin juga tertarik dengan publikasi berikut: