This is the multi-page printable view of this section. Click here to print.
Pods
1 - Pengenalan Pod
Halaman ini menyajikan ikhtisar dari Pod
, objek terkecil yang dapat di deploy di dalam objek model Kubernetes.
Memahami Pod
Sebuah Pod adalah unit dasar di Kubernetes--unit terkecil dan paling sederhana di dalam objek model Kubernetes yang dapat dibuat dan di deploy. Sebuah Pod merepresentasikan suatu proses yang berjalan di dalam klaster.
Pod membungkus sebuah kontainer (atau, di beberapa kasus, beberapa kontainer), sumber penyimpanan, alamat jaringan IP yang unik, dan opsi yang mengatur bagaimana kontainer harus dijalankan. Pod merupakan representasi dari unit deployment: sebuah instance aplikasi di dalam Kubernetes, yang mungkin terdiri dari satu kontainer atau sekumpulan kontainer yang berbagi resource.
Docker adalah salah satu kontainer runtime yang paling umum digunakan di Kubernetes Pod, tetapi Pod mendukung kontainer runtime lainnya.
Pod di Kubernetes klaster dapat digunakan dengan dua cara:
- Pod menjalankan satu kontainer. Model satu kontainer per Pod adalah model yang umum digunakan di Kubernetes; kamu dapat membayangkan sebuah Pod sebagai pembungkus kontainer tersebut, dan Kubernetes tidak mengelola kontainer secara langsung tetapi mengelola Pod tersebut.
- Pod menjalankan beberapa kontainer yang perlu berjalan bersamaan. Sebuah Pod dapat membungkus sebuah aplikasi yang terdiri dari beberapa kontainer yang perlu berbagi resource. Kontainer yang ditempatkan di dalam satu Pod ini membentuk sebuah layanan. Sebuah kontainer menyajikan berkas dari sumber penyimpanan ke publik, sedangkan kontainer sidecar yang lain melakukan pembaharuan terhadap berkas tersebut. Pod membungkus semua kontainer dan resource penyimpanan sebagai satu kesatuan yang dapat dikelola.
Kubernetes Blog menyediakan beberapa informasi tambahan terkait penggunaan Pod. Informasi selengkapnya, kunjungi:
Setiap Pod dimaksudkan untuk menjalankan satu instance aplikasi. Jika kamu ingin mengembangkan aplikasi secara horizontal (contoh, banyak instance sekaligus), kamu dapat menggunakan banyak Pod, satu untuk setiap instance. Di Kubernetes, konsep ini umumnya disebut dengan replikasi. Pod yang direplikasi biasanya dibuat dan dikelola sebagai grup oleh objek abstraksi yang disebut kontroler. Lihat Pod dan Kontroler untuk informasi selengkapnya.
Bagaimana Pod mengelola beberapa Kontainer
Pod didesain untuk mendukung banyak proses (sebagai kontainer) yang membentuk sebuah layanan. Kontainer di dalam sebuah Pod akan otomatis ditempatkan bersama di dalam satu mesin fisik atau mesin virtual di dalam klaster. Kontainer tersebut dapat berbagi resource dan dependensi, berkomunikasi satu sama lain, dan berkoordinasi kapan dan bagaimana mereka diterminasi.
Perhatikan bahwa mengelompokan kontainer di dalam satu Pod merupakan kasus lanjutan. Kamu dapat menggunakan pola ini hanya dalam kasus tertentu. Sebagai contoh, kamu memiliki kontainer yang bertindak sebagai web server yang menyajikan berkas dari resource penyimpanan bersama, dan kontainer sidecar melakukan pembaharuan terhadap berkas tersebut dari sumber lain, seperti dalam diagram Pod berikut:
Pod menyediakan dua jenis resource sebagai penyusun dari kontainer: jaringan dan penyimpanan.
Jaringan
Setiap Pod diberikan sebuah alamat IP unik. Setiap kontainer di dalam Pod berbagi network namespace, termasuk alamat IP dan port jaringan. Setiap kontainer di dalam Pod dapat berkomunikasi satu sama lain menggunakan localhost. Saat para kontainer di dalam Pod berkomunikasi dengan entitas lain di luar Pod, mereka harus berkoordinasi satu sama lain bagaimana mereka menggunakan resource jaringan (seperti Port).
Penyimpanan
Pod dapat menentukan penyimpanan bersama yaitu volumes. Semua kontainer di dalam Pod dapat mengakses volumes ini, mengizinkan kontainer untuk berbagi data. Volumes juga memungkinkan data di Pod untuk bertahan jika salah satu kontainer perlu melakukan proses restart. Lihat Volumes untuk informasi lebih lanjut bagaimana Kubernetes mengimplementasikan penyimpanan di dalam Pod.
Bekerja dengan Pod
Kamu akan jarang membuat Pod secara langsung di Kubernetes. Ini karena Pod dirancang sebagai entitas sesaat. Saat Pod dibuat (baik oleh kamu, atau secara tidak langsung oleh kontroler), Pod ditempatkan dan dijalankan di sebuah Node di dalam klaster. Pod akan tetap di Node tersebut sampai proses dihentikan, Objek Pod dihapus, Pod dihentikan karena kekurangan resource, atau Node tersebut berhenti berjalan.
Pod tidak melakukan mekanisme penyembuhan diri sendiri. Jika Pod ditempatkan disebuah Node yang gagal, atau proses penempatan Pod itu sendiri gagal, Pod akan dihapus; demikian juga, Pod tidak akan bertahan jika Node tersebut kehabisan resource atau sedang dalam tahap pemeliharaan. Kubernetes menggunakan abstraksi yang disebut kontroler, yang menangani dan mengelola Pod. Jadi, meskipun Pod dapat dipakai secara langsung di Kubernetes, kontroler merupakan cara umum yang digunakan untuk mengelola Pod. Lihat Pod dan kontroler untuk informasi lebih lanjut bagaimana Kubernetes menggunakan kontroler untuk mengimpelentasikan mekanisme penyembuhan diri sendiri dan replikasi pada Pod.
Pod dan Kontroler
Kontroler dapat membuat dan mengelola banyak Pod untuk kamu, menangani replikasi dan menyediakan kemampuan penyembuhan diri sendiri pada lingkup klaster. Sebagai contoh, jika sebuah Node gagal, kontroler akan otomatis mengganti Pod tersebut dengan menempatkan Pod yang identik di Node yang lain.
Beberapa contoh kontroler yang berisi satu atau lebih Pod meliputi:
Secara umum, kontroler menggunakan templat Pod yang kamu sediakan untuk membuat Pod.
Templat Pod
Templat Pod adalah spesifikasi dari Pod yang termasuk di dalam objek lain seperti Replication Controllers, Jobs, dan DaemonSets. Kontroler menggunakan templat Pod untuk membuat Pod.
Contoh di bawah merupakan manifestasi sederhana untuk Pod yang berisi kontainer yang membuat sebuah pesan.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
Perubahan yang terjadi pada templat atau berganti ke templat yang baru tidak memiliki efek langsung pada Pod yang sudah dibuat. Pod yang dibuat oleh replication controller dapat diperbarui secara langsung.
Selanjutnya
- Pelajari lebih lanjut tentang perilaku Pod:
2 - Pod
Pod adalah unit komputasi terkecil yang bisa di-deploy dan dibuat serta dikelola dalam Kubernetes.
Apa Itu Pod?
Sebuah Pod (seperti pod pada paus atau kacang polong) adalah sebuah kelompok yang terdiri dari satu atau lebih kontainer (misalnya kontainer Docker), dengan ruang penyimpanan ataupun jaringan yang dipakai bersama, dan sebuah spesifikasi mengenai bagaimana menjalankan kontainer. Isi dari Pod akan selalu diletakkan dan dijadwalkan bersama, serta berjalan dalam konteks yang sama. Sebuah Pod memodelkan "logical host" yang spesifik terhadap aplikasi. Ini mengandung lebih dari satu kontainer aplikasi yang secara relatif saling terhubung erat. Sebelum masa kontainer, menjalankan aplikasi dalam mesin fisik atau virtual berarti menjalankan dalam logical host yang sama.
Walaupun Kubernetes mendukung lebih banyak runtime kontainer selain Docker, namun Docker adalah yang paling umum diketahui dan ini membantu dalam menjelaskan Pod dengan istilah pada Docker.
Konteks bersama dalam sebuah Pod adalah kumpulan Linux namespace, cgroup dan kemungkinan segi isolasi lain, hal yang sama yang mengisolasi kontainer Docker. Dalam sebuah konteks pada Pod, setiap aplikasi bisa menerapkan sub-isolasi lebih lanjut.
Semua kontainer dalam suatu Pod akan berbagi alamat IP dan port yang sama,
dan bisa saling berkomunikasi melalui localhost
. Komunikasi tersebut mengunakan
standar inter-process communications (IPC) seperti SystemV semaphores
atau POSIX shared memory. Kontainer pada Pod yang berbeda memiliki alamat IP
yang berbeda dan tidak dapat berkomunikasi menggunakan IPC tanpa
pengaturan khusus. Kontainer ini
biasa berkomunikasi dengan yang lain menggunakan alamat IP setiap Pod.
Aplikasi dalam suatu Pod juga memiliki akses ke ruang penyimpanan bersama, yang didefinisikan sebagai bagian dari Pod dan dibuat bisa diikatkan ke masing-masing filesystem pada aplikasi.
Dalam istilah konsep Docker, sebuah Pod dimodelkan sebagai gabungan dari kontainer Docker yang berbagi namespace dan ruang penyimpanan filesystem.
Layaknya aplikasi dengan kontainer, Pod dianggap sebagai entitas yang relatif tidak kekal (tidak bertahan lama). Seperti yang didiskusikan dalam siklus hidup Pod, Pod dibuat, diberikan ID unik (UID), dan dijadwalkan pada suatu mesin dan akan tetap disana hingga dihentikan (bergantung pada aturan restart) atau dihapus. Jika mesin mati, maka semua Pod pada mesin tersebut akan dijadwalkan untuk dihapus, namun setelah suatu batas waktu. Suatu Pod tertentu (sesuai dengan ID unik) tidak akan dijadwalkan ulang ke mesin baru, namun akan digantikan oleh Pod yang identik, bahkan jika dibutuhkan bisa dengan nama yang sama, tapi dengan ID unik yang baru (baca replication controller untuk info lebih lanjut)
Ketika sesuatu dikatakan memiliki umur yang sama dengan Pod, misalnya saja ruang penyimpanan, maka itu berarti akan tetap ada selama Pod tersebut masih ada. Jika Pod dihapus dengan alasan apapun, sekalipun Pod pengganti yang identik telah dibuat, semua yang berhubungan (misalnya ruang penyimpanan) akan dihapus dan dibuat ulang.
Sebuah Pod dengan banyak kontainer, yaitu File Puller dan Web Server yang menggunakan ruang penyimpanan persisten untuk berbagi ruang penyimpanan bersama antara kontainer.
Motivasi suatu Pods
Pengelolaan
Pod adalah suatu model dari pola beberapa proses yang bekerja sama dan membentuk suatu unit layanan yang kohesif. Menyederhanakan proses melakukan deploy dan pengelolaan aplikasi dengan menyediakan abstraksi tingkat yang lebih tinggi daripada konstituen aplikasinya. Pod melayani sebagai unit dari deployment, penskalaan horizontal, dan replikasi. Colocation (co-scheduling), berbagi nasib (misalnya dimatikan), replikasi terkoordinasi, berbagi sumber daya dan pengelolaan ketergantungan akan ditangani otomatis untuk kontainer dalam suatu Pod.
Berbagi sumber daya dan komunikasi
Pod memungkinkan berbagi data dan komunikasi diantara konstituennya.
Semua aplikasi dalam suatu Pod menggunakan namespace jaringan yang sama
(alamat IP dan port yang sama), dan menjadikan bisa saling mencari dan berkomunikasi
dengan menggunakan localhost
. Oleh karena itu, aplikasi dalam Pod harus
berkoordinasi mengenai penggunaan port. Setiap Pod memiliki alamat IP
dalam satu jaringan bersama yang bisa berkomunikasi dengan komputer lain
dan Pod lain dalam jaringan yang sama.
Kontainer dalam suatu Pod melihat hostname sistem sebagai sesuatu yang sama
dengan konfigurasi name
pada Pod. Informasi lebih lanjut terdapat dibagian
jaringan.
Sebagai tambahan dalam mendefinisikan kontainer aplikasi yang berjalan dalam Pod, Pod memberikan sepaket sistem penyimpanan bersama. Sistem penyimpanan memungkinkan data untuk bertahan saat kontainer dijalankan ulang dan dibagikan kepada semua aplikasi dalam Pod tersebut.
Penggunaan Pod
Pod dapat digunakan untuk menjalankan beberapa aplikasi yang terintegrasi secara vertikal (misalnya LAMP), namun motivasi utamanya adalah untuk mendukung berlokasi bersama, mengelola program pembantu, diantaranya adalah:
- sistem pengelolaan konten, pemuat berkas dan data, manajer cache lokal, dll.
- catatan dan checkpoint cadangan, kompresi, rotasi, dll.
- pengamat perubahan data, pengintip catatan, adapter pencatatan dan pemantauan, penerbit peristiwa, dll.
- proksi, jembatan dan adaptor.
- pengontrol, manajer, konfigurasi dan pembaharu.
Secara umum, masing-masing Pod tidak dimaksudkan untuk menjalankan beberapa aplikasi yang sama.
Penjelasan lebih lengkap bisa melihat The Distributed System ToolKit: Patterns for Composite Containers.
Alternatif pertimbangan
Kenapa tidak menjalankan banyak program dalam satu kontainer (Docker)?
- Transparansi. Membuat kontainer dalam suatu Pod menjadi terlihat dari infrastruktur, memungkinkan infrastruktur menyediakan servis ke kontainer tersebut, misalnya saja pengelolaan proses dan pemantauan sumber daya. Ini memfasilitasi sejumlah kenyamanan untuk pengguna.
- Pemisahan ketergantungan perangkat lunak. Setiap kontainer mungkin memiliki versi, dibuat dan dijalankan ulang secara independen. Kubernetes mungkin mendukung pembaharuan secara langsung terhadap suatu kontainer, suatu saat nanti.
- Mudah digunakan. Penguna tidak diharuskan menjalankan manajer prosesnya sendiri, khawatir dengan sinyal dan propagasi exit-code, dan lain sebagainya.
- Efisiensi. Karena infrastruktur memegang lebih banyak tanggung jawab, kontainer bisa lebih ringan.
Kenapa tidak mendukung penjadwalan kontainer berdasarkan affinity?
Cara itu bisa menyediakan lokasi yang sama, namun tidak memberikan banyak keuntungan dari Pod, misalnya saja berbagi sumber daya, IPC, jaminan berbagi nasib dan kemudahan manajemen.
Ketahanan suatu Pod (atau kekurangan)
Pod tidak dimaksudkan untuk diperlakukan sebagai entitas yang tahan lama. Mereka tidak akan bertahan dengan kegagalan penjadwalan, kegagalan mesin, atau eviction (pengusiran), misalnya karena kurangnya sumber daya atau dalam suatu kasus mesin sedang dalam pemeliharaan.
Secara umum, pengguna tidak seharusnya butuh membuat Pod secara langsung. Mereka seharusnya selalu menggunakan pengontrol, sekalipun untuk yang tunggal, misalnya, Deployment. Pengontrol menyediakan penyembuhan diri dengan ruang lingkup kelompok, begitu juga dengan pengelolaan replikasi dan penluncuran. Pengontrol seperti StatefulSet bisa memberikan dukungan terhadap Pod yang stateful.
Penggunaan API kolektif sebagai user-facing primitive utama adalah hal yang relatif umum diantara sistem penjadwalan kluster, seperti
Borg, Marathon, Aurora, dan Tupperware.
Pod diekspose sebagai primitive untuk memfasilitasi hal berikut:
- penjadwalan dan pengontrol sifat pluggability
- mendukung operasi pada level Pod tanpa perlu melakukan proksi melalui API pengontrol
- pemisahan antara umur suatu Pod dan pengontrol, seperti misalnya bootstrapping.
- pemisahan antara pengontrol dan servis, pengontrol endpoint hanya memperhatikan Pod
- komposisi yang bersih antara fungsionalitas dilevel Kubelet dan klaster. Kubelet secara efektif adalah pengontrol Pod.
- aplikasi dengan ketersediaan tinggi, yang akan mengharapkan Pod akan digantikan sebelum dihentikan dan tentu saja sebelum dihapus, seperti dalam kasus penggusuran yang direncanakan atau pengambilan gambar.
Penghentian Pod
Karena Pod merepresentasikan proses yang berjalan pada mesin didalam klaster, sangat penting untuk memperbolehkan proses ini berhenti secara normal ketika sudah tidak dibutuhkan (dibandingkan dengan dihentikan paksa dengan sinyal KILL dan tidak memiliki waktu untuk dibersihkan). Pengguna seharusnya dapat meminta untuk menghapus dan tahu proses penghentiannya, serta dapat memastikan penghentian berjalan sempurna. Ketika pengguna meminta menghapus Pod, sistem akan mencatat masa tenggang untuk penghentian secara normal sebelum Pod dipaksa untuk dihentikan, dan sinyal TERM akan dikirim ke proses utama dalam setiap kontainer. Setelah masa tenggang terlewati, sinyal KILL akan dikirim ke setiap proses dan Pod akan dihapus dari API server. Jika Kubelet atau kontainer manajer dijalankan ulang ketika menunggu suatu proses dihentikan, penghentian tersebut akan diulang dengan mengembalikan masa tenggang senilai semula.
Contohnya sebagai berikut:
- Pengguna mengirim perintah untuk menghapus Pod, dengan masa tenggang (30 detik)
- Pod dalam API server akan diperbarui dengan waktu dimana Pod dianggap "mati" bersama dengan masa tenggang.
- Pod ditampilkan dalam status "Terminating" ketika tercantum dalam perintah klien
- (bersamaan dengan poin 3) Ketika Kubelet melihat Pod sudah ditandai sebagai
"Terminating" karena waktu pada poin 2 sudah diatur, ini memulai proses penghentian Pod
- Jika salah satu kontainer pada Pod memiliki
preStop hook,
maka akan dipanggil di dalam kontainer. Jika
preStop
hook masih berjalan setelah masa tenggang habis, langkah 2 akan dipanggil dengan tambahan masa tenggang yang sedikit, 2 detik. - Semua kontainer akan diberikan sinyal TERM. Sebagai catatan, tidak semua kontainer
akan menerima sinyal TERM dalam waktu yang sama dan mungkin butuh waktu untuk
menjalankan
preStop
hook jika bergantung pada urutan penghentiannya.
- Jika salah satu kontainer pada Pod memiliki
preStop hook,
maka akan dipanggil di dalam kontainer. Jika
- (bersamaan dengan poin 3) Pod akan dihapus dari daftar endpoint untuk servis dan tidak lagi dianggap sebagai bagian dari Pod yang berjalan dalam replication controllers. Pod yang dihentikan, secara perlahan tidak akan melayani permintaan karena load balancer (seperti servis proksi) menghapus mereka dari daftar rotasi.
- Ketika masa tenggang sudah lewat, semua proses yang masih berjalan dalam Pod akan dihentikan dengan sinyal SIGKILL.
- Kubelet akan selesai menghapus Pod dalam API server dengan mengatur masa tenggang menjadi 0 (langsung menghapus). Pod akan menghilang dari API dan tidak lagi terlihat oleh klien.
Secara default, semua penghapusan akan berjalan normal selama 30 detik. Perintah
kubectl delete
mendukung opsi --grace-period=<waktu dalam detik>
yang akan
memperbolehkan pengguna untuk menimpa nilai awal dan memberikan nilai sesuai keinginan
pengguna. Nilai 0
akan membuat Pod
dihapus paksa.
Kamu harus memberikan opsi tambahan --force
bersamaan dengan --grace-period=0
untuk melakukan penghapusan paksa.
Penghapusan paksa sebuah Pod
Penghapusan paksa dari sebuah Pod didefinisikan sebagai penghapusan Pod dari state klaster dan etcd secara langsung. Ketika penghapusan paksa dilakukan, API server tidak akan menunggu konfirmasi dari kubelet bahwa Pod sudah dihentikan pada mesin ia berjalan. Ini menghapus Pod secara langsung dari API, sehingga Pod baru bisa dibuat dengan nama yang sama. Dalam mesin, Pod yang dihentikan paksa akan tetap diberikan sedikit masa tenggang sebelum dihentikan paksa.
Penghentian paksa dapat menyebabkan hal berbahaya pada beberapa Pod dan seharusnya dilakukan dengan perhatian lebih. Dalam kasus StatefulSet Pods, silakan melihat dokumentasi untuk penghentian Pod dari StatefulSet.
Hak istimewa untuk kontainer pada Pod
Setiap kontainer dalam Pod dapat mengaktifkan hak istimewa (mode privileged), dengan menggunakan tanda
privileged
pada konteks keamanan
pada spesifikasi kontainer. Ini akan berguna untuk kontainer yang ingin menggunakan
kapabilitas Linux seperti memanipulasi jaringan dan mengakses perangkat. Proses dalam
kontainer mendapatkan hak istimewa yang hampir sama dengan proses di luar kontainer.
Dengan hak istimerwa, seharusnya lebih mudah untuk menulis pada jaringan dan plugin
ruang penyimpanan sebagai Pod berbeda yang tidak perlu dikompilasi ke dalam kubelet.
API Object
Pod adalah sumber daya tingkat tinggi dalam Kubernetes REST API. Definisi Objek Pod API menjelaskan mengenai objek secara lengkap.
3 - Siklus Hidup Pod
Halaman ini menjelaskan siklus hidup sebuah Pod
Fase Pod
Field status
dari sebuah Pod merupakan sebuah objek PodStatus, yang memiliki sebuah field phase
.
Fase dari sebuah Pod adalah sesuatu yang sederhana, ringkasan yang lebih tinggi tentang Pod dalam siklus hidupnya. Fase ini tidak ditujukan sebagai sebuah kesimpulan yang luas dari observasi suatu kontainer atau state suatu Pod, serta tidak ditujukan sebagai state machine yang luas.
Jumlah dan arti dari nilai-nilai fase Pod dijaga ketat. Selain yang ada dalam dokumentasi ini, tidak perlu berasumsi mengenai Pod telah diberikan nilai phase
.
Berikut adalah nilai yang mungkin diberikan untuk suatu phase
:
Nilai | Deskripsi |
---|---|
Pending | Pod telah disetujui oleh sistem Kubernetes, tapi ada satu atau lebih image kontainer yang belum terbuat. Ini termasuk saat sebelum dijadwalkan dan juga saat mengunduh image melalui jaringan, yang mungkin butuh beberapa waktu. |
Running | Pod telah terikat ke suatu node, dan semua kontainer telah terbuat. Setidaknya ada 1 kontainer yang masih berjalan, atau dalam proses memulai atau restart. |
Succeeded | Semua kontainer di dalam Pod sudah berhasil dihentikan, dan tidak akan dilakukan restart. |
Failed | Semua kontainer dalan suatu Pod telah dihentikan, dan setidaknya ada satu kontainer yang terhenti karena kegagalan. Itu merupakan kontainer yang keluar dengan kode status bukan 0 atau dihentikan oleh sistem. |
Unknown | State suatu Pod tidak dapat diperoleh karena suatu alasan, biasanya karena kesalahan dalam komunikasi dengan host yang digunakan Pod tersebut. |
Kondisi Pod
Suatu Pod memiliki sebuah PodStatus, yang merupakan array dari PodConditions yang telah atau belum dilewati oleh Pod. Setiap elemen dari array PodConditions mungkin memiliki enam field berikut:
Field
lastProbeTime
memberikan nilai timestamp yang menandakan kapan terakhir kali kondisi kondisi Pod diperiksa.Field
lastTransitionTime
memberikan nilai timestamp yang menandakan kapan terakhir kali Pod berubah status ke status lain.Field
message
adalah pesan yang bisa dibaca manusia yang mengidikasikan detail dari suatu transisi.Field
reason
adalah suatu alasan yang unik, satu kata, ditulis secara CamelCase untuk kondisi transisi terakhir.Field
status
adalah sebuah kata dengan kemungkinan nilainya berupa "True
", "False
", dan "Unknown
".Field
type
adalah sebuah kata yang memiliki kemungkinan nilai sebagai berikut:PodScheduled
: Pod telah dijadwalkan masuk ke node;Ready
: Pod sudah mampu menerima request masuk dan seharusnya sudah ditambahkan ke daftar pembagian beban kerja untuk servis yang sama;Initialized
: Semua init containers telah berjalan sempurna.Unschedulable
: scheduler belum dapat menjadwalkan Pod saat ini, sebagai contoh karena kekurangan resources atau ada batasan-batasan lain.ContainersReady
: Semua kontainer di dalam Pod telah siap.
Pemeriksaan Kontainer
Sebuah Probe adalah sebuah diagnosa yang dilakukan secara berkala oleh kubelet dalam suatu kontainer. Untuk melakukan diagnosa, kubelet memanggil sebuah Handler yang diimplementasikan oleh kontainer. Ada 3 tipe Handler yang tersedia, yaitu:
ExecAction: Mengeksekusi perintah tertentu di dalam kontainer. Diagnosa dikatakan berhasil jika perintah selesai dengan kode status 0.
TCPSocketAction: Melakukan pengecekan TCP terhadap alamat IP kontainer dengan port tertentu. Diagnosa dikatakan berhasil jika port tersebut terbuka.
HTTPGetAction: Melakukan sebuah request HTTP Get terhadap alamat IP kontainer dengan port dan path tertentu. Diagnosa dikatakan berhasil jika responnya memiliki kode status lebih besar atau sama dengan 200 dan kurang dari 400.
Setiap pemeriksaan akan menghasilkan salah satu dari tiga hasil berikut:
- Success: Kontainer berhasil melakukan diagnosa.
- Failure: Kontainer gagal melakukan diagnosa.
- Unknown: Gagal melakukan diagnosa, sehingga tidak ada aksi yang harus dilakukan.
Kubelet dapat secara optimal melakukan dan bereaksi terhadap dua jenis pemeriksaan yang sedang berjalan pada kontainer, yaitu:
livenessProbe
: Ini menunjukkan apakah kontainer sedang berjalan. Jika tidak berhasil melakukan pemeriksaan terhadap liveness dari kontainer, maka kubelet akan mematikan kontainer, dan kontainer akan mengikuti aturan dari restart policy. Jika kontainer tidak menyediakan pemeriksaan terhadap liveness, maka nilai dari state adalahSuccess
.readinessProbe
: Ini menunjukan apakah kontainer sudah siap melayani request. Jika tidak berhasil melakukan pemeriksaan terhadap kesiapan dari kontainer, maka endpoints controller akan menghapus alamat IP Pod dari daftar semua endpoint untuk servis yang sama dengan Pod. Nilai awal state sebelum jeda awal adalahFailure
. Jika kontainer tidak menyediakan pemeriksaan terhadap readiness, maka nilai awal state adalahSuccess
.
Kapan sebaiknya menggunakan pemeriksaan terhadap liveness atau readiness?
Jika proses dalam kontainer mungkin gagal yang dikarenakan menghadapi suatu masalah
atau menjadi tidak sehat, maka pemeriksaan terhadap liveness tidak diperlukan.
Kubelet akan secara otomatis melakukan aksi yang tepat mengikuti restartPolicy
dari Pod.
Jika kamu ingin kontainer bisa dimatikan dan dijalankan ulang ketika gagal melakukan
pemeriksaan, maka tentukan pemeriksaan liveness dan tentukan nilai restartPolicy
sebagai Always
atau OnFailure
.
Jika kamu ingin mulai mengirim traffic ke Pod hanya ketika pemeriksaan berhasil, maka tentukan pemeriksaan readiness. Dalam kasus ini, pemeriksaan readiness mungkin akan sama dengan pemeriksaan liveness, tapi keberadaan pemeriksaan readiness dalam spec berarti Pod akan tetap dijalankan tanpa menerima traffic apapun dan akan mulai menerima traffic ketika pemeriksaan yang dilakukan mulai berhasil. Jika kontainermu dibutuhkan untuk tetap berjalan ketika loading data yang besar, file konfigurasi, atau melakukan migrasi ketika startup, maka tentukanlah pemeriksaan readiness.
Jika kamu ingin kontainermu dalam mematikan dirinya sendiri, kamu dapat menentukan suatu pemeriksaan readiness yang melakukan pengecekan terhadap endpoint untuk readiness. endpoint tersebut berbeda dengan endpoint untuk pengecekan liveness.
Perlu dicatat, jika kamu hanya ingin bisa menutup request ketika Pod sedang dihapus maka kamu tidak perlu menggunakan pemeriksaan readiness. Dalam penghapusan, Pod akan secara otomatis mengubah state dirinya menjadi unready tanpa peduli apakah terdapat pemeriksaan readiness atau tidak. Pod tetap ada pada state unready selama menunggu kontainer dalam Pod berhenti.
Untuk informasi lebih lanjut mengenai pengaturan pemeriksaan liveness atau readiness, lihat bagian Konfigurasi Liveness dan Readiness Probe.
Status Pod dan Kontainer
Untuk informasi lebih mendalam mengenai status Pod dan kontainer, silakan lihat PodStatus dan ContainerStatus. Mohon diperhatikan, informasi tentang status Pod bergantung pada ContainerState.
State Kontainer
Ketika Pod sudah ditempatkan pada suatu node oleh scheduler, kubelet mulai membuat kontainer menggunakan runtime kontainer.
Ada tiga kemungkinan state untuk suatu kontainer, yaitu Waiting, Running, dan Terminated.
Untuk mengecek state suatu kontainer, kamu bisa menggunakan perintah kubectl describe pod [NAMA_POD]
.
State akan ditampilkan untuk masing-masing kontainer dalam Pod tersebut.
Waiting
: Merupakan state default dari kontainer. Jika state kontainer bukan Running atau Terminated, berarti dalam Wating state. Suatu kontainer dalam Waiting state akan tetap menjalan operasi-operasi yang dibutuhkan, misalnya mengunduh images, mengaplikasikan Secrets, dsb. Bersamaan dengan state ini, sebuah pesan dan alasan tentang state akan ditampilkan untuk memberi informasi lebih.... State: Waiting Reason: ErrImagePull ...
Running
: Menandakan kontainer telah berjalan tanpa masalah. Setelah kontainer masuk ke state Running, jika terdapat hookpostStart
maka akan dijalankan. State ini juga menampilkan waktu ketika kontainer masuk ke state Running.... State: Running Started: Wed, 30 Jan 2019 16:46:38 +0530 ...
Terminated
: Menandakan kontainer telah menyelesaikan "tugasnya". Kontainer akan menjadi state ini ketika telah menyelesaikan eksekusi atau terjadi kesalahan. Terlepas dari itu, sebuah alasan dan exit code akan ditampilkan, bersama dengan waktu kontainer mulai dijalankan dan waktu berhenti. Sebelum kontainer masuk ke state Terminated, jika terdapatpreStop
hook maka akan dijalankan.... State: Terminated Reason: Completed Exit Code: 0 Started: Wed, 30 Jan 2019 11:45:26 +0530 Finished: Wed, 30 Jan 2019 11:45:26 +0530 ...
Pod readiness gate
Kubernetes v1.14 [stable]
Dalam rangka menambahkan ekstensibilitas terhadap kesiapan Pod dengan menggunakan
injeksi umpan balik tambahan atau sinyal ke dalam PodStatus
,
Kubernetes 1.11 memperkenalkan sebuah fitur bernama Pod ready++.
Kamu dapat menggunakan field baru ReadinessGate
dalam sebuah PodSpec
untuk
menunjukan kondisi tambahan yang akan dievaluasi untuk kesiapan Pod. Jika Kubernetes
tidak dapat menemukan kondisi pada field status.conditions
dalam suatu Pod,
maka statusnya akan secara otomatis menjadi False
. Berikut adalah contoh pemakaiannya:
Kind: Pod
...
spec:
readinessGates:
- conditionType: "www.example.com/feature-1"
status:
conditions:
- type: Ready # ini adalah PodCondition yang telah tersedia
status: "False"
lastProbeTime: null
lastTransitionTime: 2018-01-01T00:00:00Z
- type: "www.example.com/feature-1" # sebuah PodCondition tambahan
status: "False"
lastProbeTime: null
lastTransitionTime: 2018-01-01T00:00:00Z
containerStatuses:
- containerID: docker://abcd...
ready: true
...
Kondisi Pod yang baru harus memenuhi format label pada Kubernetes.
Sejak perintah kubectl patch
belum mendukung perubahan status objek, kondisi Pod yang baru harus mengubah melalui aksi PATCH
dengan menggunakan
salah satu dari KubeClient libraries.
Dengan diperkenalkannya kondisi Pod yang baru, sebuah Pod akan dianggap siap hanya jika memenuhi dua syarat berikut:
- Semua kontainer dalam Pod telah siap.
- Semua kontainer yang diatur dalam
ReadinessGates
bernilai "True
".
Untuk memfasilitasi perubahan tersebut terhadap evaluasi kesiapan Pod, dibuatkan sebuah kondisi Pod baru yaitu ContainerReady
,
untuk dapat menangani kondisi Pod Ready
yang sudah ada.
Dalam K8s 1.11, sebagai fitur alpha, fitur "Pod Ready++" harus diaktifkan melalui pengaturan
fitur gate pada PodReadinessGates
.
Dalam K8s 1.12, fitur tersebut sudah diaktifkan dari awal.
Aturan Menjalankan Ulang
Sebuah PodSpec memiliki field restartPolicy
dengan kemungkinan nilai berupa Always, OnFailure, dan Never.
Nilai awalnya berupa Always. restartPolicy
akan berlaku untuk semua kontainer dalam Pod.
Kontainer yang mati dan dijalankan ulang oleh kubelet akan dijalankan ulang dengan jeda waktu yang ekponensial (10s, 20s, 40s, ...)
dengan batas atas senilai lima menit. Jeda waktu ini akan diatur ulang setelah sukses berjalan selama 10 menit.
Sesuai dengan diskusi pada dokumen Pod,
setelah masuk ke suatu node, sebuah Pod tidak akan pindah ke node lain.
Umur Pod
Secara umum, Pod tidak hilang sampai ada yang menghapusnya. Ini mungkin dihapus oleh orang atau pengontrol.
Satu pengecualian untuk aturan ini adalah Pod dengan phase
bernilai Succeeded atau Failed untuk waktu
beberapa lama yang akan berakhir dan secara otomatis akan dihapus.
(diatur dalam terminated-pod-gc-threshold
pada master)
Tiga tipe pengontrol yang tersedia yaitu:
Menggunakan sebuah Job untuk Pod yang diharapkan akan berakhir, sebagai contoh, penghitungan dalam jumlah banyak. Jobs hanyak cocok untuk Pod dengan
restartPolicy
yang bernilai OnFailure atau Never.Menggunakan sebuah ReplicationController, ReplicaSet, atau Deployment untuk Pod yang tidak diharapkan untuk berakhir, sebagai contoh, web servers. ReplicationControllers hanya cocok digunakan pada Pod dengan
restartPolicy
yang bernilai Always.Menggunakan sebuah DaemonSet untuk Pod yang akan berjalan hanya satu untuk setiap mesin, karena menyediakan servis yang spesifik untuk suatu mesin.
Ketiga tipe pengontrol ini memiliki sebuah PodTemplate. Direkomdasikan untuk membuat pengontrol yang sesuai dan membiarkan ini membuat Pod, daripada membuat Pod sendiri secara langsung. Karena Pod itu sendiri tidak tahan terhadap gagalnya suatu mesin, namun pengontrol tahan.
Jika node mati atau sambungannya terputus dari klaster, Kubernetes mengatur
phase
dari semua Pod pada node yang mati untuk menjadi Failed.
Contoh
Contoh Liveness Probe tingkat lanjut
Liveness probe dieksekusi oleh kubelet, jadi semua permintaan akan dilakukan di dalam namespace jaringan kubelet.
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- args:
- /server
image: k8s.gcr.io/liveness
livenessProbe:
httpGet:
# ketika "host" tidak ditentukan, "PodIP" akan digunakan
# host: my-host
# ketika "scheme" tidak ditentukan, _scheme_ "HTTP" akan digunakan. Hanya "HTTP" and "HTTPS" yang diperbolehkan
# scheme: HTTPS
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 15
timeoutSeconds: 1
name: liveness
Contoh State
Pod sedang berjalan dan memiliki sebuah kontainer. Kontainer berhenti dengan sukses.
- Mencatat event penyelesaian.
- Jika nilai
restartPolicy
adalah:- Always: Jalankan ulang kontainer; nilai
phase
Pod akan tetap Running. - OnFailure: nilai
phase
Pod akan berubah menjadi Succeeded. - Never: nilai
phase
Pod akan berubah menjadi Succeeded.
- Always: Jalankan ulang kontainer; nilai
Pod sedang berjalan dan memiliki sebuah kontainer. Kontainer berhenti dengan kegagalan.
- Mencatat event kegagalan.
- Jika nilai
restartPolicy
adalah:- Always: Jalankan ulang kontainer, nilai
phase
Pod akan tetap Running. - OnFailure: Jalankan ulang kontainer, nilai
phase
Pod akan tetap Running. - Never: nilai
phase
Pod akan menjadi Failed.
- Always: Jalankan ulang kontainer, nilai
Pod sedang berjalan dan memiliki dua kontainer. Kontainer pertama berhenti dengan kegagalan.
- Mencatat event kegagalan.
- Jika nilai
restartPolicy
adalah:- Always: Jalankan ulang kontainer, nilai
phase
Pod akan tetap Running. - OnFailure: Jalankan ulang kontainer, nilai
phase
Pod akan tetap Running. - Never: Tidak akan menjalankan ulang kontainer, nilai
phase
Pod akan tetap Running.
- Always: Jalankan ulang kontainer, nilai
- Jika kontainer pertama tidak berjalan dan kontainer kedua berhenti:
- Mencatat event kegagalan.
- Jika nilai
restartPolicy
adalah:- Always: Jalankan ulang kontainer, nilai
phase
Pod akan tetap Running. - OnFailure: Jalankan ulang kontainer, nilai
phase
Pod akan tetap Running. - Never: nilai
phase
Pod akan menjadi Failed.
- Always: Jalankan ulang kontainer, nilai
Pod sedang berjalan dan memiliki satu kontainer. Kontainer berhenti karena kehabisan memory.
- Kontainer diberhentikan dengan kegagalan.
- Mencatat kejadian kehabisan memory (OOM)
- Jika nilai
restartPolicy
adalah:- Always: Jalankan ulang kontainer, nilai
phase
Pod akan tetap Running. - OnFailure: Jalankan ulang kontainer, nilai
phase
Pod akan tetap Running. - Never: Mencatat kejadian kegagalan, nilai
phase
Pod akan menjadi Failed.
- Always: Jalankan ulang kontainer, nilai
Pod sedang berjalan dan sebuah disk mati.
- Menghentikan semua kontainer.
- Mencatat kejadian yang sesuai.
- Nilai
phase
Pod menjadi Failed. - Jika berjalan menggunakan pengontrol, maka Pod akan dibuat ulang di tempat lain.
Pod sedang berjalan, dan node mengalami segmented out.
- Node pengontrol menunggu sampai suatu batas waktu.
- Node pengontrol mengisi nilai
phase
Pod menjadi Failed. - Jika berjalan menggunakan pengontrol, maka Pod akan dibuat ulang di tempat lain.
Selanjutnya
Dapatkan pengalaman langsung mengenai penambahan handlers pada kontainer lifecycle events.
Dapatkan pengalaman langsung mengenai pengaturan liveness dan readiness probes.
Pelajari lebih lanjut mengenai lifecycle hooks pada kontainer.
4 - Init Container
Halaman ini menyediakan ikhtisar untuk Init Container, yaitu Container khusus yang dijalankan sebelum Container aplikasi dan berisi skrip peralatan atau setup yang tidak tersedia di dalam image dari Container aplikasi.
Fitur ini telah keluar dari trek Beta sejak versi 1.6. Init Container dapat dispesifikasikan di dalam PodSpec bersama dengan array containers
aplikasi. Nilai anotasi beta akan tetap diperhitungkan dan akan menimpa nilai pada PodSpec, tetapi telah ditandai sebagai kedaluarsa pada versi 1.6 dan 1.7. Pada versi 1.8, anotasi beta tidak didukung lagi dan harus diganti menjadi nilai pada PodSpec.
Memahami Init Container
Sebuah Pod dapat memiliki beberapa Container yang berjalan di dalamnya, dan dapat juga memiliki satu atau lebih Init Container, yang akan berjalan sebelum Container aplikasi dijalankan.
Init Container sama saja seperti Container biasa, kecuali:
- Mereka selalu berjalan hingga selesai.
- Setiap Init Container harus selesai secara sukses sebelum Init Container berikutnya dijalankan.
Jika sebuah Init Container tidak selesai secara sukses untuk sebuah Pod, Kubernetes akan mengulang kembali Pod tersebut secara terus menerus hingga Init Container selesai secara sukses. Tetapi, jika Pod tersebut memiliki nilai restartPolicy
berupa Never
, Pod tersebut tidak akan diulang kembali.
Untuk menspesifikasikan sebuah Container sebagai Init Container, tambahkan kolom initContainers
pada PodSpec sebagai sebuah array JSON yang berisi objek dengan tipe Container, berdampingan dengan array containers
aplikasi.
Status-status dari Init Container dikembalikan di kolom .status.initContainerStatuses
sebagai sebuah array dari status-status Container (mirip seperti kolom status.containerStatuses
)
Perbedaan dengan Container biasa
Init Container mendukung semua kolom dan fitur dari Container aplikasi, termasuk konfigurasi limit
sumber daya, volume
, dan keamanan. Tetapi, request
dan limit
sumber daya dari sebuah Init Container ditangani dengan cara yang sedikit berbeda, yang didokumentasikan di bagian Sumber Daya di bawah. Juga, Init Container tidak mendukung readiness probe karena mereka harus berjalan hingga selesai sebelum Pod dapat siap.
Jika beberapa Init Container dispesifikasikan untuk sebuah Pod, Container-container tersebut akan dijalankan satu per satu secara berurutan. Setiap Init Container harus selesai secara sukses sebelum yang berikutnya dapat berjalan. Saat semua Init Container telah berjalan hingga selesai, Kubernetes akan menginisialisasi Pod dan menjalankan Container aplikasi seperti biasa.
Apa kegunaan Init Container?
Karena Init Container memiliki image yang berbeda dengan Container aplikasi, mereka memiliki beberapa kelebihan untuk kode yang berhubungan dengan dimulainya Init Container:
- Mereka dapat berisi dan menjalankan skrip peralatan yang tidak diinginkan untuk berada di dalam image Container aplikasi karena alasan keamanan.
- Mereka dapat berisi skrip peralatan atau setup yang tidak tersedia di dalam image aplikasi. Misalnya, kita tidak perlu membuat image dengan instruksi
FROM
dari image lainnya hanya untuk menggunakan peralatan sepertised
,awk
,python
, ataudig
pada saat setup. - Peran builder atau deployer dari image dapat bekerja secara independen tanpa harus digabung untuk membuat satu image aplikasi.
- Mereka menggunakan namespace Linux, sehingga mereka dapat memiliki sudut pandang filesystem yang berbeda dengan Container aplikasi. Oleh karenanya, mereka dapat diberikan akses terhadap
Secret
yang tidak boleh diakses oleh Container aplikasi. - Mereka berjalan hingga selesai sebelum Container aplikasi manapun dimulai, sedangkan Container aplikasi dijalankan secara paralel, sehingga Init Container menyediakan cara yang mudah untuk menunda dijalankannya Container aplikasi hingga ketentuan-ketentuan yang diinginkan dipenuhi.
Contoh-contoh
Berikut beberapa contoh kasus penggunaan Init Container:
Menunggu sebuah Service untuk dibuat dengan perintah shell seperti:
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
Mendaftarkan suatu Pod ke sebuah peladen terpisah dari downward API dengan perintah seperti:
`curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'`
Menunggu beberapa waktu sebelum menjalankan Container aplikasi dengan perintah seperti
sleep 60
.Mengklon sebuah git repository ke dalam sebuah volume.
Menaruh nilai-nilai tertentu ke dalam sebuah file konfigurasi dan menjalankan peralatan template untuk membuat file konfigurasi secara dinamis untuk Container aplikasi utama. Misalnya, untuk menaruh nilai POD_IP ke dalam sebuah konfigurasi dan membuat konfigurasi aplikasi utama menggunakan Jinja.
Contoh-contoh penggunaan yang lebih detail dapat dilihat pada dokumentasi StatefulSet dan petunjuk Produksi Pod.
Menggunakan Init Container
File YAML untuk Kubernetes 1.5 berikut menguraikan sebuah Pod sederhana yang memiliki dua buah Init Container.
Pod pertama menunggu myservice
dan yang kedua menunggu mydb
. Saat kedua Init Container tersebut sudah selesai, Podnya akan dijalankan.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
annotations:
pod.beta.kubernetes.io/init-containers: '[
{
"name": "init-myservice",
"image": "busybox:1.28",
"command": ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
},
{
"name": "init-mydb",
"image": "busybox:1.28",
"command": ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
}
]'
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
Ada sintaksis baru pada Kubernetes 1.6, walaupun sintaksis anotasi yang lama tetap akan bekerja untuk versi 1.6 dan 1.7. Sintaksis yang baru harus digunakan untuk versi 1.8 ke atas. Deklarasi Init Container dipindahkan ke dalam spec
:
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
Sintaksis versi 1.5 tetap akan bekerja pada versi 1.6 dan 1.7, tetapi kami menyarankan untuk menggunakan sintaksis versi 1.6. Pada Kubernetes 1.6, Init Container dijadikan sebagai sebuah kolom di dalam API Kubernetes. Anotasi beta tetap akan diperhitungkan pada versi 1.6 dan 1.7, tetapi tidak didukung lagi pada versi 1.8 ke atas.
File YAML di bawah menguraikan Service mydb
dan myservice
.
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
Pod ini dapat dijalankan dan di-debug dengan menggunakan perintah berikut:
kubectl apply -f myapp.yaml
pod/myapp-pod created
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
kubectl describe -f myapp.yaml
Name: myapp-pod
Namespace: default
[...]
Labels: app=myapp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
kubectl logs myapp-pod -c init-myservice # Memeriksa Init Container pertama
kubectl logs myapp-pod -c init-mydb # Memeriksa Init Container kedua
Saat kita menjalankan Service mydb
dan myservice
, kita dapat melihat Init Container telah selesai dan myapp-pod
pun dibuat:
kubectl apply -f services.yaml
service/myservice created
service/mydb created
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
Contoh ini sangat sederhana, tetapi dapat memberikan sedikit petunjuk bagi kamu untuk membuat Init Container sendiri.
Perilaku mendetail
Saat dimulainya sebuah Pod, Init Container dijalankan secara berurutan, setelah jaringan dan volume telah diinisialisasi. Setiap Init Container harus selesai dan keluar secara berhasil sebelum yang berikutnya dijalankan. Jika ada Init Container yang gagal dijalankan atau keluar secara gagal, dia akan diulang kembali sesuai dengan restartPolicy
yang dimiliki Pod. Tetapi, jika restartPolicy
Pod disetel dengan nilai Always
, Init Container akan menggunakan strategi RestartPolicy
OnFailure
.
Sebuah Pod tidak dapat masuk ke status Ready
hingga semua Init Container berhasil selesai. Port di sebuah Init Container tidak diagregasikan di dalam sebuah Service. Sebuah Pod yang sedang diinisalisasikan akan masuk ke dalam status Pending
, tetapi akan memiliki kondisi Initialized
yang disetel menjadi true
.
Jika sebuah Pod diulang kembali, semua Init Container harus dijalankan kembali.
Perubahan pada spesifikasi Init Container dibatasi hanya pada kolom image
pada Init Container. Mengganti kolom image
sebuah Init Container sama dengan mengulang kembali Pod tersebut.
Karena Init Container dapat diulang kembali, dicoba ulang, atau dijalankan ulang, Init Container sebaiknya bersifat idempotent. Khususnya, kode yang menulis ke dalam file pada EmptyDir
sebaiknya dipersiapkan untuk menangani kemungkinan jika file keluaran yang diharapkan sudah ada di dalam EmptyDir
tersebut.
Init Container memiliki semua kolom yang dimiliki oleh Container aplikasi. Tetapi, Kubernetes melarang penggunaan readinessProbe
karena Init Container tidak dapat mendefinisikan/menggunakan readiness probe setelah selesai/keluar secara berhasil. Hal ini dipaksakan saat proses validasi.
Gunakan activeDeadlineSeconds
pada Pod dan livenessProbe
pada Container untuk mencegah Init Container gagal terus menerus. Nilai activeDeadlineSeconds
berlaku juga terhadap Init Container.
Nama setiap Container aplikasi dan Init Container pada sebuah Pod haruslah unik; Kesalahan validasi akan terjadi jika ada Container atau Init Container yang memiliki nama yang sama.
Sumber Daya
Karena eksekusi Init Container yang berurutan, aturan-aturan untuk sumber daya berlaku sebagai berikut:
- Yang tertinggi antara
request
ataulimit
sumber daya yang didefinisikan pada semua Init Container adalahrequest
/limit
inisialisasi yang berlaku. request
/limit
sumber daya Pod yang berlaku adalah yang paling besar diantara:- Jumah
request
/limit
semua Container aplikasi untuk suatu sumber daya. request
/limit
inisialisasi yang berlaku untuk suatu sumber daya.
- Jumah
- Penjadwalan dilakukan berdasarkan
request
/limit
(Pod) yang berlaku, yang berarti bahwa Init Container dapat mengambil sumber daya inisialisasi yang tidak digunakan selama umur Pod tersebut. - Tingkat QoS yang berlaku milik Pod adalah sama dengan tingkat QoS untuk Init Container dan Container aplikasi.
ResourceQuota
dan limitedResources
diberlakukan berdasarkan request
dan limit
Pod yang berlaku.
Cgroup pada tingat Pod didasarkan pada request
dan limit
Pod yang berlaku, sama dengan scheduler.
Alasan Pod diulang kembali
Pod dapat diulang kembali, yang berakibat pada diulangnya eksekusi Init Container, diakibatkan oleh beberapa alasan berikut:
- Seorang pengguna memperbarui
PodSpec
, mengakibatkanimage
Init Container berubah. Perubahan apapun padaimage
Init Container akan mengulang kembali Pod tersebut. Perubahan padaimage
Container aplikasi hanya mengulang kembali Container aplikasi yang bersangkutan. - Infrastruktur Container Pod diulang kembali. Hal ini jarang terjadi, dan hanya dapat dilakukan oleh seseorang yang memiliki akses root pada node yang bersangkutan.
- Semua Container di dalam Pod diterminasi, dengan nilai
restartPolicy
yang disetel sebagaiAlways
, memaksa pengulangan kembali, dan catatan selesainya Init Container telah hilang karena garbage collection.
Dukungan dan kompatibilitas
Sebuah klaster dengan versi Apiserver 1.6.0 ke atas mendukung Init Container melalui kolom .spec.initContainers
. Versi-versi sebelumnya mendukung Init Container melalui anotasi alpha atau beta. Kolom .spec.initContainers
juga diduplikasikan dalam bentuk anotasi alpha dan beta agar Kubelet versi 1.3.0 ke atas dapat menjalankan Init Container, dan agar Apiserver versi 1.6 dapat dengan aman dikembalikan ke versi 1.5.x tanpa kehilangan fungsionalitas Pod-pod yang telah dibuat sebelumnya.
Pada Apiserver dan Kubelet versi 1.8.0 ke atas, dukungan untuk anotasi alpha dan beta telah dihapus, sehingga dibutuhkan konversi (manual) dari anotasi yang telah kedaluwarsa tersebut ke dalam bentuk kolom .spec.initContainers
.
Selanjutnya
5 - Batasan Persebaran Topologi Pod
Kubernetes v1.18 [beta]
Kamu dapat menggunakan batasan perseberan topologi (topology spread constraints) untuk mengatur bagaimana Pod akan disebarkan pada klaster yang ditetapkan sebagai failure-domains, seperti wilayah, zona, Node dan domain topologi yang ditentukan oleh pengguna. Ini akan membantu untuk mencapai ketersediaan yang tinggi dan juga penggunaan sumber daya yang efisien.
Persyaratan
Mengaktifkan Gerbang Fitur
Gerbang fitur (feature gate)
EvenPodsSpread
harus diaktifkan untuk
API Server dan
penjadwal (_scheduler_).
Label Node
Batasan persebaran topologi bergantung dengan label pada Node untuk menentukan
domain topologi yang memenuhi untuk semua Node. Misalnya saja, sebuah Node bisa memiliki
label sebagai berikut: node=node1,zone=us-east-1a,region=us-east-1
Misalkan kamu memiliki klaster dengan 4 Node dengan label sebagai berikut:
NAME STATUS ROLES AGE VERSION LABELS
node1 Ready <none> 4m26s v1.16.0 node=node1,zone=zoneA
node2 Ready <none> 3m58s v1.16.0 node=node2,zone=zoneA
node3 Ready <none> 3m17s v1.16.0 node=node3,zone=zoneB
node4 Ready <none> 2m43s v1.16.0 node=node4,zone=zoneB
Maka klaster tersebut secara logika akan dilihat sebagai berikut:
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
Tanpa harus memberi label secara manual, kamu dapat menggunakan [label ternama] (/docs/reference/kubernetes-api/labels-annotations-taints/) yang terbuat dan terkumpulkan secara otomatis pada kebanyakan klaster.
Batasan Persebaran untuk Pod
API
Field pod.spec.topologySpreadConstraints
diperkenalkan pada versi 1.16 sebagai berikut:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
topologySpreadConstraints:
- maxSkew: <integer>
minDomains: <integer>
topologyKey: <string>
whenUnsatisfiable: <string>
labelSelector: <object>
Kamu dapat mendefinisikan satu atau lebih topologySpreadConstraint
untuk menginstruksikan
kube-scheduler mengenai cara peletakan tiap Pod baru dengan menggunakan kondisi Pod yang
sudah ada dalam klaster kamu. Field yang ada adalah:
- maxSkew menentukan batasan yang menandakan Pod tidak tersebar secara merata. Ini merupakan nilai maksimal dari selisih jumlah Pod yang sama untuk setiap 2 domain topologi yang sama. Nilai ini harus lebih dari 0.
- topologyKey adalah kunci dari label Node. Jika terdapat dua Node memiliki label dengan kunci ini dan memiliki nilai yang identik untuk label tersebut, maka penjadwal akan menganggap kedua Noode dalam topologi yang sama. Penjadwal akan mencoba untuk menyeimbangkan jumlah Pod dalam setiap domain topologi.
- whenUnsatisfiable mengindikasikan cara menangani Pod yang tidak memenuhi batasan persebaran:
DoNotSchedule
(default) memberitahukan penjadwal untuk tidak menjadwalkan Pod tersebut.ScheduleAnyway
memberitahukan penjadwal untuk tetap menjadwalkan Pod namun tetap menjaga ketidakseimbangan Node sekecil mungkin.
- labelSelector digunakan untuk mencari Pod yang sesuai. Pod dengan label yang sama dengan ini akan dihitung untuk menentukan jumlah Pod dalam domain topologi yang sesuai. Silakan baca Label dan Selector untuk lebih detailnya.
Kamu juga bisa membaca lebih detail mengenai field ini dengan menjalankan perintah
kubectl explain Pod.spec.topologySpreadConstraints
.
Contoh: Satu TopologySpreadConstraint
Misalkan kamu memiliki klaster dengan 4 Node dimana 3 Pod berlabel foo:bar
terdapat pada node1,
node2 dan node3 (P
merepresentasikan Pod):
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
| P | P | P | |
+-------+-------+-------+-------+
Jika kita ingin Pod baru akan disebar secara merata berdasarkan Pod yang telah ada pada semua zona, maka spec bernilai sebagai berikut:
kind: Pod
apiVersion: v1
metadata:
name: mypod
labels:
foo: bar
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
containers:
- name: pause
image: k8s.gcr.io/pause:3.1
topologyKey: zone
berarti persebaran merata hanya akan digunakan pada Node dengan pasangan label
"zone: whenUnsatisfiable: DoNotSchedule
memberitahukan penjadwal untuk membiarkan
tetap ditunda jika Pod yang baru tidak memenuhi batasan yang diterapkan.
Jika penjadwal menempatkan Pod baru pada "zoneA", persebaran Pod akan menjadi [3, 1], menjadikan
ketidakseimbangan menjadi bernilai 2 (3 - 1), yang mana akan melanggar batasan maxSkew: 1
.
Dalam contoh ini, Pod baru hanya dapat ditempatkan pada "zoneB":
+---------------+---------------+ +---------------+---------------+
| zoneA | zoneB | | zoneA | zoneB |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
| node1 | node2 | node3 | node4 | OR | node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
| P | P | P | P | | P | P | P P | |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
Kamu dapat mengatur spesifikasi Pod untuk memenuhi beberapa persyaratan berikut:
- Ubah nilai
maxSkew
menjadi lebih besar, misal "2", sehingga Pod baru dapat ditempatkan pada "zoneA". - Ubah nilai
topologyKey
menjadi "node" agar Pod disebarkan secara merata pada semua Node, bukan zona. Pada contoh di atas, jikamaxSkew
tetap bernilai "1", maka Pod baru hanya akan ditempatkan pada "node4". - Ubah nilai
whenUnsatisfiable: DoNotSchedule
menjadiwhenUnsatisfiable: ScheduleAnyway
untuk menjamin agar semua Pod baru akan tetap dijadwalkan (misalkan saja API penjadwalan lain tetap terpenuhi). Namun, ini lebih suka ditempatkan pada domain topologi yang memiliki lebih sedikit Pod yang sesuai. (Harap diperhatikan bahwa preferensi ini digabungkan bersama dengan prioritas penjadwalan internal yang lain, seperti rasio penggunaan sumber daya, dan lain sebagainya.)
Contoh: Beberapa TopologySpreadConstraint
Ini dibuat berdasarkan contoh sebelumnya. Misalkan kamu memiliki klaster dengan 4 Node dengan
3 Pod berlabel foo:bar
yang ditempatkan pada node1, node2 dan node3. (P
merepresentasikan Pod):
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
| P | P | P | |
+-------+-------+-------+-------+
Kamu dapat menggunakan 2 TopologySpreadConstraint untuk mengatur persebaran Pod pada zona dan Node:
kind: Pod
apiVersion: v1
metadata:
name: mypod
labels:
foo: bar
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
- maxSkew: 1
topologyKey: node
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
containers:
- name: pause
image: k8s.gcr.io/pause:3.1
Dalam contoh ini, untuk memenuhi batasan pertama, Pod yang baru hanya akan ditempatkan pada "zoneB", sedangkan untuk batasan kedua, Pod yang baru hanya akan ditempatkan pada "node4". Maka hasil dari 2 batasan ini akan digunakan (AND), sehingga opsi untuk menempatkan Pod hanya pada "node4".
Beberapa batasan dapat berujung pada konflik. Misalnya saja kamu memiliki klaster dengan 3 Node pada 2 zona berbeda:
+---------------+-------+
| zoneA | zoneB |
+-------+-------+-------+
| node1 | node2 | node3 |
+-------+-------+-------+
| P P | P | P P |
+-------+-------+-------+
Jika kamu menerapkan "two-constraints.yaml" pada klaster ini, kamu akan mendapatkan "mypod" tetap
dalam kondisi Pending
. Ini dikarenakan oleh: untuk memenuhi batasan pertama, "mypod" hanya dapat
ditempatkan pada "zoneB", sedangkan untuk batasan kedua, "mypod" hanya dapat ditempatkan pada
"node2". Tidak ada hasil penggabungan dari "zoneB" dan "node2".
Untuk mengatasi situasi ini, kamu bisa menambahkan nilai maxSkew
atau mengubah salah satu dari
batasan untuk menggunakan whenUnsatisfiable: ScheduleAnyway
.
Konvensi
Ada beberapa konvensi implisit yang perlu diperhatikan di sini:
Hanya Pod dengan Namespace yang sama dengan Pod baru yang bisa menjadi kandidat yang cocok.
Node tanpa memiliki
topologySpreadConstraints[*].topologyKey
akan dilewatkan. Ini berarti:- Pod yang ditempatkan pada Node tersebut tidak berpengaruh pada perhitungan
maxSkew
. Dalam contoh di atas, misalkan "node1" tidak memiliki label "zone", maka kedua Pod tidak diperhitungkan dan menyebabkan Pod yang baru akan dijadwalkan masuk ke "zoneA". - Pod yang baru tidak memiliki kesempatan untuk dijadwalkan ke Node tersebut, pada contoh di atas, misalkan terdapat "node5" dengan label
{zone-typo: zoneC}
bergabung dalam klaster, Node ini akan dilewatkan karena tidak memiliki label dengan kunci "zone".
- Pod yang ditempatkan pada Node tersebut tidak berpengaruh pada perhitungan
Harap diperhatikan mengenai hal yang terjadi jika nilai
topologySpreadConstraints[*].labelSelector
pada Pod yang baru tidak sesuai dengan labelnya. Pada contoh di atas, jika kita menghapus label pada Pod yang baru, maka Pod akan tetap ditempatkan pada "zoneB" karena batasan yang ada masih terpenuhi. Namun, setelah ditempatkan, nilai ketidakseimbangan pada klaster masih tetap tidak berubah, zoneA tetap memiliki 2 Pod dengan label {foo:bar} dan zoneB memiliki 1 Pod dengan label {foo:bar}. Jadi jika ini tidak yang kamu harapkan, kami menyarankan nilai daritopologySpreadConstraints[*].labelSelector
disamakan dengan labelnya.Jika Pod yang baru memiliki
spec.nodeSelector
atauspec.affinity.nodeAffinity
, Node yang tidak sesuai dengan nilai tersebut akan dilewatkan.Misalkan kamu memiliki klaster dengan 5 Node dari zoneA sampai zoneC:
+---------------+---------------+-------+ | zoneA | zoneB | zoneC | +-------+-------+-------+-------+-------+ | node1 | node2 | node3 | node4 | node5 | +-------+-------+-------+-------+-------+ | P | P | P | | | +-------+-------+-------+-------+-------+
dan kamu mengetahui bahwa "zoneC" harus tidak diperhitungkan. Dalam kasus ini, kamu dapat membuat berkas yaml seperti di bawah, jadi "mypod" akan ditempatkan pada "zoneB", bukan "zoneC". Demikian juga
spec.nodeSelector
akan digunakan.kind: Pod apiVersion: v1 metadata: name: mypod labels: foo: bar spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: foo: bar affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: zone operator: NotIn values: - zoneC containers: - name: pause image: k8s.gcr.io/pause:3.1
Batasan default pada tingkat klaster
Kubernetes v1.18 [alpha]
Ini memungkinkan untuk mengatur batasan persebaran topologi bawaan untuk klaster. Batasan persebaran topologi bawaan akan digunakan pada Pod jika dan hanya jika:
- Hal ini tidak mendefinisikan batasan apapun pada
.spec.topologySpreadConstraints
. - Hal ini milik sebuah Service, ReplicationController, ReplicaSet atau StatefulSet.
Batasan bawaan akan diatur sebagai bagian dari argumen pada plugin PodTopologySpread
di dalam sebuah profil penjadwalan.
Batasan dispesifikasikan dengan API yang sama dengan di atas, kecuali bagian labelSelector
harus kosong. selector akan dihitung dari Service, ReplicationController, ReplicaSet atau
StatefulSet yang dimiliki oleh Pod tersebut.
Sebuah contoh konfigurasi sebagai berikut:
apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: PodTopologySpread
args:
defaultConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
DefaultPodTopologySpread
plugin.
Direkomendasikan untuk kamu menonaktifkan plugin ini dalam profil penjadwalan ketika
menggunakan batasan default untuk PodTopologySpread
.Perbandingan dengan PodAffinity/PodAntiAffinity
Di Kubernetes, arahan yang terkait dengan "Afinitas" mengontrol bagaimana Pod dijadwalkan - lebih terkumpul atau lebih tersebar.
- Untuk
PodAffinity
, kamu dapat mencoba mengumpulkan beberapa Pod ke dalam suatu domain topologi yang memenuhi syarat. - Untuk
PodAntiAffinity
, hanya satu Pod yang dalam dijadwalkan pada sebuah domain topologi.
Fitur "EvenPodsSpread" memberikan opsi fleksibilas untuk mendistribusikan Pod secara merata pada domain topologi yang berbeda, untuk meraih ketersediaan yang tinggi atau menghemat biaya. Ini juga dapat membantu saat perbaruan bergilir dan menaikan jumlah replika dengan lancar. Silakan baca motivasi untuk lebih detail.
Limitasi yang diketahui
Pada versi 1.18, dimana fitur ini masih Beta, beberapa limitasi yang sudah diketahui:
- Pengurangan jumlah Deployment akan membuat ketidakseimbangan pada persebaran Pod.
- Pod yang cocok pada tainted Node akan dihargai. Lihat Issue 80921
6 - Pod Preset
Halaman ini menyajikan gambaran umum tentang PodPreset, yang merupakan objek untuk memasukkan informasi tertentu ke dalam Pod pada saat waktu penciptaan. Informasi dapat berupa secret, volume, volume mount, dan variabel environment.
Memahami Pod Preset
Sebuah Pod Preset
adalah sebuah resource API untuk memasukkan kebutuhan runtime tambahan ke dalam sebuah Pod pada saat waktu penciptaan. Kamu akan menggunakan label selector untuk menunjuk Pod dimana Pod Preset diterapkan.
Menggunakan sebuah Pod Preset memungkinkan pembuat templat pod untuk tidak menyediakan secara eksplisit semua informasi untuk setiap pod. Dengan demikian, pembuat templat pod yang mengkonsumsi sebuah service spesifik tidak perlu tahu semua detail-detail tentang service tersebut.
Untuk informasi lebih lanjut mengenai latar belakang lihat proposal desain untuk PodPreset.
Bagaimana Cara Kerja Pod Preset
Kubernetes menyediakan sebuah admission controller (PodPreset
) dimana, ketika diaktifkan, PodPreset diterapkan kepada permintaan penciptaan Pod yang akan datang. Ketika sebuah penciptaan Pod terjadi, sistem melakukan hal-hal berikut:
- Mengambil semua
PodPreset
yang tersedia untuk digunakan. - Cek jika label selector dari salah satu
PodPreset
cocok dengan label pada pod yang sedang diciptakan. - Usaha untuk menggabungkan berbagai resource didefinisikan oleh
PodPreset
ke dalam Pod yang sedang diciptakan. - Ketika terjadi galat, lempar sebuah event yang mendokumentasikan galat penggabungan dalam pod, dan membuat pod tanpa salah satu resource dari
PodPreset
. - Anotasikan hasil spesifikasi Pod yang telah dimodifikasi untuk menunjukkan bahwa Pod telah dimodifikasi oleh sebuah PodPreset. Anotasi berupa
podpreset.admission.kubernetes.io/podpreset-<nama pod-preset>: "<versi resource>"
.
Tiap Pod akan bisa dipasangkan oleh nol atau lebih PodPreset; dan tiap PodPreset bisa diterapkan ke nol atau lebih Pod. Ketika sebuah PodPreset diterapkan ke satu atau lebih Pod, Kubernetes memodifikasi Pod Spec. Untuk perubahan terhadap Env
,EnvFrom
, dan VolumeMount
, Kubernetes memodifikasi spesifikasi kontainer untuk semua kontainer di dalam Pod; Untuk perubahan terhadap Volume
, Kubernetes memodifikasi Pod Spec.
.spec.containers
pada sebuah Pod Spec jika sesuai. Tidak ada definisi resource dari Pod Preset yang akan diterapkan kepada kolom initContainer
.Menonaktifkan Pod Preset untuk sebuah Pod Spesifik
Mungkin akan ada keadaan dimana kamu menginginkan sebuah Pod tidak bisa diubah oleh sebuah mutasi PodPreset. Pada kasus ini, kamu bisa menambahkan sebuah anotasi pada Pod Spec dalam bentuk: podpreset.admission.kubernetes.io/exclude: "true"
.
Mengaktifkan Pod Preset
Dalam rangka untuk menggunakan Pod Preset di dalam klaster kamu, kamu harus memastikan hal berikut:
Kamu telah mengaktifkan tipe API
settings.k8s.io/v1alpha1/podpreset
. Sebagai contoh, ini bisa dilakukan dengan menambahkansettings.k8s.io/v1alpha1=true
di dalam opsi--runtime-config
untuk API server. Dalam minikube tambahkan argumen berikut--extra-config=apiserver.runtime-config=settings.k8s.io/v1alpha1=true
saat menginisialisasi klaster.Kamu telah mengaktifkan admission controller dari
PodPreset
. Salah satu cara untuk melakukannya adalah dengan menambahkanPodPreset
di dalam nilai opsi--enable-admission-plugins
yang dispesifikasikan untuk API server. Dalam minikube tambahkan argumen berikut--extra-config=apiserver.enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodPreset
saat menginisialisasi klaster.
Kamu telah membuat objek
PodPreset
pada namespace yang kamu gunakan dengan cara mendefinisikan Pod Preset.
Selanjutnya
7 - Disrupsi
Petunjuk ini ditujukan pada pemilik aplikasi yang meninginkan aplikasinya memiliki ketersediaan yang tinggi, sehingga butuh untuk mengerti jenis-jenis Disrupsi yang dapat terjadi pada Pod-pod.
Petunjuk ini juga ditujukan pada administrator klaster yang ingin melakukan berbagai tindakan otomasi pada klaster, seperti pembaruan dan autoscaling klaster.
Disrupsi yang Disengaja dan Tidak Disengaja
Pod-pod tidak akan terhapus sampai sesuatu (orang ataupun pengendali) menghancurkan mereka atau ada kesalahan perangkat keras maupun perangkat lunak yang tidak dapat dihindari.
Kita menyebut kasus-kasus yang tidak dapat dihindari sebagai disrupsi yang tidak disengaja terhadap aplikasi. Beberapa contohnya adalah sebagai berikut:
- Kesalahan perangkat keras pada mesin yang menjalankan Node
- Administrator klaster menghapus virtual machine secara tidak sengaja
- Kesalahan pada penyedia layanan cloud yang mengakibatkan terhapusnya virtual machine
- Sebuah kernel panic
- Node menghilang dari klaster karena partisi jaringan klaster
- Pod mengalami eviction karena Node kehabisan sumber daya
Dengan pengecualian pada kondisi kehabisan sumber daya, kondisi-kondisi tersebut pada umumnya diketahui oleh kebanyakan pengguna karena kondisi-kondisi tersebut tidak spesifik pada Kubernetes saja.
Kita menyebut kasus-kasus lainnya sebagai disrupsi yang disengaja. Hal ini termasuk tindakan yang dilakukan oleh pemilik aplikasi atau yang dilakukan oleh administrator klaster. Pemilik aplikasi umumnya melakukan hal-hal berikut:
- Menghapus Deployment atau pengendali yang mengatur Pod
- Memperbarui templat Pod yang menyebabkan pengulangan kembali/restart
- Menghapus Pod secara langsung
Administrator klaster umumnya melakukan hal-hal berikut:
- Melakukan drain terhadap Node untuk perbaikan atau pembaruan.
- Melakukan drain terhadap sebuah node dari klaster untuk memperkecil ukuran klaster (untuk lebih lanjutnya, pelajari Autoscaling klaster).
- Menghapus sebuah Pod dari node untuk memuat Pod lain ke node tersebut.
Tindakan-tindakan tersebut dapat dilakukan secara langsung oleh administrator klaster, atau oleh alat otomasi yang dijalankan oleh administrator klaster, atau oleh penyedia layanan Kubernetes kamu.
Tanyakan administrator klaster atau penyedia layanan cloud kamu, atau lihatlah dokumentasi penyedia layanan Kubernetes kamu untuk mengetahui bila ada sumber-sumber yang berpotensi mengakibatkan disrupsi yang disengaja yang ada pada klastermu. Jika tidak ada, kamu bisa melewatkan pembuatan PodDisruptionBudget
Mengatasi Disrupsi
Berikut beberapa cara untuk mengatasi disrupsi yang tidak disengaja:
- Pastikan Pod-pod kamu merinci permintaan sumber daya klaster yang dibutuhkan.
- Replikasikan aplikasimu jika membutuhkan ketersediaan yang tinggi. (Pelajari tentang menjalankan aplikasi stateless dan stateful).
- Untuk mencapai ketersediaan yang bahkan lebih tinggi lagi saat mereplikasikan aplikasi, sebarkanlah Pod-pod kamu di rak-rak pada data center (menggunakan anti-affinity) atau di seluruh zona (jika kamu menggunakan klaster pada beberapa zona).
Frekuensi disrupsi yang disengaja dapat berubah-ubah. Pada klaster Kubernetes yang dasar, tidak ada disrupsi yang disengaja sama sekali. Tetapi, administrator klaster atau penyedia layanan Kubernetes kamu mungkin saja menjalankan beberapa servis tambahan yang dapat mengakibatkan disrupsi yang disengaja. Misalnya, memperbarui perangkat lunak pada node yang dapat mengakibatkan disrupsi yang disengaja. Selain itu, beberapa implementasi autoscaling klaster (atau node) dapat mengakibatkan disrupsi yang disengaja untuk merapikan dan memadatkan node-node pada klaster. Administrator klaster atau penyedia layanan Kubernetes kamu perlu mendokumentasikan tingkatan disrupsi yang disengaja, jika ada disrupsi yang telah diperkirakan.
Kubernetes menawarkan fitur-fitur untuk membantu menjalankan aplikasi-aplikasi dengan ketersediaan tinggi bersamaan dengan seringnya disrupsi yang disengaja, fitur-fitur tersebut dinamai Disruption Budget.
Bagaimana cara kerja Disruption Budget
Pemilik aplikasi dapat membuat objek PodDisruptionBudget
(PDB) untuk setiap aplikasi. Sebuah PDB membatasi jumlah Pod yang boleh mati secara bersamaan pada aplikasi yang direplikasi dikarenakan disrupsi yang disengaja.
Misalnya, sebuah aplikasi yang bekerja secara quorum mau memastikan bahwa jumlah replika yang berjalan tidak jatuh ke bawah yang dibutuhkan untuk membentuk sebuah quorum. Contoh lainnya, sebuah front-end web mungkin perlu memastikan bahwa jumlah replika yang melayani trafik tidak pernah turun ke total persentase yang telah ditentukan.
Administrator klaster dan penyedia layanan Kubernetes sebaiknya menggunakan alat-alat yang menghormati PDB dengan cara berkomunikasi dengan Eviction API dari pada menghapus Pod atau Deployment secara langsung. Contohnya adalah perintah kubectl drain
dan skrip pembaruan Kubernetes-on-GCE (cluster/gce/upgrade.sh
)
Saat seorang administrator klaster ingin melakukan drain terhadap sebuah node, ia akan menggunakan perintah kubectl drain
. Alat tersebut mencoba untuk "mengusir" semua Pod di node tersebut. Permintaan untuk mengusir Pod tersebut mungkin ditolak untuk sementara, dan alat tersebut akan mencoba ulang permintaannya secara periodik hingga semua Pod dihapus, atau hingga batas waktu yang ditentukan telah dicapai.
Sebua PDB merinci jumlah replika yang dapat ditoleransi oleh sebuah aplikasi, relatif terhadap berapa banyak yang seharusnya dimiliki oleh aplikasi tersebut. Sebagai contoh, sebuah Deployment yang memiliki rincian .spec.replicas :5
diharapkan memiliki 5 Pod pada satu waktu. Jika PDB aplikasi tersebut mengizinkan ada 4 replika pada satu waktu, maka Eviction API akan mengizinkan disrupsi yag disengaja sebanyak satu, tapi tidak mengizinkan dua, pada satu waktu.
Sebuah kelompok Pod yang mewakili aplikasi dispesifikasikan menggunakan sebuah label selector yang sama dengan yang digunakan oleh pengatur aplikasi tersebut (Deployment, StatefulSet, dsb.)
Jumlah Pod yang "diharapkan" dihitung dari .spec.replicas
dari pengendali Pod tersebut. Pengendali dari sebuah Pod dapat ditemukan di spesifikasi .metadata.ownerReferences
objek Pod yang bersangkutan.
PDB tidak dapat mencegah disrupsi yang tidak disengaja, tapi disrupsi ini akan dihitung terhadap bujet PDB.
Pod yang dihapus atau tidak tersetia dikarenakan pembaruan bertahap juga dihitung terhadap bujet PDB, tetapi pengendali (seperti Deployment dan StatefulSet) tidak dibatasi oleh PDB ketika melakukan pembaruan bertahap; Penanganan kerusakan saat pembaruan aplikasi dikonfigurasikan pada spesifikasi pengendali. (Pelajari tentang memperbarui sebuah Deployment.)
Saat sebuah Pod diusir menggunakan eviction API, Pod tersebut akan dihapus secara graceful (lihat terminationGracePeriodSeconds
pada PodSpec.))
Contoh PDB
Kita ambil contoh sebuah klaster dengan 3 node, node-1
hingga node-3
.
Klaster tersebut menjalankan beberapa aplikasi. Salah satu dari aplikasi tersebut awalnya memiliki 3 replika, yang akan kita namai Pod-a
, Pod-b
, dan Pod-c
. Sebuah Pod lain yang tidak bersangkutan dan tidak memiliki PDB, dinamai Pod-x
juga terlihat. Awalnya, Pod-pod tersebut berada pada node-node sebagai berikut:
node-1 | node-2 | node-3 |
---|---|---|
Pod-a available | Pod-b available | Pod-c available |
Pod-x available |
3 Pod Pod-a
hingga Pod-c
adalah bagian dari sebuah Deployment, dan mereka secara kolektif memiliki sebuah PDB yang mengharuskan ada setidaknya 2 dari 3 Pod untuk tersedia sepanjang waktu.
Sebagai contoh, asumsikan administrator klaster ingin me-reboot ke dalam versi kernel baru untuk memperbaiki kesalahan di dalam kernel lama. Administator klaster pertama-tama mencoba untuk melakukan drain terhadap node-1
menggunakan perintah kubectl drain
. Perintah tersebut mencoba untuk mengusir Pod-a
dan Pod-x
. Hal ini langsung berhasil. Kedua Pod tersebut masuk ke dalam kondisi terminating
secara bersamaan. Hal ini mengubah kondisi klaster menjadi sebagai berikut:
node-1 draining | node-2 | node-3 |
---|---|---|
Pod-a terminating | Pod-b available | Pod-c available |
Pod-x terminating |
Deployment tersebut melihat bahwa salah satu Pod berada dalam kondisi terminating
, sehingga Deployment mencoba untuk membuat penggantinya, Pod-d
. Sejak node-1
ditutup (karena perintah kubectl-drain
), Pod-d
masuk ke node lainnya. Sesuatu juga membuat Pod-y
sebagai pengganti Pod-x
(Catatan: untuk sebuah StatefulSet, Pod-a
, akan dinamai dengan Pod-1
, harus diterminasi hingga selesai sebelum penggantinya, yang juga dinamai Pod-1
tetapi memiliki UID yang berbeda, akan dibuat. Selain hal ini, seluruh contoh ini juga berlaku untuk StatefulSet.)
Sekarang, klaster berada pada kondisi berikut:
node-1 draining | node-2 | node-3 |
---|---|---|
Pod-a terminating | Pod-b available | Pod-c available |
Pod-x terminating | Pod-d starting | Pod-y |
Pada satu waktu, Pod-pod yang diusir pun selesai diterminasi, dan kondisi klaster menjadi seperti berikut:
node-1 drained | node-2 | node-3 |
---|---|---|
Pod-b available | Pod-c available | |
Pod-d starting | Pod-y |
Pada titik ini, jika seorang administrator klaster yang tidak sabar mencoba untuk melakukan drain terhadap node-2
atau node-3
, perintah untuk melakukan drain terhadap node tersebut akan terhalang, karena hanya ada 2 Pod yang tersedia, dan PDB-nya membutuhkan setidaknya ada 2 Pod tersedia. Setelah beberapa waktu, Pod-d
menjadi tersedia.
Kondisi klaster menjadi seperti berikut:
node-1 drained | node-2 | node-3 |
---|---|---|
Pod-b available | Pod-c available | |
Pod-d available | Pod-y |
Sekarang, administrator klaster mencoba untuk melakukan drain terhadap node-2
. Perintah drain tersebut akan mencoba mengusir Pod-pod tersebut secara berurutan (tidak bersamaan), misalnya Pod-b
yang pertama dan diikuti dengan Pod-d
. Perintah tersebut akan berhasil mengusir Pod-b
. Tetapi, pada saat ia mencoba untuk mengusir Pod-d
, hal tersebut akan ditolak karena hal tersebut akan mengakibatkan hanya satu Pod yang tersedia untuk Deployment yang bersangkutan.
Deployment tersebut membuat pengganti Pod-b
yang dinamai Pod-e
.
Karena tidak ada sumber daya klaster yang cukup untuk mengalokasikan Pod-e
, proses drain akan kembali terhalang.
Klaster mungkin berada pada kondisi berikut:
node-1 drained | node-2 | node-3 | no node |
---|---|---|---|
Pod-b available | Pod-c available | Pod-e pending | |
Pod-d available | Pod-y |
Pada titik ini, administrator klaster mesti menambah sebuah node untuk klaster agar bisa melanjutkan pembaruan klaster.
Kamu dapat melihat bagaimana frekuensi disrupsi dapat berubah-ubah pada Kubernetes, tergantung pada:
- Berapa banyak replika yang dibutuhkan sebuah aplikasi
- Berapa lama waktu yang dibutuhkan untuk mematikan sebuah Pod secara graceful
- Berapa lama waktu yang dibutuhkan untuk memulai sebuah Pod
- Tipe pengendali
- Kapasitas sumber daya klaster
Memisahkan Peran Pemilik Klaster dan Pemilik Aplikasi
Seringkali akan bermanfaat untuk berpikir Administrator Klaster dan Pemilik Aplikasi sebagai peran yang terpisah dan dengan pengetahuan yang terbatas satu sama lainnya. Pemisahan ini dapat dimengerti dalam beberapa skenario berikut:
- Saat ada banyak tim aplikasi yang berbagi pakai sebuah klaster Kubernetes, dan ada pembagian peran yang spesifik
- Saat alat atau servis pihak ketiga digunakan untuk melakukan otomasi manajemen klaster.
PDB mendukung pemisahan peran ini dengan cara menyediakan antarmuka bagi peran-peran tersebut.
Jika kamu tidak memiliki pemisahan peran seperti ini pada organisasimu, kamu mungkin tidak membutuhkan PDB.
Bagaimana cara melakukan Tindakan Disruptif terhadap Klaster
Jika kamu adalah Administrator Klaster, maka kamu mesti melakukan tindakan disruptif pada setiap node di klastermu, seperti melakukan pembaruan perangkat lunak pada node, berikut beberapa opsinya:
- Menerima downtime pada saat pembaruan node
- Melakukan failover ke replika lengkap klaster lain.
- Tanpa downtime, tetapi mungkin lebih mahal, baik ongkos duplikasi node-node dan tenaga yang dibutuhkan untuk melakukan failover.
- Membuat aplikasi yang toleran terhadap disrupsi, dan gunakan PDB.
- Tanpa downtime.
- Duplikasi sumber daya yang minimal.
- Mengizinkan lebih banyak otomasi administrasi klaster.
- Membuat aplikasi yang toleran terhadap disrupsi agak rumit, tetapi usaha yang dilakukan untuk menoleransi disrupsi yang disengaja kebanyakan beririsan dengan usaha untuk mendukung autoscaling dan menoleransi disrupsi yang tidak disengaja.
Selanjutnya
Ikuti langkah-langkah untuk melindungi aplikasimu dengan membuat sebuah PodDisruptionBudget.
Pelajari lebih lanjut mengenai melakukan drain terhadap node.
8 - Kontainer Sementara (Ephemeral)
Kubernetes v1.16 [alpha]
Halaman ini memberikan gambaran umum tentang kontainer sementara: satu jenis kontainer khusus yang berjalan sementara pada Pod yang sudah ada untuk melakukan tindakan yang diinisiasi oleh pengguna seperti dalam pemecahan masalah. Kamu menggunakan kontainer sementara untuk memeriksa layanan bukan untuk membangun aplikasi.
Memahami Kontainer Sementara
Pod adalah blok pembangun fundamental dalam aplikasi Kubernetes. Karena Pod diharapkan digunakan hanya sekali dan dapat diganti, sehingga kamu tidak dapat menambahkan kontainer ke dalam Pod setelah Pod tersebut dibuat. Sebaliknya, kamu biasanya menghapus dan mengganti beberapa Pod dengan cara yang terkontrol melalui Deployment.
Namun, kadang-kadang perlu juga untuk memeriksa keadaan Pod yang telah ada, sebagai contoh untuk memecahkan masalah bug yang sulit direproduksi. Dalam kasus ini, kamu dapat menjalankan sebuah kontainer sementara di dalam suatu Pod yang sudah ada untuk memeriksa statusnya dan menjalankannya segala macam perintah.
Apa itu Kontainer Sementara?
Kontainer sementara berbeda dengan kontainer lainnya karena tidak memiliki jaminan sumber daya maupun akan eksekusi, dan mereka tidak akan pernah secara otomatis melakukan restart, jadi mereka tidak sesuai untuk membangun aplikasi. Kontainer sementara dideskripsikan dengan menggunakan ContainerSpec yang sama dengan kontainer biasa, tetapi banyak bagian yang tidak kompatibel dan tidak diperbolehkan untuk kontainer sementara.
- Kontainer sementara mungkin tidak memiliki port, sehingga bagian seperti
port
,livenessProbe
,readinessProbe
tidak diperbolehkan. - Alokasi sumber daya untuk Pod tidak dapat diubah, sehingga pengaturan sumber daya tidak diperbolehkan.
- Untuk daftar lengkap bagian yang diperbolehkan, dapat di lihat referensi dokumentasi Kontainer Sementara.
Kontainer sementara dibuat dengan menggunakan handler khusus
EphemeralContainers dalam API tanpa menambahkannya langsung ke pod.spec
,
sehingga tidak memungkinan untuk menambahkan kontainer sementara dengan
menggunakan kubectl edit
.
Seperti dengan kontainer biasa, kamu tidak dapat mengubah atau menghapus kontainer sementara setelah kamu memasukkannya ke dalam sebuah Pod.
Penggunaan Kontainer Sementara
Kontainer sementara berguna untuk pemecahan masalah secara interaktif pada saat
kubectl exec
tidak mencukupi karena sebuah kontainer telah hancur atau
kontainer image tidak memiliki utilitas untuk debugging.
Khususnya, untuk images_distroless
memungkinkan kamu untuk menyebarkan kontainer image minimal yang mengurangi
surface attack dan paparan bug dan vulnerability. Karena
image distroless tidak mempunyai sebuah shell atau utilitas debugging apa
pun, sehingga sulit untuk memecahkan masalah image distroless dengan
menggunakan kubectl exec
saja.
Saat menggunakan kontainer sementara, akan sangat membantu untuk mengaktifkan process namespace sharing sehingga kamu dapat melihat proses pada kontainer lain.
Contoh
EphemeralContainers
feature
gate untuk
diaktifkan, dan membutuhkan Kubernetes klien dan server versi v1.16 atau
yang lebih baru.Contoh-contoh pada bagian ini menunjukkan bagaimana kontainer sementara muncul
dalam API. Kamu biasanya dapat menggunakan plugin kubectl
untuk mengatasi
masalah untuk mengotomatiskan langkah-langkah ini.
Kontainer sementara dibuat menggunakan subresource ephemeralcontainers
Pod, yang dapat didemonstrasikan menggunakan kubectl --raw
. Pertama-tama
deskripsikan kontainer sementara untuk ditambahkan dalam daftar
EphemeralContainers
:
{
"apiVersion": "v1",
"kind": "EphemeralContainers",
"metadata": {
"name": "example-pod"
},
"ephemeralContainers": [{
"command": [
"sh"
],
"image": "busybox",
"imagePullPolicy": "IfNotPresent",
"name": "debugger",
"stdin": true,
"tty": true,
"terminationMessagePolicy": "File"
}]
}
Untuk memperbarui kontainer yang sudah berjalan dalam example-pod
:
kubectl replace --raw /api/v1/namespaces/default/pods/example-pod/ephemeralcontainers -f ec.json
Ini akan menampilkan daftar baru dari seluruh kontainer sementara:
{
"kind":"EphemeralContainers",
"apiVersion":"v1",
"metadata":{
"name":"example-pod",
"namespace":"default",
"selfLink":"/api/v1/namespaces/default/pods/example-pod/ephemeralcontainers",
"uid":"a14a6d9b-62f2-4119-9d8e-e2ed6bc3a47c",
"resourceVersion":"15886",
"creationTimestamp":"2019-08-29T06:41:42Z"
},
"ephemeralContainers":[
{
"name":"debugger",
"image":"busybox",
"command":[
"sh"
],
"resources":{
},
"terminationMessagePolicy":"File",
"imagePullPolicy":"IfNotPresent",
"stdin":true,
"tty":true
}
]
}
Kamu dapat melihat kondisi kontainer sementara yang baru dibuat dengan
menggunakan kubectl describe
:
kubectl describe pod example-pod
...
Ephemeral Containers:
debugger:
Container ID: docker://cf81908f149e7e9213d3c3644eda55c72efaff67652a2685c1146f0ce151e80f
Image: busybox
Image ID: docker-pullable://busybox@sha256:9f1003c480699be56815db0f8146ad2e22efea85129b5b5983d0e0fb52d9ab70
Port: <none>
Host Port: <none>
Command:
sh
State: Running
Started: Thu, 29 Aug 2019 06:42:21 +0000
Ready: False
Restart Count: 0
Environment: <none>
Mounts: <none>
...
Kamu dapat mengakses kontainer sementara yang baru menggunakan
kubectl attach
:
kubectl attach -it example-pod -c debugger
Jika proses berbagi namespace diaktifkan, kamu dapat melihat proses dari semua
kontainer dalam Pod tersebut. Misalnya, setelah mengakses, kamu jalankan
ps
di kontainer debugger:
# Jalankan ini pada _shell_ dalam _debugger_ dari kontainer sementara
ps auxww
Hasilnya akan seperti ini:
PID USER TIME COMMAND
1 root 0:00 /pause
6 root 0:00 nginx: master process nginx -g daemon off;
11 101 0:00 nginx: worker process
12 101 0:00 nginx: worker process
13 101 0:00 nginx: worker process
14 101 0:00 nginx: worker process
15 101 0:00 nginx: worker process
16 101 0:00 nginx: worker process
17 101 0:00 nginx: worker process
18 101 0:00 nginx: worker process
19 root 0:00 /pause
24 root 0:00 sh
29 root 0:00 ps auxww