evilfactorylabs

Cover image for Ketika kubernetes terasa masuk akal
Rizaldy
Rizaldy

Posted on

Ketika kubernetes terasa masuk akal

Tahun ini 2022, hampir di setiap komputer yang bekerja di industri IT terpasang sebuah program bernama Docker. Docker adalah sebuah produk yang dibuat oleh perusahaan bernama Docker Inc untuk membuat proses 'penjalanan aplikasi' menjadi lebih efisien berkat teknologi container. Teknologi container itu sendiri bukanlah hal yang baru, pada tahun 2000, Jails diperkenalkan di sistem operasi FreeBSD versi 4.0. Jails singkatnya adalah sebuah konsep untuk membuat sistem diatas sistem dan terisolasi dari sistem lain — yang mana secara konsep kurang lebih seperti teknologi container yang kita tahu sekarang ini.

Dan bahkan, program bernama chroot(2) itu sendiri yang menjadi cikal bakal teknologi container sudah dipekernalkan sejak tahun 1979 dalam sistem operasi UNIX.

Oke oke tapi kita sedang tidak dalam kelas sejarah sekarang.

Penggunaan Docker sendiri menurut gue pribadi lebih banyak membantu (dan bekerja) di lingkungan pengembangan, seperti, siapa yang masih buka 2 tab di terminal untuk menjalankan npm run dev dan python3 manage.py runserver? Dan jangan lupa jalanin postgres dan redis juga! Ah, pastikan si aplikasi yang berjalan dan bertindak sebagai worker harus berjalan juga.

Tidak sampai situ, pastikan dependensi yang digunakan harus sudah terpasang! Apa saja dependensi yang harus dipasang? Read your README.md if you're lucky.

Docker cukup sukses mengambil hati pengembang dengan menawarkan "cara baru" dalam membuat; menjalankan, dan membagikan aplikasi. Tidak perlu autoconf(1) ribet, tidak perlu multi output untuk beda OS dan platform, tidak perlu makepkg -si, jika docker berjalan di komputer mu maka aplikasi yang dibungkus dengan format OCI image kemungkinan besar akan berjalan. Bahkan bisa berjalan sendiri setelah boot selesai tanpa harus menyentuh init daemon.

Plus, dalam lingkungan yang terisolasi. Seperti, jika emacs hanya digunakan di container tersebut, maka emacs hanya berada di container tersebut.

Bagian paling menarik dari teknologi container ini adalah proses dari pengembangan sampai ke rilis menjadi lebih ter-prediksi sehingga kasus "It works on my machine" yang sangat 2009 seharusnya sudah tidak terjadi lagi berkat teknologi container ini, plus Docker menawarkan cara membuat sebuah container secara deklaratif. Dan selain berdampak ke proses pengembangan, juga berdampak ke proses operasional sehingga kita sebagai sysadmin tidak perlu lagi extract tar archives on-the-fly karena itu menjadi pekerjaannya docker untuk mengambil (hasil) program dari sesuatu bernama artifact repository.

8 paragraf diatas adalah introduksi dari topik inti di tulisan ini agar terlihat lebih panjang. Jika lo sudah familiar dengan teknologi container, khususnya bila sudah menjalankan aplikasi dalam bentuk container, harusnya tulisan ini relevan dengan lo.

Jika memang ternyata belum, pertimbangkan menggunakan Heroku before it's too late.

Just kidding.

The process manager

Ketika lo menjalankan sebuah program, berarti lo menjalankan sebuah proses. Proses tersebut diatur oleh OS yang lo gunakan dan memiliki ID unik sebagai penanda. Seperti, program Safari yang gue gunakan sekarang untuk menulis tulisan ini memiliki ID 63849.

Berdasarkan ID tersebut kita bisa mengetahui informasi seperti siapa yang menjalankan program, berapa CPU yang digunakan, memory, dsb.

contoh

Nah, apa yang terjadi jika si program sedang membutuhkan banyak CPU dan memakan banyak memory? Di kasus langka, sistem operasi akan kurang responsif. Di beberapa sistem operasi terkadang menawarkan untuk menutup program tersebut, atau mungkin pengguna secara sukarela terpaksa membuka "Task Manager" untuk menutup program lain agar komputer mereka kembali responsif ;)

Tapi itu untuk lingkungan desktop, berbeda dengan lingkungan server yang memiliki workload berbeda. Server dimaksudkan untuk terus berjalan 24/7 sekalipun hujan badai menyerang. Server selain dimaksudkan untuk terus berjalan, juga dimaksudkan untuk melayani permintaan apapun yang ada, sebagaimana sebutannya: server.

Di banyak kasus, permintaan tersebut berbentuk paket yang ditransmisi dalam protokol TCP, termasuk permintaan ketika lo mengakses URL ini dan server tempat si website ini berjalan harus ngasih halaman yang sedang lo baca sekarang.

Jika si website mati, siapapun yang mengoperasikan server tersebut harus menyalakannya kembali. Berkat service manager (i.e: systemd, launchd, dkk), kita bisa membebankan tugas tersebut ke si OS.

Jika si OS mati, kita bisa membebankan tugas tersebut ke hypervisor jika OS tersebut berjalan diatas mesin virtual. Jika bare metal, kita bisa membebankan tugas tersebut ke anak magang agar pergi ke data center.

Just kidding, mungkin bisa pakai Tinkerbell atau MAAS, idk.

Anggap komputer kita memiliki memory (RAM) 4Gi dan CPU 1. Setidaknya program/proses yang ada harus dibawah ambang batas dari spek komputer yang kita miliki. Seperti, jika ada 2 program yang masing-masing menggunakan 2Gi memory dan 0.6% CPU, besar kemungkinan komputer kita akan freeze dan syukur jika tidak crash (shutdown/reboot sendiri).

Di workload server, khususnya dalam penggunakan Docker, kita bisa mengalokasi sumber daya ke sebuah container sesuai dengan yang kita inginkan. Plus, bisa memberikan batas berapa sumber daya maksimal yang bisa digunakan. Pendekatan ini bisa mencegah server lo meledak karena menjalankan aplikasi ruby on rails lo yang lapar itu.

Of course lo gak butuh Docker untuk "budgeting" sumber daya dalam menjalankan sebuah program, karena secara teori, jika dengan Docker bisa dilakukan, tanpa Docker pun harusnya bisa juga.

Anyway, tentu saja masalah tersebut bisa saja diselesaikan dengan menaikkan sumber daya lo. Jika program lo membutuhkan 2Gi memory dan 2 CPU, setidaknya komputer lo harus punya 4Gi memory dan 4 CPU. Pendekatan ini umumnya disebut dengan "vertical scaling" atau "scale up" jika menggunakan bahasa PM untuk menggambarkan sebuah "upgrade". Umumnya ada 2 pendekatan yang bisa digunakan, yang satu lagi adalah "horizontal scaling" atau "scale out".

Alih-alih menaikkan sumber daya, dia menambahkan sumber daya baru ke komputer baru. Alias, cara mendapatkan memori 4Gi dan 4 CPU tersebut adalah dengan menggunakan 2 komputer ber-memori 2Gi dan memiliki 1 CPU.

Secara teori, itu bukan hal yang mustahil. Dan bahkan sudah digunakan oleh beberapa perusahaan.

Alasan mengapa menambah sumber daya alih-alih menaikkannya, itu adalah topik inti dari tulisan ini.

The very scale up

Ketika menjalankan program dalam bentuk container, setidaknya lingkungan yang ter-isolasi adalah berikut:

  • File system
  • Network
  • User/Group ID
  • Control group

Setiap container memiliki root directory nya sendiri, network interface nya sendiri, dan pid 1 nya sendiri. Jika ada 2 container yang berjalan menggunakan network nya masing-masing, maka 2 container tersebut tidak bisa berkomunikasi.

Aplikasi sekarang kebanyakan dibuat sebagai aplikasi stateless, yang sederhananya tidak memiliki side effect. Salah satu contohnya, misal untuk di level OS. Anggap jika aplikasi tersebut adalah Notepad, dia hanya bisa membuka dan menyimpan sebuah berkas yang menunjuk ke external URL, bukan ke lokal. Jika aplikasi lo tidak melakukan operasi menulis ke OS, kemungkinan aplikasi lo bisa disebut stateless jika konteks state tersebut adalah file system.

Anggap kita ingin melakukan transcode video.

Proses tersebut memakan sumber daya yang tidak sedikit, terlebih bila kita hanya menggunakan kekuatan dari CPU. Misal, kita ingin membuat 2 resolusi dari 1 video berdurasi 80 menit dengan komputer ber memori 8Gi dan 8 CPU. Yang anggap memakan waktu 40 menit. Secara imajinasi, jika kita gandakan speknya menjadi memori 16Gi dan 16 CPU, harusnya si video tersebut dapat selesai dalam waktu 20 menit.

Agar komputer tidak freeze, kita buat si proses yang ada di container tersebut hanya boleh menggunakan ~87% dari sumber daya yang ada, berarti memori 6.9Gi dan 6.96 CPU. Dari yang sebelumnya 40 menit, anggap menjadi 46 menit. Jika misalnya kita gandakan speknya menjadi memori 13.8Gi dan 13.92 CPU, secara imajinasi si video tersebut dapat selesai dalam waktu 23 menit.

Untuk bisa memiliki memory 16Gi dan 16 CPU adalah dengan... memilikinya.

LOL ok that's how reality sounds.

Dengan virtualisasi cloud, tidak jarang penyedia cloud menawarkan fitur "vertical scaling" secara otomatis jika sudah/akan menyentuh ambang yang sudah kita definisikan. Misal, jika penggunaan sumber daya akan menyentuh 87% dari total sumber daya yang ada, then double the number.

Tapi kenyataannya tidak sesederhana itu.

Sejauh yang gue tahu, sampai hari ini mesin harus dalam kondisi mati untuk bisa di upgrade, sekalipun si mesin tersebut virtual. Dan ini cikal bakal horizontal scaling atau scale out laris digunakan karena secara teori menambah baru lebih murah daripada menambah yang ada.

Yang secara tidak langsung, realita untuk bisa memiliki memory 16Gi dan 16 CPU adalah dengan memilikinya, sudah tidak relevan lagi jika bisa dengan cara memiliki 2*8Gi memory dan 2*8 CPU.

The very scale out

Ingat jika kita menjalankan program kita dalam bentuk container. By default, container tersebut berjalan di satu mesin. Jika ingin menjalankan di lebih dari 1 mesin, berarti lo explicitly harus manage container-container yang ada di n mesin tersebut.

Jika tidak ingin ribet manage, lo harus menggunakan sesuatu yang bisa manage banyak container di banyak mesin, secara otomatis. Docker sendiri memiliki mode swarm, setiap mesin yang terhubung akan diatur oleh sesuatu bernama "swarm manager". Kumpulan mesin yang terhubung ini disebut cluster, dan mesin-mesin ini disebut node.

Misal, ketika lo ingin menjalankan sidekiq, si swarm manager ini yang akan mengatur di mesin mana (node) si container tersebut akan dijalankan. Termasuk jika lo ingin mereplika si sidekiq tersebut, tugas lo hanya memberi tahu bahwa lo butuh 2 instance sidekiq ke si swarm manager, dan tugas si swarm manager tersebut yang mengatur dimana si sidekiq satunya lagi tersebut akan dijalankan.

Proses otomatisasi manajemen container ini kurang lebih disebut "container orchestration". Jika lo bisa melakukannya secara manual (i.e: tanpa mode swarm), besar kemungkin si container orchestrator nya itu harusnya adalah lo sendiri.

Kita kembali ke kasus transcode video lagi.

Anggap sekarang kita memiliki 2 server Intel NUC yang masing-masing memiliki memory 8Gi dan 8 CPU. Berikut ilustrasi kerennya:

Image description

Dalam konsep cluster, yang dilihat adalah seperti ini:

Image description

Jika gue beli Intel NUC lagi dengan spek yang sama dan tambahin itu mesin ke cluster, si cluster simply menjadi seperti ini:

Image description

Sekarang gue balikin jadi dua dulu biar sesuai dengan contoh sebelumnya. Misal ilustrasinya seperti ini:

Image description

Lalu kita menambahkan fitur untuk bisa transcode video concurrently dengan memecahnya since kita sekarang menggunakan cluster yang cocok dengan workload seperti itu:

Image description

Aplikasi kita si transcode-video ini technically gak tahu apa-apa tentang video yang ingin di transcode as dia hanya menerima tugas dari si broker, dan as expected, si transcode-video ini akan menggunakan >=100% dari resource yang sudah di budget oleh kita.

Lalu kita membuat strategi, jika selama 3 menit penggunaan resource >= 80%, kita akan me-replica si aplikasi transcode-video ini. Dan karena si broker tahu bahwa ada consumer baru, dia somehow akan memberikan task ke si consumer tersebut:

Image description

Selama job masih ada, si transcode-video ini akan terus melakukan pekerjaannya, dan akan terus mereplika sampai maksimal replika sudah terpenuhi atau sampai sumber daya sudah tidak bisa dialokasikan lagi.

And as the peak time drop, si orchestrator seharusnya melakukan scale in/scale down untuk tetap menjaga sumber daya efektif.

Masalah dari Docker Swarm sejauh yang gue tahu adalah dia tidak bisa scale in dan out secara otomatis.

Dan itulah alasan utama gue menulis tentang ini.

Si paling container orchestration

Kata pertama ketika mendengar "Kubernetes" besar kemungkinan adalah "ribet". Dan yang gue yakin, Kubernetes yang mereka maksud kurang lebih seperti ingin bermigrasi ke cloud, dan yang dilakukan adalah setup openstack.

Oke oke, tapi gue setuju kalau Kubernetes ribet. I mean, kubernetes memang ribet, tapi gue rasa tidak seribet itu. Ribet karena lo harus mengetahui konsep baru, teknologi baru, dan tentu saja best practices nya termasuk operation dan security.

Dari segi learning curve, relatif tinggi. Hampir sama seperti mempelajari Docker ketika belum familiar dengan teknologi container.

Satu hal yang membuat gue kenapa Kubernetes terasa masuk akal adalah karena banyak penyedia cloud menawarkan layanan Managed Kubernetes, dan lo sekarang bisa berhenti membaca tulisan ini jika hanya ingin mengetahui jawabannya.

Contoh-contoh tadi yang sempat kita bahas menggunakan ilustrasi yang sudah kita ketahui, di kasus nyata, kita akan selalu berurusan dengan ketidakpastian.

Salah satu contoh layanan Managed Kubernetes yang gue pakai adalah GKE, atau Google Kubernetes Engine dari GCP. GKE membuat proses pembuatan cluster menjadi lebih mudah, lo bisa define berapa minimal mesin/node yang harus dimiliki, dan berapa maksimalnya (alas <=15k nodes) berdasarkan kebutuhan lo.

Di lingkungan cloud, time is money. Salah satu yang dijual oleh apapun yang menganggap dirinya cloud adalah billing relatif dihitung berdasarkan seberapa banyak yang digunakan, bukan seberapa banyak yang menggunakan. Jika organisasi lo memiliki 100 users sedangkan transaction email yang dikirim perbulan adalah 50, kemungkinan besar yang lo bayar adalah 50 nya bukan 100 nya.

Tapi strategi pricing setiap bisnis berbeda-beda, dan gue bukan orang bizdev.

Anyways, anggap lo menjalankan situs berita yang menerima trafik 100k perbulan alias 3,3k/hari alias 138/jam. Untuk bisa menangani 2 requests/menit tentu tidak perlu mengambil DevOps Engineer certification sekalipun dengan VPS $6/mo di DigitalOcean.

Tapi somehow situs berita lo viral!

Cheers?

Artis paling kontroversial se tiktok indonesia membagikan tautan lo dan situs lo langsung diserbu oleh 9M penggunanya. Situs lo sekarang setidaknya harus bisa meng-handle permintaan 150k/jam, alias 2,5k/menit nya. Satu halaman setidaknya ada 5 request, berarti harus bisa handle 12,5k requests/menit yang mana adalah 208 requests/detik.

Situs lo down, nginx bilang 503 Service Unavailable, dan hashtag #hugops bertebaran di twitter. Membutuhkan waktu 10 menit untuk meng-upgrade server, menyalakan kembali server, dan menjalankan aplikasi lo — dan lo kehilangan 25k pengunjung dari down time tersebut.

Yes, para senior akan bilang jika yang lo butuhkan adalah cache karena server MySQL lo hanya bisa handle 40 connections/detik dan lo tidak menggunakan connection pooling.

Anyway, tentu aplikasi tidak sesederhana itu. Di halaman tersebut ada kolom komentar, kolom reaction, ada artificial intelligence 4.0 untuk menentukan apakah komentar yang ada adalah phising, hate speech, ataupun promosi obat pembesar alat vital. Dan, uh, aplikasi lo juga harus tau apakah permintaan masuk dari logged in user atau crawler.

Masalahnya adalah ada sesuatu yang tidak bisa lo kontrol, tapi sepertinya tulisan ini sudah cukup panjang dan oot untuk membahas stoikisme.

Oke oke fine, dengan menggunakan Kubernetes, it is possible to do node provisioning automatically for your cluster. Selain itu, lo bisa deprioritize workload lain yang kurang penting yang bukan komponen utama dari aplikasi lo.

Deploy 3 pods di 3 zone, jika setiap zone bisa memiliki 5 nodes dan 1 node bisa menjalankan 3 pods, harusnya total nodes yang lo bisa buat adalah 15, dan total pods yang bisa lo replika adalah 45 pods, jika perhitungan gue tidak mabok.

Jika ada 208 requests/detik, setidaknya dengan 45 pods, satu pod bisa cuma handle 14 requests/detik jika menggunakan round robin.

Gue personally tidak peduli apakah itu Kubernetes, K3s, Nomad, Docker Swarm, dkk. Selama dia menyebut dirinya sebagai "container orchestration tools" dan support autoscale dari level pods ke level cluster, I'm in.

Sejauh ini hanya Kubernetes yang gue tahu, and I'm happy if I' wrong.

Scalability

People keep talking about scalability, yet what is the context.

Scalability umumnya berarti "kemampuannya untuk berkembang", no citation needed. Ketika ada yang bilang apapun berkaitan dengan "scalable", harusnya maksudnya adalah "apakah mampu melakukan X ketika Y".

Jika aplikasi lo dapat memproses 100k pencarian/detik, berarti aplikasi lo scalable dengan skala yang lo sudah tentukan tersebut, yang mana 100k/detik. Jika yang orang lain inginkan adalah 500k/detik, aplikasi lo simply bukan di skala mereka.

Dan ini bagian dari marketing juga.

Bukan tanpa alasan mengapa di beberapa landing page menuliskan "25B+ request/week", "10PB data served", "198 Tbps Edge network capacity" dsb, karena itu adalah angka yang sudah mereka capai dan mampu, sekalipun, sekali lagi, gue bukan orang bizdev.

And the interesting part about scalability is the numbers.

Penutup

Back to container, penggunaan teknologi container ini dimaksudkan untuk menjalankan (mengoperasikan) sebuah program dengan efektif dan efisien.

Untuk mengetahui apakah sesuatu tersebut efektif dan efisien, kita harus merancang dan mengukur, dari segi performa sampai keamanan.

Tidak jarang sebuah aplikasi disebut "aman" karena berjalan di container, meskipun uid yang digunakan adalah 0. Tidak jarang aplikasi yang berjalan di container tidak membatasi penggunaan resource, selagi restart policy nya always. Dan itu tidak salah, karena setiap orang organisasi memiliki perencanaan yang berbeda-beda.

But if you're playing with numbers, or booleans, then you should have an answer, where it all comes from.

Sebagai penutup, ketika menggunakan Kubernetes, gue jadi harus tau angka-angka yang harus gue punya agar Kubernetes melakukan sesuatu berdasarkan yang gue mau.

Sekali lagi, gue personally tidak peduli apakah itu Kubernetes, K3s, Nomad, Docker Swarm, dkk. Selama dia menyebut dirinya sebagai "container orchestration tools" dan support autoscale dari level pods ke level cluster, I'm in. Sejauh ini hanya Kubernetes yang gue tahu, and I'm happy if I' wrong.

Thanks for your time, and let's connect with me on dating app.

Discussion (0)