3 cerita kecelakaan Kubernetes dalam produksi: anti-afinitas, shutdown anggun, webhook


Catatan perev. : Kami menyajikan pilihan mini post-mortem tentang masalah fatal yang dihadapi oleh insinyur dari berbagai perusahaan saat mengoperasikan infrastruktur berdasarkan Kubernetes. Setiap catatan berbicara tentang masalah itu sendiri, penyebab dan konsekuensinya, dan, tentu saja, tentang solusi yang membantu menghindari situasi serupa di masa depan.

Seperti yang Anda ketahui, belajar dari pengalaman orang lain lebih murah, dan karenanya - biarkan cerita ini membantu Anda bersiap untuk kemungkinan kejutan. Ngomong-ngomong, sejumlah besar tautan yang diperbarui secara berkala ke "cerita kegagalan" dipublikasikan di situs ini (menurut data dari repositori Git ini ).

1 Bagaimana panik kernel menabrak sebuah situs


Asli: Cahaya Bulan .

Antara 18 dan 22 Januari, situs web Moonlight dan API mengalami kegagalan fungsi intermiten. Semuanya dimulai dengan kesalahan API acak dan diakhiri dengan penghentian total. Masalah diselesaikan dan aplikasi kembali normal.

Informasi umum


Moonlight menggunakan perangkat lunak yang dikenal sebagai Kubernetes. Kubernetes menjalankan aplikasi pada grup server. Server-server ini disebut node. Salinan aplikasi yang berjalan pada node disebut pod. Kubernetes memiliki penjadwal yang secara dinamis menentukan pod mana yang node harus bekerja.

Garis waktu


Kesalahan pertama pada hari Jumat terkait dengan masalah koneksi ke database Redis. Moonlight API menggunakan Redis untuk memverifikasi sesi untuk setiap permintaan yang diautentikasi. Alat pemantauan kami Kubernetes telah memberi tahu bahwa beberapa node dan pod tidak merespons. Pada saat yang sama, Google Cloud melaporkan tidak berfungsinya layanan jaringan , dan kami memutuskan bahwa mereka adalah penyebab masalah kami.

Ketika lalu lintas pada akhir pekan menurun, kesalahan tampaknya diselesaikan secara massal. Namun, pada Selasa pagi, situs Moonlight jatuh, dan lalu lintas eksternal tidak mencapai cluster sama sekali. Kami menemukan orang lain di Twitter dengan gejala yang sama dan memutuskan bahwa hosting Google mengalami kegagalan jaringan. Kami menghubungi dukungan Google Cloud, yang segera merujuk masalah ini ke tim dukungan teknis.

Tim dukungan teknis Google mengungkapkan beberapa pola dalam perilaku node di kluster Kubernet kami. Pemanfaatan CPU dari masing-masing node mencapai 100%, setelah itu kepanikan kernel terjadi di mesin virtual dan macet.

Alasan


Siklus yang menyebabkan kegagalan adalah sebagai berikut:

  • Penjadwal Kubernetes meng-host beberapa pod dengan konsumsi CPU tinggi pada node yang sama.
  • Pod memakan semua sumber daya CPU pada node.
  • Selanjutnya muncul panik kernel, yang menyebabkan periode downtime di mana node tidak menanggapi scheduler.
  • Penjadwal memindahkan semua pod jatuh ke node baru, dan proses itu diulangi, memperburuk situasi umum.

Awalnya, kesalahan terjadi di pod Redis, tetapi pada akhirnya semua pod yang bekerja dengan traffic turun, yang menyebabkan shutdown total. Keterlambatan eksponensial selama perencanaan ulang menyebabkan periode waktu henti yang lebih lama.

Solusi


Kami dapat memulihkan situs dengan menambahkan aturan anti-afinitas ke semua Penyebaran utama. Mereka secara otomatis mendistribusikan pods melalui node, meningkatkan toleransi kesalahan dan kinerja.

Kubernetes sendiri dirancang sebagai sistem host yang toleran terhadap kesalahan. Moonlight menggunakan tiga node pada server yang berbeda untuk stabilitas, dan kami menjalankan tiga salinan dari setiap aplikasi yang melayani lalu lintas. Idenya adalah memiliki satu salinan pada setiap simpul. Dalam hal ini, bahkan kegagalan dua node tidak akan menyebabkan downtime. Namun, Kubernetes kadang-kadang menempatkan ketiga pod dengan situs pada node yang sama, sehingga menciptakan hambatan dalam sistem. Pada saat yang sama, aplikasi lain yang menuntut daya prosesor (yaitu, rendering sisi-server) berada pada node yang sama, dan bukan pada yang terpisah.

Cluster Kubernetes yang dikonfigurasikan dengan benar dan berfungsi dengan benar diperlukan untuk mengatasi beban CPU yang lama dan menempatkan pod sedemikian rupa untuk memaksimalkan penggunaan sumber daya yang tersedia. Kami terus bekerja dengan dukungan Google Cloud untuk mengidentifikasi dan mengatasi penyebab utama panik kernel pada server.

Kesimpulan


Aturan anti-afinitas memungkinkan Anda membuat aplikasi yang berfungsi dengan lalu lintas eksternal lebih toleran terhadap kesalahan. Jika Anda memiliki layanan serupa di Kubernetes, pertimbangkan untuk menambahkannya.

Kami terus bekerja dengan orang-orang dari Google untuk menemukan dan menghilangkan penyebab kegagalan pada kernel OS pada node.

2 Rahasia "kotor" dari titik akhir Kubernetes dan Ingress


Asli: Phil Pearl of Ravelin .

Keanggunan berlebihan


Kami di Ravelin bermigrasi ke Kubernetes (di GKE). Prosesnya sangat sukses. Anggaran gangguan pod kami penuh seperti biasa, statefuls benar-benar megah (kata-kata yang sulit diterjemahkan: "set statefuls kami sangat megah" - kira-kira. Terjemahan) , Dan penggantian node yang berjalan seperti jarum jam.

Bagian terakhir dari teka-teki adalah memindahkan lapisan API dari mesin virtual lama ke kluster Kubernetes. Untuk melakukan ini, kita perlu mengonfigurasi Ingress agar API dapat diakses dari dunia luar.

Awalnya, tugas itu tampak sederhana. Kami hanya mendefinisikan pengontrol Ingress, mengubah Terraform untuk mendapatkan sejumlah alamat IP, dan Google menangani hampir semua hal lainnya. Dan semua ini akan bekerja seperti sulap. Kelas!

Namun, seiring waktu, mereka mulai memperhatikan bahwa tes integrasi secara berkala menerima kesalahan 502. Dari sini, perjalanan kami dimulai. Namun, saya akan menghemat waktu Anda dan langsung menuju kesimpulan.

Shutdown yang anggun


Semua orang berbicara tentang shutdown anggun ("anggun", shutdown bertahap). Tapi Anda benar-benar tidak harus bergantung padanya di Kubernetes. Atau setidaknya itu bukan shutdown anggun yang Anda serap dengan susu ibu Anda . Di dunia Kubernetes, tingkat "keanggunan" ini tidak perlu dan mengancam dengan masalah serius.

Dunia yang sempurna


Berikut ini cara tampilan mayoritas pod dihapus dari layanan atau penyeimbang beban di Kubernetes:

  1. Pengontrol replikasi memutuskan untuk menghapus pod.
  2. Pod titik akhir dihapus dari penyeimbang layanan atau beban. Lalu lintas baru ke pod tidak lagi tiba.
  3. Pengait pre-stop disebut, atau pod menerima sinyal SIGTERM.
  4. Pod "anggun" terputus. Itu berhenti menerima koneksi masuk.
  5. Putus "anggun" selesai, dan pod hancur setelah semua koneksi yang ada dihentikan atau dihentikan.

Sayangnya, kenyataannya sangat berbeda.

Dunia nyata


Sebagian besar dokumentasi mengisyaratkan bahwa semuanya terjadi sedikit berbeda, tetapi mereka tidak secara eksplisit menulis tentang ini di mana pun. Masalah utama adalah bahwa langkah 3 tidak mengikuti langkah 2. Mereka terjadi secara bersamaan. Dalam layanan biasa, penghapusan titik akhir sangat cepat sehingga kemungkinan menghadapi masalah sangat rendah. Namun, dengan Ingresss, semuanya berbeda: mereka biasanya merespons lebih lambat, sehingga masalahnya menjadi jelas. Pod bisa mendapatkan SIGTERM jauh sebelum perubahan pada titik akhir masuk ke Ingress.

Akibatnya, shutdown yang anggun sama sekali tidak seperti yang diminta pod. Dia akan menerima koneksi baru dan harus terus memprosesnya, jika tidak klien akan mulai menerima kesalahan ke-500 dan seluruh cerita indah tentang penyebaran yang tidak rumit dan penskalaan akan mulai berantakan.

Inilah yang sebenarnya terjadi:

  1. Pengontrol replikasi memutuskan untuk menghapus pod.
  2. Pod titik akhir dihapus dari penyeimbang layanan atau beban. Dalam kasus Ingress, ini bisa memakan waktu, dan lalu lintas baru akan terus mengalir ke pod.
  3. Pengait pre-stop disebut, atau pod menerima sinyal SIGTERM.
  4. Untuk sebagian besar, pod harus mengabaikan ini, terus bekerja dan memelihara koneksi baru. Jika memungkinkan, ia harus memberi petunjuk kepada pelanggan bahwa alangkah baiknya untuk pindah ke tempat lain. Misalnya, dalam hal HTTP, mungkin mengirim Connection: close di header respons.
  5. Pod keluar hanya ketika periode tunggu "elegan" berakhir dan terbunuh oleh SIGKILL.
  6. Pastikan periode ini lebih lama dari waktu yang diperlukan untuk memprogram ulang penyeimbang beban.

Jika ini adalah kode pihak ketiga dan Anda tidak dapat mengubah perilakunya, maka hal terbaik yang dapat Anda lakukan adalah menambahkan kait pre-stop yang hanya akan tidur selama periode "elegan", sehingga pod akan terus bekerja seolah-olah tidak ada terjadi

Nomor 3 Bagaimana webhook sederhana menyebabkan kegagalan cluster


Asli: Jetstack .

Jetstack menawarkan platform multi-tenant kepada pelanggannya di Kubernetes. Terkadang ada persyaratan khusus yang tidak dapat kami penuhi dengan konfigurasi standar Kubernetes. Untuk mengimplementasikannya, baru-baru ini kami mulai menggunakan Open Policy Agent (kami menulis tentang proyek secara lebih rinci dalam ulasan ini - kira-kira Terjemahkan.)

Artikel ini menjelaskan kegagalan yang disebabkan oleh integrasi ini yang tidak dikonfigurasi dengan benar.

Insiden


Kami terlibat dalam memperbarui wizard untuk klaster dev, di mana berbagai tim menguji aplikasi mereka selama hari kerja. Itu adalah cluster regional di zona eropa-barat1 di Google Kubernetes Engine (GKE).

Perintah diperingatkan bahwa pembaruan sedang berlangsung, dengan tidak ada downtime yang diharapkan. Sebelumnya pada hari itu, kami sudah melakukan pembaruan yang mirip dengan lingkungan pra-produksi lain.

Kami memulai peningkatan menggunakan pipa GKE Terraform kami. Pembaruan panduan tidak selesai sampai batas waktu Terraform berakhir, yang kami atur selama 20 menit. Ini adalah panggilan bangun pertama yang terjadi kesalahan, meskipun di konsol GKE cluster masih terdaftar sebagai "peningkatan".

Mulai ulang pipa menyebabkan kesalahan berikut

 google_container_cluster.cluster: Error waiting for updating GKE master version: All cluster resources were brought up, but the cluster API is reporting that: component "kube-apiserver" from endpoint "gke-..." is unhealthy 

Kali ini, koneksi dengan server API mulai terputus secara berkala dan tim tidak dapat menggunakan aplikasi mereka.

Sementara kami mencoba memahami apa yang sedang terjadi, semua node mulai dihancurkan dan diciptakan kembali dalam siklus yang tak berujung. Hal ini menyebabkan penolakan layanan tanpa pandang bulu untuk semua pelanggan kami.

Kami menetapkan akar penyebab kegagalan


Dengan dukungan Google, kami dapat menentukan urutan peristiwa yang menyebabkan kegagalan:

  1. GKE menyelesaikan upgrade pada satu instance wizard dan mulai menerima semua lalu lintas ke server API saat wizard berikutnya diperbarui.
  2. Selama pemutakhiran instance kedua wizard, server API tidak dapat menjalankan PostStartHook untuk mendaftarkan CA.
  3. Selama pelaksanaan kait ini, server API mencoba memperbarui ConfigMap yang disebut extension-apiserver-authentication di kube-system . Itu tidak mungkin untuk melakukan ini karena backend untuk webhook memeriksa Agen Kebijakan Terbuka (OPA) yang kami konfigurasi tidak merespons.
  4. Agar wisaya lulus pemeriksaan kesehatan, operasi ini harus selesai dengan sukses. Karena ini tidak terjadi, master kedua memasuki siklus darurat dan menghentikan pembaruan.

Hasilnya adalah crash API berkala, karena kubelet tidak dapat melaporkan kesehatan node. Pada gilirannya, ini mengarah pada fakta bahwa mekanisme untuk pemulihan otomatis node GKE (perbaikan otomatis node) mulai me-restart node. Fitur ini dijelaskan secara rinci dalam dokumentasi :

Status yang tidak sehat dapat berarti: Dalam waktu tertentu (sekitar 10 menit), simpul tidak memberikan status apa pun sama sekali.

Solusi


Ketika kami mengetahui bahwa sumber daya ValidatingAdmissionWebhook menyebabkan akses intermiten ke server API, kami menghapusnya dan mengembalikan cluster agar berfungsi.

Sejak itu, ValidatingAdmissionWebhook untuk OPA telah dikonfigurasikan untuk memantau hanya ruang nama di mana kebijakan tersebut berlaku dan yang dapat diakses oleh tim pengembangan. Kami juga membatasi webhook untuk Ingress dan Service , satu-satunya yang sesuai dengan kebijakan kami.

Sejak kami pertama kali menyebarkan OPA, dokumentasi telah diperbarui untuk mencerminkan perubahan ini.

Kami juga menambahkan tes liveness untuk memastikan bahwa OPA restart jika itu tidak tersedia (dan membuat amandemen yang sesuai untuk dokumentasi).

Kami juga mempertimbangkan untuk menonaktifkan mekanisme pemulihan otomatis untuk node GKE, tetapi masih memutuskan untuk meninggalkan ide ini.

Ringkasan


Jika kami mengaktifkan peringatan waktu respons server API, pada awalnya kami akan dapat melihat peningkatan global untuk semua permintaan CREATE dan UPDATE setelah menggunakan webhook untuk OPA.

Ini menggarisbawahi pentingnya menyiapkan tes untuk semua beban kerja. Melihat ke belakang, kita dapat mengatakan bahwa penyebaran OPA sangat sederhana sehingga kita bahkan tidak terlibat dalam grafik Helm (meskipun seharusnya). Grafik membuat sejumlah penyesuaian di luar pengaturan dasar yang dijelaskan dalam manual, termasuk pengaturan livenessProbe untuk wadah dengan pengontrol masuk.

Kami bukan yang pertama kali menghadapi masalah ini: masalah hulu tetap terbuka. Fungsionalitas dalam hal ini jelas dapat ditingkatkan (dan kami akan menindaklanjutinya).

PS dari penerjemah


Baca juga di blog kami:

Source: https://habr.com/ru/post/id475026/


All Articles