Lima kesalahan saat menerapkan aplikasi Kubernetes pertama Anda

Gagal oleh Aris-Dreamer



Banyak orang berpikir bahwa cukup dengan mem-port aplikasi ke Kubernetes (baik menggunakan Helm atau secara manual) dan akan ada kebahagiaan. Tapi tidak sesederhana itu.



Tim Solusi Cloud Mail.ru telahmenerjemahkan artikel oleh insinyur DevOps, Julian Guindi. Dia berbicara tentang kesulitan yang dihadapi perusahaannya selama proses migrasi sehingga Anda tidak menginjak penggaruk yang sama.



Langkah satu: siapkan permintaan dan batas pod



Mari kita mulai dengan menyiapkan lingkungan bersih tempat pod kita akan berjalan. Kubernetes melakukan pekerjaan yang sangat baik dalam menjadwalkan pod dan menangani kegagalan. Namun ternyata perencana terkadang tidak dapat menempatkan pod jika sulit memperkirakan berapa banyak sumber daya yang dibutuhkannya agar berhasil bekerja. Di sinilah permintaan dan batasan sumber daya masuk. Ada banyak perdebatan tentang pendekatan terbaik untuk menetapkan permintaan dan batasan. Kadang-kadang tampaknya itu lebih merupakan seni daripada sains. Inilah pendekatan kami.



Permintaan pod adalah nilai utama yang digunakan penjadwal untuk penempatan pod yang optimal.



Kubernetes: , . , PodFitsResources , .


Kami menggunakan permintaan aplikasi sehingga kami dapat menggunakannya untuk memperkirakan berapa banyak sumber daya yang sebenarnya dibutuhkan aplikasi agar dapat berfungsi dengan baik. Ini akan memungkinkan perencana untuk menempatkan node secara realistis. Awalnya, kami ingin menyiapkan permintaan dengan margin untuk memastikan bahwa ada cukup resource untuk setiap pod, tetapi kami melihat bahwa waktu penjadwalan meningkat secara signifikan, dan beberapa pod tidak pernah dijadwalkan sepenuhnya, seolah-olah tidak ada permintaan resource untuk pod tersebut.



Dalam kasus ini, penjadwal akan sering "menekan" pod dan tidak dapat menjadwalkan ulang pod karena bidang kontrol tidak tahu berapa banyak resource yang dibutuhkan aplikasi, yang merupakan komponen kunci dari algoritme penjadwalan.



Batas PodMerupakan batasan yang lebih jelas untuk pod. Ini mewakili jumlah maksimum resource yang akan dialokasikan cluster ke container.



Sekali lagi, dari dokumentasi resmi : jika batas memori 4 GiB ditetapkan untuk sebuah container, maka kubelet (dan runtime container) akan memaksanya. Waktu proses mencegah penampung menggunakan lebih dari batas sumber daya yang ditentukan. Misalnya, ketika sebuah proses dalam wadah mencoba menggunakan lebih dari jumlah memori yang diizinkan, kernel keluar dari proses dengan kesalahan "kehabisan memori" (OOM).


Sebuah penampung selalu dapat menggunakan lebih banyak sumber daya daripada yang ditentukan dalam permintaan sumber daya, tetapi tidak pernah dapat menggunakan lebih dari yang ditentukan dalam suatu batas. Nilai ini sulit diatur dengan benar, tetapi ini sangat penting.



Idealnya, kami ingin persyaratan resource pod berubah sepanjang siklus hidup proses tanpa mengganggu proses lain dalam sistem - ini adalah tujuan dari menetapkan batas.



Sayangnya, saya tidak dapat memberikan instruksi khusus tentang nilai apa yang harus ditetapkan, tetapi kami sendiri mematuhi aturan berikut:



  1. Dengan menggunakan alat pengujian beban, kami menyimulasikan lalu lintas dasar dan memantau penggunaan sumber daya pod (memori dan prosesor).
  2. ( 5 ) . , , Go.


Perhatikan bahwa batasan sumber daya yang lebih tinggi membuat penjadwalan lebih sulit karena pod memerlukan node target dengan sumber daya yang cukup tersedia.



Bayangkan situasi di mana Anda memiliki server web ringan dengan batasan sumber daya yang sangat tinggi seperti memori 4 GB. Proses ini mungkin perlu diskalakan secara horizontal dan setiap modul baru harus dijadwalkan pada node dengan setidaknya 4 GB memori yang tersedia. Jika tidak ada node seperti itu, cluster harus memperkenalkan node baru untuk memproses pod ini, yang mungkin memerlukan waktu. Penting untuk menjaga perbedaan antara permintaan sumber daya dan batas sekecil mungkin untuk memastikan penskalaan yang cepat dan lancar.



Langkah kedua: siapkan tes Liveness dan Readiness



Ini adalah topik halus lainnya yang sering dibahas di komunitas Kubernetes. Penting untuk memiliki pemahaman yang baik tentang tes Liveness dan Readiness karena menyediakan mekanisme untuk perangkat lunak agar dapat berjalan dengan lancar dan meminimalkan waktu henti. Namun, mereka dapat sangat mempengaruhi kinerja aplikasi Anda jika tidak dikonfigurasi dengan benar. Di bawah ini adalah ringkasan dari kedua sampel tersebut.



Kehidupan menunjukkan jika wadah sedang berjalan. Jika gagal, kubelet akan mematikan kontainer, dan kebijakan restart diaktifkan untuknya. Jika container tidak dilengkapi dengan probe Liveness, status default-nya akan berhasil - seperti yang dinyatakan dalam dokumentasi Kubernetes .



Probe kehidupan seharusnya murah, yaitu tidak menghabiskan banyak sumber daya, karena sering berjalan dan harus memberi tahu Kubernetes bahwa aplikasi sedang berjalan.



Menyetelnya agar berjalan setiap detik akan menambahkan 1 permintaan per detik, jadi ketahuilah bahwa sumber daya tambahan akan dibutuhkan untuk menangani lalu lintas ini.



Di perusahaan kami, tes Liveness memvalidasi komponen utama aplikasi, meskipun data (misalnya, dari database atau cache jarak jauh) tidak sepenuhnya tersedia.



Kami telah mengonfigurasi titik akhir "kesehatan" dalam aplikasi yang hanya mengembalikan kode respons 200. Ini merupakan indikasi bahwa proses sedang aktif dan berjalan serta mampu menangani permintaan (tetapi belum lalu lintas).



Tes kesiapanmenunjukkan apakah penampung siap untuk melayani permintaan. Jika pemeriksaan kesiapan gagal, pengontrol titik akhir akan menghapus alamat IP pod dari titik akhir semua layanan yang cocok dengan pod. Ini juga dinyatakan dalam dokumentasi Kubernetes.



Probe kesiapan mengkonsumsi lebih banyak sumber daya, karena harus pergi ke backend sedemikian rupa untuk menunjukkan bahwa aplikasi siap menerima permintaan.



Ada banyak kontroversi di komunitas mengenai apakah akan langsung membuka database. Mengingat overhead (pemeriksaan sering dilakukan, tetapi dapat disesuaikan), kami memutuskan bahwa untuk beberapa aplikasi, ketersediaan untuk melayani lalu lintas dihitung hanya setelah memeriksa bahwa catatan dikembalikan dari database. Pemeriksaan ketersediaan yang dirancang dengan baik memastikan ketersediaan yang lebih tinggi dan waktu henti yang dihilangkan selama penerapan.



Jika Anda memutuskan untuk meminta database untuk memeriksa apakah aplikasi Anda sudah siap, pastikan itu semurah mungkin. Mari kita tanyakan seperti ini:



SELECT small_item FROM table LIMIT 1


Berikut adalah contoh bagaimana kami mengonfigurasi dua nilai ini di Kubernetes:



livenessProbe: 
 httpGet:   
   path: /api/liveness    
   port: http 
readinessProbe:  
 httpGet:    
   path: /api/readiness    
   port: http  periodSeconds: 2


Beberapa opsi konfigurasi tambahan dapat ditambahkan:



  • initialDelaySeconds - berapa detik yang akan berlalu antara dimulainya wadah dan dimulainya sampel.
  • periodSeconds — .
  • timeoutSeconds — , . -.
  • failureThreshold — , .
  • successThreshold — , ( , ).


:



Kubernetes memiliki topografi jaringan "datar", secara default semua pod berinteraksi langsung satu sama lain. Dalam beberapa kasus, ini tidak diinginkan.



Masalah keamanan potensial adalah penyerang dapat menggunakan satu aplikasi yang rentan untuk mengirim lalu lintas ke semua pod di jaringan. Seperti di banyak bidang keamanan, prinsip hak istimewa terendah berlaku. Idealnya, kebijakan jaringan harus secara eksplisit menyatakan koneksi mana antara pod yang diizinkan dan mana yang tidak.



Misalnya, di bawah ini adalah kebijakan sederhana yang menolak semua lalu lintas masuk untuk namespace tertentu:



---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:  
 name: default-deny-ingress
spec:  
 podSelector: {}  
 policyTypes:  
   - Ingress


Visualisasi konfigurasi ini:





(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)

Selengkapnya di sini .



Langkah empat: perilaku kustom dengan kait dan wadah init



Salah satu tujuan utama kami adalah menyediakan penerapan ke Kubernetes tanpa waktu henti bagi pengembang. Ini sulit karena ada banyak opsi untuk mematikan aplikasi dan membebaskan sumber daya yang digunakan.



Kesulitan khusus muncul dengan Nginx . Kami melihat bahwa ketika pod ini diterapkan secara berurutan, koneksi aktif dihentikan sebelum berhasil diselesaikan.



Setelah penelitian ekstensif di Internet, ternyata Kubernetes tidak menunggu koneksi Nginx habis sendiri sebelum mematikan pod. Dengan bantuan pengait pra-stop, kami menerapkan fungsi berikut dan sepenuhnya menghilangkan waktu henti:



lifecycle: 
 preStop:
   exec:
     command: ["/usr/local/bin/nginx-killer.sh"]


Dan di sini nginx-killer.sh:



#!/bin/bash
sleep 3
PID=$(cat /run/nginx.pid)
nginx -s quit
while [ -d /proc/$PID ]; do
   echo "Waiting while shutting down nginx..."
   sleep 10
done


Paradigma lain yang sangat berguna adalah penggunaan container init untuk menangani peluncuran aplikasi tertentu. Ini sangat berguna jika Anda memiliki proses migrasi database intensif sumber daya yang perlu dimulai sebelum menjalankan aplikasi. Anda juga dapat menentukan batas sumber daya yang lebih tinggi untuk proses ini tanpa menyetel batas tersebut untuk aplikasi utama.



Skema umum lainnya adalah mengakses rahasia dalam penampung init, yang memberikan kredensial ini ke modul utama, yang mencegah akses tidak sah ke rahasia dari modul aplikasi utama itu sendiri.



, : init- , . , .


:



Terakhir, mari kita bicara tentang teknik yang lebih canggih.



Kubernetes adalah platform yang sangat fleksibel yang memungkinkan Anda menjalankan beban kerja sesuai keinginan Anda. Kami memiliki sejumlah aplikasi intensif sumber daya yang sangat efisien. Melalui pengujian beban yang ekstensif, kami menemukan bahwa salah satu aplikasi kesulitan menangani beban lalu lintas yang diharapkan saat default Kubernetes berlaku.



Namun, Kubernetes memungkinkan Anda menjalankan container dengan hak istimewa yang mengubah parameter kernel hanya untuk pod tertentu. Inilah yang kami gunakan untuk mengubah jumlah maksimum koneksi terbuka:



initContainers:
  - name: sysctl
     image: alpine:3.10
     securityContext:
         privileged: true
      command: ['sh', '-c', "sysctl -w net.core.somaxconn=32768"]


Ini adalah teknik yang lebih maju dan seringkali tidak diperlukan. Tetapi jika aplikasi Anda kesulitan untuk mengatasi beban yang berat, Anda dapat mencoba menyesuaikan beberapa parameter ini. Detail lebih lanjut tentang proses ini dan pengaturan berbagai nilai - seperti biasa di dokumentasi resmi .



Akhirnya



Meskipun Kubernetes mungkin tampak seperti solusi out-of-the-box, ada beberapa langkah penting yang harus diambil agar aplikasi Anda tetap berjalan dengan lancar.



Sepanjang migrasi Anda ke Kubernetes, penting untuk mengikuti "siklus pengujian beban": jalankan aplikasi, uji beban, amati metrik dan perilaku penskalaan, sesuaikan konfigurasi berdasarkan data tersebut, lalu ulangi siklusnya lagi.



Perkirakan secara realistis lalu lintas yang diharapkan dan coba melampaui itu untuk melihat komponen mana yang rusak lebih dulu. Dengan pendekatan berulang ini, hanya sedikit dari rekomendasi ini yang mungkin cukup untuk mencapai kesuksesan. Atau, penyesuaian yang lebih mendalam mungkin diperlukan.



Selalu tanyakan pada diri Anda pertanyaan-pertanyaan ini:



  1. ?
  2. ? ? ?
  3. ? , ?
  4. ? ? ?
  5. ? - , ?


Kubernetes menyediakan platform luar biasa yang memungkinkan praktik terbaik untuk menerapkan ribuan layanan di seluruh cluster. Namun, semua aplikasi berbeda. Terkadang implementasi membutuhkan lebih banyak pekerjaan.



Untungnya, Kubernetes menyediakan kustomisasi yang diperlukan untuk memenuhi semua tujuan teknis. Dengan menggunakan kombinasi permintaan dan batas sumber daya, probe Liveness dan Readiness, wadah init, kebijakan jaringan, dan penyesuaian kernel khusus, Anda dapat mencapai kinerja tinggi bersama dengan toleransi kesalahan dan skalabilitas cepat.



Apa lagi yang harus dibaca:



  1. Praktik dan pedoman terbaik untuk menjalankan container dan Kubernetes di lingkungan produksi .
  2. 90+ Kubernetes: , , , .
  3. Kubernetes .



All Articles