10 Kesalahan Umum Saat Menggunakan Kubernetes

Catatan. terjemahan: Penulis artikel ini adalah insinyur dari sebuah perusahaan kecil di Ceko, pipetail. Mereka berhasil menyusun daftar masalah yang [terkadang dangkal, namun tetap] sangat mendesak dan kesalahpahaman terkait pengoperasian cluster Kubernetes.

10 Kesalahan Umum Saat Menggunakan Kubernetes

Selama bertahun-tahun menggunakan Kubernetes, kami telah bekerja dengan sejumlah besar cluster (baik yang terkelola maupun tidak terkelola - di GCP, AWS, dan Azure). Seiring waktu, kami mulai memperhatikan bahwa beberapa kesalahan terus terulang. Namun, tidak ada salahnya untuk melakukan hal ini: kami telah melakukan sebagian besarnya sendiri!

Artikel tersebut berisi kesalahan paling umum dan juga menyebutkan cara memperbaikinya.

1. Sumber daya: permintaan dan batasan

Item ini tentu saja layak mendapat perhatian paling dekat dan tempat pertama dalam daftar.

Permintaan CPU biasanya baik tidak ditentukan sama sekali atau memiliki nilai yang sangat rendah (untuk menempatkan sebanyak mungkin pod di setiap node). Dengan demikian, node menjadi kelebihan beban. Selama masa beban tinggi, kekuatan pemrosesan node dimanfaatkan sepenuhnya dan beban kerja tertentu hanya menerima apa yang "diminta" olehnya. Pelambatan CPU. Hal ini menyebabkan peningkatan latensi aplikasi, waktu tunggu, dan konsekuensi tidak menyenangkan lainnya. (Baca lebih lanjut tentang ini di terjemahan terbaru kami yang lain: β€œBatasan CPU dan pembatasan agresif di Kubernetes" - kira-kira. terjemahan.)

Usaha terbaik (sangat tidak direkomendasikan):

resources: {}

Permintaan CPU yang sangat rendah (sangat tidak direkomendasikan):

   resources:
      Requests:
        cpu: "1m"

Di sisi lain, adanya batas CPU dapat menyebabkan lompatan siklus clock yang tidak wajar oleh pod, bahkan jika prosesor node tidak terisi penuh. Sekali lagi, hal ini dapat menyebabkan peningkatan penundaan. Kontroversi terus berlanjut seputar parameter Kuota CPU CFS di kernel Linux dan pelambatan CPU tergantung pada batas yang ditetapkan, serta menonaktifkan kuota CFS... Sayangnya, batasan CPU dapat menyebabkan lebih banyak masalah daripada yang bisa diselesaikan. Informasi lebih lanjut mengenai hal ini dapat ditemukan pada tautan di bawah ini.

Seleksi yang berlebihan (komitmen berlebihan) masalah memori dapat menyebabkan masalah yang lebih besar. Mencapai batas CPU berarti melewatkan siklus jam, sementara mencapai batas memori berarti mematikan pod. Pernahkah Anda mengamati OOMkill? Ya, itulah tepatnya yang sedang kita bicarakan.

Apakah Anda ingin meminimalkan kemungkinan hal ini terjadi? Jangan mengalokasikan memori secara berlebihan dan gunakan Guaranteed QoS (Quality of Service) dengan mengatur permintaan memori hingga batasnya (seperti pada contoh di bawah). Baca lebih lanjut tentang ini di Presentasi Henning Jacobs (Insinyur Utama di Zalando).

meledak (peluang lebih tinggi untuk mendapatkan OOMkilled):

   resources:
      requests:
        memory: "128Mi"
        cpu: "500m"
      limits:
        memory: "256Mi"
        cpu: 2

Terjamin:

   resources:
      requests:
        memory: "128Mi"
        cpu: 2
      limits:
        memory: "128Mi"
        cpu: 2

Apa yang berpotensi membantu saat menyiapkan sumber daya?

Dengan server metrik Anda dapat melihat konsumsi sumber daya CPU dan penggunaan memori saat ini berdasarkan pod (dan container di dalamnya). Kemungkinan besar Anda sudah menggunakannya. Jalankan saja perintah berikut:

kubectl top pods
kubectl top pods --containers
kubectl top nodes

Namun, mereka hanya menunjukkan penggunaan saat ini. Ini mungkin memberi Anda gambaran kasar tentang urutan besarnya, tetapi pada akhirnya Anda akan membutuhkannya riwayat perubahan metrik dari waktu ke waktu (untuk menjawab pertanyaan seperti: β€œBerapa beban puncak CPU?”, β€œBerapa bebannya kemarin pagi?”, dll.). Untuk ini, Anda dapat menggunakan Prometheus, DataDog dan alat lainnya. Mereka hanya mendapatkan metrik dari server metrik dan menyimpannya, dan pengguna dapat menanyakannya dan memplotnya sesuai dengan itu.

VertikalPodAutoscaler memungkinkan mengotomatisasikan proses ini. Ini melacak riwayat penggunaan CPU dan memori dan mengatur permintaan dan batasan baru berdasarkan informasi ini.

Menggunakan daya komputasi secara efisien bukanlah tugas yang mudah. Ini seperti bermain Tetris sepanjang waktu. Jika Anda membayar terlalu mahal untuk daya komputasi dengan konsumsi rata-rata rendah (katakanlah ~10%), kami sarankan untuk melihat produk berdasarkan AWS Fargate atau Virtual Kubelet. Mereka dibuat dengan model penagihan tanpa server/bayar per penggunaan, yang mungkin menjadi lebih murah dalam kondisi seperti itu.

2. Pemeriksaan keaktifan dan kesiapan

Secara default, pemeriksaan keaktifan dan kesiapan tidak diaktifkan di Kubernetes. Dan terkadang mereka lupa menyalakannya...

Namun bagaimana lagi Anda dapat memulai ulang layanan jika terjadi kesalahan fatal? Dan bagaimana penyeimbang beban mengetahui bahwa sebuah pod siap menerima lalu lintas? Atau dapat menangani lebih banyak lalu lintas?

Tes-tes ini sering membingungkan satu sama lain:

  • Kehidupan β€” pemeriksaan β€œsurvivability”, yang akan memulai ulang pod jika gagal;
  • Kesiapan β€” pemeriksaan kesiapan, jika gagal, ia akan memutus koneksi pod dari layanan Kubernetes (ini dapat diperiksa menggunakan kubectl get endpoints) dan lalu lintas tidak sampai ke sana sampai pemeriksaan berikutnya berhasil diselesaikan.

Kedua pemeriksaan ini DILAKUKAN SELAMA SELURUH SIKLUS HIDUP POD. Ini sangat penting.

Kesalahpahaman yang umum adalah bahwa pemeriksaan kesiapan hanya dijalankan saat startup sehingga penyeimbang dapat mengetahui bahwa pod sudah siap (Ready) dan dapat mulai memproses lalu lintas. Namun, ini hanyalah salah satu pilihan untuk penggunaannya.

Kemungkinan lainnya adalah mengetahui bahwa lalu lintas di pod tersebut berlebihan dan membebani itu (atau pod melakukan penghitungan intensif sumber daya). Dalam hal ini, pemeriksaan kesiapan membantu kurangi beban pada pod dan β€œdinginkan”.. Keberhasilan menyelesaikan pemeriksaan kesiapan di masa depan memungkinkan menambah beban pada pod lagi. Dalam hal ini (jika uji kesiapan gagal), kegagalan uji keaktifan akan sangat kontraproduktif. Mengapa memulai ulang pod yang sehat dan bekerja keras?

Oleh karena itu, dalam beberapa kasus, tidak ada pemeriksaan sama sekali lebih baik daripada mengaktifkannya dengan parameter yang tidak dikonfigurasi dengan benar. Seperti yang dinyatakan di atas, jika pemeriksaan keaktifan salinan pemeriksaan kesiapan, maka kamu berada dalam masalah besar. Opsi yang memungkinkan adalah mengonfigurasi tes kesiapan sajaDan kehidupan yang berbahaya tinggalkan.

Kedua jenis pemeriksaan tersebut tidak boleh gagal ketika dependensi umum gagal, jika tidak, hal ini akan menyebabkan kegagalan berjenjang (seperti longsoran salju) pada semua pod. Dengan kata lain, jangan menyakiti dirimu sendiri.

3. LoadBalancer untuk setiap layanan HTTP

Kemungkinan besar, Anda memiliki layanan HTTP di cluster Anda yang ingin Anda teruskan ke dunia luar.

Jika Anda membuka layanan sebagai type: LoadBalancer, pengontrolnya (tergantung pada penyedia layanan) akan menyediakan dan menegosiasikan LoadBalancer eksternal (tidak harus berjalan di L7, melainkan bahkan di L4), dan ini dapat memengaruhi biaya (alamat IPv4 statis eksternal, daya komputasi, penagihan per detik ) karena kebutuhan untuk menciptakan sejumlah besar sumber daya tersebut.

Dalam hal ini, jauh lebih logis untuk menggunakan satu penyeimbang beban eksternal, membuka layanan sebagai type: NodePort. Atau lebih baik lagi, perluas sesuatu seperti nginx-ingress-controller (Atau traefik.dll), siapa yang akan menjadi satu-satunya Pelabuhan Node titik akhir yang terkait dengan penyeimbang beban eksternal dan akan merutekan lalu lintas di cluster menggunakan masuk-Sumber daya Kubernetes.

Layanan intra-cluster (mikro) lainnya yang berinteraksi satu sama lain dapat β€œberkomunikasi” menggunakan layanan seperti ClusterIP dan mekanisme penemuan layanan bawaan melalui DNS. Hanya saja, jangan gunakan DNS/IP publiknya, karena hal ini dapat memengaruhi latensi dan meningkatkan biaya layanan cloud.

4. Melakukan penskalaan otomatis sebuah cluster tanpa memperhitungkan fitur-fiturnya

Saat menambahkan node ke dan menghapusnya dari cluster, Anda tidak boleh mengandalkan beberapa metrik dasar seperti penggunaan CPU pada node tersebut. Perencanaan pod harus mempertimbangkan banyak hal pembatasan, seperti afinitas pod/node, noda dan toleransi, permintaan sumber daya, QoS, dll. Menggunakan penskala otomatis eksternal yang tidak mempertimbangkan nuansa ini dapat menimbulkan masalah.

Bayangkan sebuah pod tertentu harus dijadwalkan, tetapi semua daya CPU yang tersedia diminta/dibongkar dan pod tersebut terjebak dalam suatu keadaan Pending. Penskala otomatis eksternal melihat rata-rata beban CPU saat ini (bukan yang diminta) dan tidak memulai perluasan (perluasan skala) - tidak menambahkan node lain. Akibatnya, pod ini tidak akan dijadwalkan.

Dalam hal ini, penskalaan terbalik (peningkatan skala) β€” menghapus sebuah node dari sebuah cluster selalu lebih sulit untuk diterapkan. Bayangkan Anda memiliki pod stateful (dengan penyimpanan persisten yang terhubung). Volume yang persisten biasanya milik zona ketersediaan tertentu dan tidak direplikasi di wilayah tersebut. Jadi, jika autoscaler eksternal menghapus sebuah node dengan pod ini, penjadwal tidak akan dapat menjadwalkan pod ini pada node lain, karena hal ini hanya dapat dilakukan di zona ketersediaan tempat penyimpanan persisten berada. Pod akan terjebak dalam status Pending.

Sangat populer di komunitas Kubernetes penskala otomatis cluster. Ini berjalan pada sebuah cluster, mendukung API dari penyedia cloud besar, memperhitungkan semua batasan dan dapat melakukan penskalaan dalam kasus di atas. Hal ini juga dapat meningkatkan skala sambil mempertahankan semua batasan yang ditetapkan, sehingga menghemat uang (yang seharusnya akan dihabiskan untuk kapasitas yang tidak terpakai).

5. Mengabaikan kemampuan IAM/RBAC

Berhati-hatilah dalam menggunakan pengguna IAM dengan rahasia yang terus-menerus mesin dan aplikasi. Atur akses sementara menggunakan peran dan akun layanan (akun layanan).

Kita sering menemukan fakta bahwa kunci akses (dan rahasia) di-hardcode dalam konfigurasi aplikasi, serta mengabaikan perputaran rahasia meskipun memiliki akses ke Cloud IAM. Gunakan peran IAM dan akun layanan alih-alih pengguna jika diperlukan.

10 Kesalahan Umum Saat Menggunakan Kubernetes

Lupakan kube2iam dan langsung buka IAM role untuk akun layanan (seperti yang dijelaskan di catatan dengan nama yang sama Ε tΔ›pΓ‘n VranΓ½):

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role
  name: my-serviceaccount
  namespace: default

Satu anotasi. Tidak terlalu sulit, bukan?

Selain itu, jangan berikan hak istimewa pada akun layanan dan profil instans admin ΠΈ cluster-adminjika mereka tidak membutuhkannya. Hal ini sedikit lebih sulit untuk diterapkan, terutama pada RBAC K8, namun usaha ini layak untuk dilakukan.

6. Jangan mengandalkan anti-afinitas otomatis untuk pod

Bayangkan Anda memiliki tiga replika penerapan pada sebuah node. Nodenya jatuh, dan bersamaan dengan itu semua replikanya. Situasi yang tidak menyenangkan bukan? Namun mengapa semua replika berada di node yang sama? Bukankah Kubernetes seharusnya menyediakan ketersediaan tinggi (HA)?!

Sayangnya, penjadwal Kubernetes, atas inisiatifnya sendiri, tidak mematuhi aturan keberadaan terpisah (anti-afinitas) untuk pod. Mereka harus dinyatakan secara eksplisit:

// ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ для краткости
      labels:
        app: zk
// ΠΎΠΏΡƒΡ‰Π΅Π½ΠΎ для краткости
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"

Itu saja. Sekarang pod akan dijadwalkan pada node yang berbeda (kondisi ini hanya diperiksa selama penjadwalan, tetapi tidak selama pengoperasiannya - oleh karena itu requiredDuringSchedulingIgnoredDuringExecution).

Di sini kita bicarakan podAntiAffinity pada node yang berbeda: topologyKey: "kubernetes.io/hostname", - dan bukan tentang zona ketersediaan yang berbeda. Untuk menerapkan HA yang lengkap, Anda harus menggali lebih dalam topik ini.

7. Mengabaikan Anggaran PodDisruption

Bayangkan Anda memiliki beban produksi di cluster Kubernetes. Secara berkala, node dan cluster itu sendiri harus diperbarui (atau dinonaktifkan). PodDisruptionBudget (PDB) adalah sesuatu seperti perjanjian jaminan layanan antara administrator klaster dan pengguna.

PDB memungkinkan Anda menghindari gangguan layanan yang disebabkan oleh kurangnya node:

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: zookeeper

Dalam contoh ini, Anda, sebagai pengguna klaster, menyatakan kepada admin: β€œHai, saya memiliki layanan penjaga kebun binatang, dan apa pun yang Anda lakukan, saya ingin setidaknya 2 replika layanan ini selalu tersedia.”

Anda dapat membaca lebih lanjut tentang ini di sini.

8. Beberapa pengguna atau lingkungan dalam satu cluster umum

Namespace Kubernetes (ruang nama) tidak memberikan isolasi yang kuat.

Kesalahpahaman yang umum terjadi adalah jika Anda menerapkan beban non-prod ke dalam satu namespace dan beban prod ke namespace lain, maka beban tersebut tidak akan saling mempengaruhi dengan cara apa pun... Namun, tingkat isolasi tertentu dapat dicapai dengan menggunakan permintaan/batasan sumber daya, menetapkan kuota, dan mengatur Kelas prioritas. Beberapa isolasi β€œfisik” pada bidang data disebabkan oleh afinitas, toleransi, noda (atau nodeselector), namun pemisahan tersebut cukup sulit melaksanakan.

Mereka yang perlu menggabungkan kedua jenis beban kerja dalam cluster yang sama harus menghadapi kompleksitas. Jika tidak ada kebutuhan seperti itu, dan Anda mampu untuk memilikinya satu cluster lagi (misalnya, di cloud publik), maka lebih baik melakukannya. Ini akan mencapai tingkat isolasi yang jauh lebih tinggi.

9. Kebijakan Lalu Lintas eksternal: Cluster

Sangat sering kita melihat bahwa semua lalu lintas di dalam cluster datang melalui layanan seperti NodePort, yang kebijakan defaultnya telah ditetapkan externalTrafficPolicy: Cluster... Ini berarti bahwa Pelabuhan Node terbuka di setiap node dalam cluster, dan Anda dapat menggunakan salah satu node tersebut untuk berinteraksi dengan layanan yang diinginkan (kumpulan pod).

10 Kesalahan Umum Saat Menggunakan Kubernetes

Pada saat yang sama, pod nyata yang terkait dengan layanan NodePort yang disebutkan di atas biasanya hanya tersedia pada layanan tertentu subset dari node ini. Dengan kata lain, jika saya terhubung ke node yang tidak memiliki pod yang diperlukan, lalu lintas akan diteruskan ke node lain, menambahkan lompatan dan peningkatan latensi (jika node berada di zona ketersediaan/pusat data yang berbeda, latensinya bisa sangat tinggi; selain itu, biaya lalu lintas keluar akan meningkat).

Sebaliknya, jika layanan Kubernetes tertentu memiliki kebijakan yang ditetapkan externalTrafficPolicy: Local, maka NodePort hanya akan terbuka pada node dimana pod yang diperlukan benar-benar berjalan. Saat menggunakan penyeimbang beban eksternal yang memeriksa status (pemeriksaan kesehatan) titik akhir (bagaimana cara kerjanya AWSELB), Dia akan mengirimkan lalu lintas hanya ke node yang diperlukan, yang akan memberikan efek menguntungkan pada penundaan, kebutuhan komputasi, tagihan keluar (dan akal sehat menyatakan hal yang sama).

Ada kemungkinan besar Anda sudah menggunakan sesuatu seperti traefik.dll ΠΈΠ»ΠΈ nginx-ingress-controller sebagai titik akhir NodePort (atau LoadBalancer, yang juga menggunakan NodePort) untuk merutekan lalu lintas masuk HTTP, dan menyetel opsi ini dapat mengurangi latensi untuk permintaan tersebut secara signifikan.

Π’ publikasi ini Anda dapat mempelajari lebih lanjut tentang externalTrafficPolicy, kelebihan dan kekurangannya.

10. Jangan terikat pada cluster dan jangan menyalahgunakan bidang kendali

Sebelumnya, server biasanya dipanggil dengan nama aslinya: Anton, HAL9000 dan Colossus... Hari ini mereka telah digantikan oleh pengidentifikasi yang dibuat secara acak. Namun, kebiasaan itu tetap ada, dan sekarang nama-nama yang tepat dikelompokkan.

Kisah yang khas (berdasarkan peristiwa nyata): semuanya dimulai dengan pembuktian konsep, sehingga cluster tersebut memiliki nama yang membanggakan pengujian… Bertahun-tahun telah berlalu dan MASIH digunakan dalam produksi, dan semua orang takut untuk menyentuhnya.

Tidak ada yang menyenangkan tentang cluster yang berubah menjadi hewan peliharaan, jadi kami sarankan untuk menghapusnya secara berkala saat berlatih pemulihan bencana (ini akan membantu rekayasa kekacauan - kira-kira. terjemahkan). Selain itu, tidak ada salahnya untuk mengerjakan lapisan kontrol (bidang kendali). Takut menyentuhnya bukanlah pertanda baik. dll mati? Teman-teman, kamu benar-benar dalam masalah!

Di sisi lain, Anda tidak boleh terbawa oleh manipulasi. Bersama waktu lapisan kontrol mungkin menjadi lambat. Kemungkinan besar, hal ini disebabkan oleh banyaknya objek yang dibuat tanpa rotasinya (situasi umum saat menggunakan Helm dengan pengaturan default, itulah sebabnya statusnya di configmaps/rahasia tidak diperbarui - akibatnya, ribuan objek terakumulasi di lapisan kontrol) atau dengan pengeditan objek kube-api secara konstan (untuk penskalaan otomatis, untuk CI/CD, untuk pemantauan, log peristiwa, pengontrol, dll.).

Selain itu, kami menyarankan untuk memeriksa perjanjian SLA/SLO dengan penyedia Kubernetes yang dikelola dan memperhatikan jaminannya. Vendor dapat menjamin ketersediaan lapisan kontrol (atau subkomponennya), tetapi bukan penundaan p99 permintaan yang Anda kirim ke sana. Dengan kata lain, Anda bisa masuk kubectl get nodes, dan menerima jawaban hanya setelah 10 menit, dan ini tidak akan menjadi pelanggaran terhadap ketentuan perjanjian layanan.

11. Bonus: menggunakan tag terbaru

Tapi ini sudah menjadi klasik. Akhir-akhir ini kami semakin jarang menemukan teknik ini, karena banyak orang, setelah belajar dari pengalaman pahit, berhenti menggunakan tag tersebut :latest dan mulai menyematkan versi. Hore!

ECR mempertahankan kekekalan tag gambar; Kami menyarankan Anda membiasakan diri dengan fitur luar biasa ini.

Ringkasan

Jangan berharap semuanya berhasil dalam semalam: Kubernetes bukanlah obat mujarab. Aplikasi buruk akan tetap seperti ini bahkan di Kubernetes (dan mungkin akan bertambah buruk). Kecerobohan akan menyebabkan kompleksitas yang berlebihan, lambatnya dan stres pada lapisan kontrol. Selain itu, Anda berisiko kehilangan strategi pemulihan bencana. Jangan berharap Kubernetes menyediakan isolasi dan ketersediaan tinggi secara langsung. Luangkan waktu untuk menjadikan aplikasi Anda benar-benar cloud native.

Anda bisa mengetahui pengalaman gagal dari berbagai tim di kumpulan cerita ini oleh Henning Jacobs.

Mereka yang ingin menambah daftar kesalahan yang diberikan dalam artikel ini dapat menghubungi kami di Twitter (@MarekBartik, @MstrsObserver).

PS dari penerjemah

Baca juga di blog kami:

Sumber: www.habr.com

Tambah komentar