
Halo semua! Nama saya Oleg Sidorenkov, saya bekerja di DomClick sebagai pemimpin tim infrastruktur. Kami telah menggunakan Cube untuk dijual selama lebih dari tiga tahun, dan selama ini kami telah mengalami banyak momen menarik yang berbeda dengannya. Hari ini saya akan memberi tahu Anda bagaimana, dengan pendekatan yang tepat, Anda dapat memeras lebih banyak lagi kinerja dari vanilla Kubernetes untuk kluster Anda. Siap mantap berangkat!
Anda semua tahu betul bahwa Kubernetes adalah sistem sumber terbuka yang dapat diskalakan untuk orkestrasi wadah; baik, atau 5 binari yang melakukan keajaiban dengan mengelola siklus hidup layanan mikro Anda di lingkungan server. Selain itu, ini adalah alat yang cukup fleksibel yang dapat dirangkai seperti konstruktor Lego untuk penyesuaian maksimum untuk berbagai tugas.
Dan semuanya tampak baik-baik saja: lempar server ke dalam cluster, seperti kayu bakar ke dalam kotak api, dan tidak tahu kesedihan. Tetapi jika Anda untuk lingkungan, maka Anda akan berpikir: "Bagaimana saya bisa menjaga api di tungku dan menyesali hutan?". Dengan kata lain, bagaimana menemukan cara untuk meningkatkan infrastruktur dan mengurangi biaya.
1. Lacak sumber daya tim dan aplikasi

Salah satu metode yang paling dangkal namun efektif adalah pengenalan permintaan/batasan. Pisahkan aplikasi menurut ruang nama, dan ruang nama menurut tim pengembangan. Setel aplikasi sebelum menerapkan nilai untuk konsumsi waktu prosesor, memori, penyimpanan sementara.
resources:
requests:
memory: 2Gi
cpu: 250m
limits:
memory: 4Gi
cpu: 500mBerdasarkan pengalaman, kami sampai pada kesimpulan: tidak ada gunanya menaikkan permintaan dari batas lebih dari dua kali lipat. Ukuran cluster dihitung berdasarkan permintaan, dan jika Anda menyetel aplikasi ke perbedaan sumber daya, misalnya, 5-10 kali lipat, bayangkan apa yang akan terjadi pada node Anda ketika diisi dengan pod dan tiba-tiba menerima beban. Tidak ada yang baik. Minimal, pelambatan, dan maksimal, ucapkan selamat tinggal kepada pekerja dan dapatkan beban siklik di node lainnya setelah pod mulai bergerak.
Selain itu, dengan bantuan limitranges Anda dapat menetapkan nilai sumber daya untuk wadah di awal - minimum, maksimum, dan default:
➜ ~ kubectl describe limitranges --namespace ops
Name: limit-range
Namespace: ops
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container cpu 50m 10 100m 100m 2
Container ephemeral-storage 12Mi 8Gi 128Mi 4Gi -
Container memory 64Mi 40Gi 128Mi 128Mi 2Ingatlah untuk membatasi sumber daya namespace sehingga satu perintah tidak dapat mengambil semua sumber daya cluster:
➜ ~ kubectl describe resourcequotas --namespace ops
Name: resource-quota
Namespace: ops
Resource Used Hard
-------- ---- ----
limits.cpu 77250m 80
limits.memory 124814367488 150Gi
pods 31 45
requests.cpu 53850m 80
requests.memory 75613234944 150Gi
services 26 50
services.loadbalancers 0 0
services.nodeports 0 0Seperti yang Anda lihat dari deskripsi resourcequotas, jika perintah ops ingin menyebarkan pod yang akan menggunakan 10 cpu lagi, maka penjadwal tidak akan mengizinkannya dilakukan dan akan mengeluarkan kesalahan:
Error creating: pods "nginx-proxy-9967d8d78-nh4fs" is forbidden: exceeded quota: resource-quota, requested: limits.cpu=5,requests.cpu=5, used: limits.cpu=77250m,requests.cpu=53850m, limited: limits.cpu=10,requests.cpu=10Untuk mengatasi masalah serupa, Anda dapat menulis alat, misalnya sebagai , yang dapat menyimpan dan mengkomit status sumber daya perintah.
2. Pilih penyimpanan file terbaik

Di sini saya ingin menyentuh topik volume persisten dan subsistem disk dari node pekerja Kubernetes. Saya harap tidak ada yang menggunakan "Cube" pada HDD dalam produksi, tetapi terkadang bahkan SSD biasa saja tidak cukup. Kami menghadapi masalah sedemikian rupa sehingga log mematikan disk dengan operasi I / O, dan tidak banyak solusi di sini:
Gunakan SSD berperforma tinggi atau beralih ke NVMe (jika Anda mengelola perangkat keras Anda sendiri).
Turunkan level logging.
Lakukan penyeimbangan "pintar" dari pod yang memperkosa disk (
podAntiAffinity).
Tangkapan layar di atas menunjukkan apa yang terjadi di bawah nginx-ingress-controller dengan disk saat access_logs diaktifkan (~12k log/detik). Keadaan seperti itu, tentu saja, dapat menyebabkan degradasi semua aplikasi di node ini.
Untuk PV, sayangnya, saya belum mencoba semuanya. Volume yang terus-menerus. Gunakan opsi terbaik yang cocok untuk Anda. Secara historis terjadi di negara kita bahwa sebagian kecil layanan membutuhkan volume RWX, dan sejak lama mereka mulai menggunakan penyimpanan NFS untuk tugas ini. Murah dan ... cukup. Tentu saja, kami makan kotoran dengannya - jadilah sehat, tetapi kami belajar cara menyetelnya, dan kepalanya tidak lagi sakit. Dan jika memungkinkan, alihkan ke penyimpanan objek S3.
3. Bangun Gambar yang Dioptimalkan

Sebaiknya gunakan gambar yang dioptimalkan untuk wadah agar Kubernet dapat mengambilnya lebih cepat dan menjalankannya dengan lebih efisien.
Pengoptimalan berarti bahwa gambar:
hanya berisi satu aplikasi atau hanya menjalankan satu fungsi;
ukuran kecil, karena gambar besar ditransmisikan lebih buruk melalui jaringan;
memiliki endpoint kesehatan dan kesiapan yang dapat digunakan Kubernetes untuk mengambil tindakan jika terjadi downtime;
gunakan sistem operasi ramah wadah (seperti Alpine atau CoreOS) yang lebih tahan terhadap kesalahan konfigurasi;
gunakan build multi-tahap sehingga Anda hanya dapat menerapkan aplikasi yang dikompilasi dan bukan sumber yang menyertainya.
Ada banyak alat dan layanan yang memungkinkan Anda memeriksa dan mengoptimalkan gambar dengan cepat. Penting untuk selalu memperbaruinya dan aman. Akibatnya, Anda mendapatkan:
Mengurangi beban jaringan di seluruh cluster.
Penurunan waktu startup kontainer.
Ukuran lebih kecil dari seluruh registri Docker Anda.
4. Gunakan cache DNS

Jika kita berbicara tentang beban tinggi, maka tanpa menyetel sistem DNS cluster, hidup menjadi sangat buruk. Dahulu kala, pengembang Kubernetes mendukung solusi kube-dns mereka. Itu juga diterapkan di negara kita, tetapi perangkat lunak ini tidak terlalu selaras dan tidak memberikan kinerja yang diperlukan, meskipun tampaknya tugasnya sederhana. Kemudian coredns muncul, yang kami alihkan dan tidak tahu duka, kemudian menjadi layanan DNS default di K8s. Pada titik tertentu, kami meningkatkan hingga 40 ribu rps ke sistem DNS, dan solusi ini juga tidak cukup. Tapi, secara kebetulan, Nodelocaldns keluar, alias cache lokal node, alias .
Mengapa kita menggunakan ini? Pada intinya Linux Terdapat bug yang, ketika beberapa permintaan dilakukan melalui NAT Conntrack melalui UDP, menyebabkan kondisi persaingan (race condition) untuk entri dalam tabel Conntrack, dan sebagian lalu lintas melalui NAT hilang (setiap hop melalui Layanan adalah NAT). Nodelocaldns menyelesaikan masalah ini dengan menghilangkan NAT dan meningkatkan koneksi ke TCP untuk DNS upstream, serta caching lokal permintaan DNS ke DNS upstream (termasuk cache negatif singkat selama 5 detik).
5. Menskalakan pod secara horizontal dan vertikal secara otomatis

Dapatkah Anda mengatakan dengan yakin bahwa semua layanan mikro Anda siap untuk peningkatan beban dua hingga tiga kali lipat? Bagaimana cara mengalokasikan sumber daya dengan benar ke aplikasi Anda? Mempertahankan beberapa pod yang berjalan melebihi beban kerja dapat menjadi mubazir, dan menjaganya dari belakang ke belakang berisiko mengalami downtime karena peningkatan lalu lintas yang tiba-tiba ke layanan. Rata-rata emas membantu mencapai mantra penggandaan layanan seperti и .
VPA memungkinkan Anda untuk secara otomatis menaikkan permintaan/batas wadah Anda di pod berdasarkan penggunaan sebenarnya. Bagaimana ini bisa berguna? Jika Anda memiliki Pod yang karena alasan tertentu tidak dapat diskalakan secara horizontal (yang tidak sepenuhnya dapat diandalkan), maka Anda dapat mencoba memercayai VPA untuk mengubah sumber dayanya. Fiturnya adalah sistem rekomendasi berdasarkan data historis dan terkini dari server metrik, jadi jika Anda tidak ingin mengubah permintaan/batasan secara otomatis, Anda cukup memantau sumber daya yang direkomendasikan untuk wadah Anda dan mengoptimalkan pengaturan untuk menghemat CPU dan memori dalam klaster.
Gambar diambil dari https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231
Penjadwal di Kubernetes selalu berdasarkan permintaan. Nilai apa pun yang Anda masukkan di sana, penjadwal akan mencari node yang sesuai berdasarkan itu. Nilai batas diperlukan oleh kublet untuk mengetahui kapan harus mencekik atau membunuh pod. Dan karena satu-satunya parameter penting adalah nilai permintaan, VPA akan bekerja dengannya. Setiap kali Anda menskalakan aplikasi secara vertikal, Anda menentukan permintaan apa yang seharusnya. Dan apa yang akan terjadi pada limit? Parameter ini juga akan diskalakan secara proporsional.
Misalnya, berikut adalah pengaturan pod yang khas:
resources:
requests:
memory: 250Mi
cpu: 200m
limits:
memory: 500Mi
cpu: 350mMesin rekomendasi menentukan bahwa aplikasi Anda membutuhkan CPU 300m dan 500Mi untuk berjalan dengan baik. Anda akan mendapatkan pengaturan ini:
resources:
requests:
memory: 500Mi
cpu: 300m
limits:
memory: 1000Mi
cpu: 525mSeperti disebutkan di atas, ini adalah penskalaan proporsional berdasarkan rasio permintaan/batas dalam manifes:
CPU: 200m → 300m: rasio 1:1.75;
Memori: 250Mi → 500Mi: rasio 1:2.
mengenai HPA, maka mekanisme pengoperasiannya lebih transparan. Ambang batas ditetapkan untuk metrik seperti prosesor dan memori, dan jika rata-rata semua replika melebihi ambang batas, aplikasi akan diskalakan dengan +1 pod hingga nilainya turun di bawah ambang batas, atau hingga jumlah maksimum replika tercapai.
Gambar diambil dari https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231
Selain metrik biasa seperti CPU dan Memori, Anda dapat menetapkan ambang batas pada metrik Prometheus kustom Anda dan bekerja dengannya jika Anda merasa ini adalah cara paling akurat untuk menentukan kapan harus menskalakan aplikasi Anda. Setelah aplikasi stabil di bawah ambang batas metrik yang ditentukan, HPA akan mulai menurunkan Pod ke jumlah minimum replika atau hingga beban memenuhi ambang batas.
6. Jangan Lupa Tentang Afinitas Node dan Afinitas Pod

Tidak semua node berjalan pada perangkat keras yang sama, dan tidak semua pod perlu menjalankan aplikasi intensif komputasi. Kubernetes memungkinkan Anda menentukan spesialisasi node dan pod menggunakan Afinitas Node и Afinitas Pod.
Jika Anda memiliki node yang cocok untuk operasi intensif komputasi, maka untuk efisiensi maksimum, lebih baik ikat aplikasi ke node yang sesuai. Untuk melakukan ini, gunakan nodeSelector dengan label simpul.
Katakanlah Anda memiliki dua node: satu dengan CPUType=HIGHFREQ dan sejumlah besar inti cepat, lainnya dengan MemoryType=HIGHMEMORY lebih banyak memori dan kinerja lebih cepat. Cara termudah adalah dengan menetapkan penerapan pod ke sebuah node HIGHFREQdengan menambahkan ke bagian spec pemilih seperti ini:
…
nodeSelector:
CPUType: HIGHFREQCara yang lebih mahal dan spesifik untuk melakukan ini adalah dengan menggunakan nodeAffinity di lapangan affinity аздела spec. Ada dua opsi:
requiredDuringSchedulingIgnoredDuringExecution: pengaturan keras (penjadwal hanya akan menerapkan pod pada node tertentu (dan tidak di tempat lain));preferredDuringSchedulingIgnoredDuringExecution: pengaturan lunak (penjadwal akan mencoba menerapkan ke node tertentu, dan jika gagal, ia akan mencoba menerapkan ke node berikutnya yang tersedia).
Anda dapat menentukan sintaks khusus untuk mengelola label simpul, misalnya, In, NotIn, Exists, DoesNotExist, Gt или Lt. Namun, ingatlah bahwa metode rumit dalam daftar label yang panjang akan memperlambat pengambilan keputusan dalam situasi kritis. Dengan kata lain, jangan terlalu rumit.
Seperti disebutkan di atas, Kubernetes memungkinkan Anda mengatur pengikatan pod saat ini. Artinya, Anda dapat membuat pod tertentu bekerja sama dengan pod lain di zona ketersediaan yang sama (relevan untuk cloud) atau node.
В podAffinity поля affinity аздела spec bidang yang sama tersedia seperti dalam kasus nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution и preferredDuringSchedulingIgnoredDuringExecution. Satu-satunya perbedaan adalah itu matchExpressions akan mengikat pod ke node yang sudah menjalankan pod dengan label tersebut.
Lebih banyak Kubernet menawarkan bidang podAntiAffinity, yang, sebaliknya, tidak mengikat sebuah pod ke sebuah node dengan pod tertentu.
Tentang ekspresi nodeAffinity Nasihat yang sama dapat diberikan: cobalah untuk menjaga aturan tetap sederhana dan logis, jangan mencoba membebani spesifikasi pod dengan seperangkat aturan yang rumit. Sangat mudah untuk membuat aturan yang tidak sesuai dengan kondisi klaster, memberikan beban ekstra pada penjadwal dan menurunkan kinerja secara keseluruhan.
7. Noda & Toleransi
Ada cara lain untuk mengelola penjadwal. Jika Anda memiliki klaster besar dengan ratusan node dan ribuan layanan mikro, sangat sulit untuk mencegah pod tertentu dihosting oleh node tertentu.
Mekanisme noda - aturan larangan - membantu dalam hal ini. Misalnya, Anda dapat mencegah node tertentu menjalankan pod dalam skenario tertentu. Untuk menerapkan taint ke node tertentu, gunakan opsi taint di kubectl. Tentukan key dan value lalu taint like NoSchedule или NoExecute:
$ kubectl taint nodes node10 node-role.kubernetes.io/ingress=true:NoSchedulePerlu juga dicatat bahwa mekanisme noda mendukung tiga efek utama: NoSchedule, NoExecute и PreferNoSchedule.
NoScheduleberarti sampai ada entri yang sesuai dalam spesifikasi podtolerations, itu tidak dapat diterapkan ke node (dalam contoh ininode10).PreferNoSchedule- versi yang disederhanakanNoSchedule. Dalam hal ini, penjadwal akan mencoba untuk tidak mengalokasikan pod yang tidak memiliki entri yang cocok.tolerationsper node, tapi ini bukan batas keras. Jika tidak ada sumber daya di kluster, maka pod akan mulai diterapkan di node ini.NoExecute- efek ini memicu evakuasi langsung dari pod yang tidak memiliki entri yang cocoktolerations.
Anehnya, perilaku ini dapat diurungkan menggunakan mekanisme toleransi. Ini nyaman ketika ada node "terlarang" dan Anda hanya perlu menempatkan layanan infrastruktur di atasnya. Bagaimana cara melakukannya? Izinkan hanya pod yang memiliki toleransi yang sesuai.
Berikut tampilan spek pod:
spec:
tolerations:
- key: "node-role.kubernetes.io/ingress"
operator: "Equal"
value: "true"
effect: "NoSchedule"Ini tidak berarti bahwa selama redeploy berikutnya, pod akan tepat mengenai node ini, ini bukan mekanisme Afinitas Node dan nodeSelector. Namun dengan menggabungkan beberapa fitur, Anda dapat mencapai pengaturan penjadwalan yang sangat fleksibel.
8. Tetapkan Prioritas Penerapan Pod
Hanya karena Anda telah mengonfigurasi binding pod-ke-node tidak berarti bahwa semua pod harus diperlakukan dengan prioritas yang sama. Misalnya, Anda mungkin ingin menerapkan beberapa Pod sebelum yang lain.
Kubernetes menawarkan berbagai cara untuk menetapkan Prioritas dan Preemption Pod. Latar terdiri dari beberapa bagian: objek PriorityClass dan deskripsi lapangan priorityClassName dalam spesifikasi pod. Pertimbangkan sebuah contoh:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 99999
globalDefault: false
description: "This priority class should be used for very important pods only"Kami membuat PriorityClass, beri nama, deskripsi, dan nilai. Semakin tinggi value, semakin tinggi prioritasnya. Nilainya bisa berupa bilangan bulat 32-bit yang kurang dari atau sama dengan 1. Nilai yang lebih tinggi dicadangkan untuk pod sistem kritis, yang biasanya tidak dapat didahului. Pengusiran hanya akan terjadi jika pod dengan prioritas tinggi tidak memiliki tempat untuk berbalik, maka beberapa pod dari node tertentu akan dievakuasi. Jika mekanisme ini terlalu kaku untuk Anda, maka Anda dapat menambahkan opsi preemptionPolicy: Never, dan kemudian tidak akan ada preemption, pod akan menjadi yang pertama dalam antrean dan menunggu penjadwal menemukan sumber daya gratis untuknya.
Selanjutnya, kami membuat pod, di mana kami menentukan namanya priorityClassName:
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
priorityClassName: high-priority
Anda dapat membuat kelas prioritas sebanyak yang Anda suka, meskipun disarankan untuk tidak terbawa oleh ini (katakanlah, batasi diri Anda pada prioritas rendah, sedang, dan tinggi).
Jadi, jika perlu, Anda dapat meningkatkan efisiensi penerapan layanan penting, seperti nginx-ingress-controller, coredns, dll.
9. Optimalkan klaster ETCD Anda

ETCD bisa disebut sebagai otak dari seluruh cluster. Sangat penting untuk menjaga operasi database ini pada level tinggi, karena kecepatan operasi di "Cube" bergantung padanya. Cukup standar, dan pada saat yang sama, solusi yang baik adalah dengan mempertahankan cluster ETCD pada node master agar memiliki penundaan minimum ke kube-apiserver. Jika ini tidak memungkinkan, tempatkan ETCD sedekat mungkin, dengan bandwidth yang baik antar peserta. Perhatikan juga berapa banyak node dari ETCD yang dapat jatuh tanpa merusak cluster.

Perlu diingat bahwa peningkatan jumlah peserta yang berlebihan dalam kluster dapat meningkatkan toleransi kesalahan dengan mengorbankan kinerja, semuanya harus secukupnya.
Jika kita berbicara tentang menyiapkan layanan, maka ada beberapa rekomendasi:
Memiliki perangkat keras yang bagus, berdasarkan ukuran cluster (Anda dapat membaca ).
Tweak beberapa parameter jika Anda telah menyebarkan cluster antara sepasang DC atau jaringan dan disk Anda meninggalkan banyak hal yang diinginkan (Anda dapat membaca ).
Kesimpulan
Artikel ini menjelaskan poin-poin yang coba dipatuhi oleh tim kami. Ini bukan deskripsi tindakan langkah demi langkah, tetapi opsi yang dapat berguna untuk mengoptimalkan overhead cluster. Jelas bahwa setiap klaster unik dengan caranya sendiri, dan solusi penyetelan bisa sangat bervariasi, jadi akan menarik untuk mendapatkan umpan balik dari Anda: bagaimana Anda memantau klaster Kubernetes Anda, bagaimana Anda meningkatkan kinerjanya. Bagikan pengalaman Anda di komentar, akan menarik untuk mengetahuinya.
Sumber: www.habr.com
