This is the multi-page printable view of this section. Click here to print.
Workloads
- 1: Pods
- 1.1: Pengenalan Pod
- 1.2: Pod
- 1.3: Siklus Hidup Pod
- 1.4: Init Container
- 1.5: Batasan Persebaran Topologi Pod
- 1.6: Pod Preset
- 1.7: Disrupsi
- 1.8: Kontainer Sementara (Ephemeral)
- 2: Controllers
- 2.1: ReplicaSet
- 2.2: ReplicationController
- 2.3: Deployment
- 2.4: StatefulSet
- 2.5: DaemonSet
- 2.6: Garbage Collection
- 2.7: Pengendali TTL untuk Sumber Daya yang Telah Selesai Digunakan
- 2.8: Jobs
- 2.9: CronJob
1 - Pods
1.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:
1.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.
1.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.
1.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
1.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
1.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
1.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.
1.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
2 - Controllers
2.1 - ReplicaSet
Tujuan dari ReplicaSet adalah untuk memelihara himpunan stabil dari replika Pod yang sedang berjalan pada satu waktu tertentu. Maka dari itu, ReplicaSet seringkali digunakan untuk menjamin ketersediaan dari beberapa Pod identik dalam jumlah tertentu.
Cara kerja ReplicaSet
Sebuah ReplicaSet didefinisikan dengan beberapa field termasuk selektor yang menentukan bagaimana mengidentifikasi Pod yang dapat diakuisisi, jumlah replika yang mengindikasi berapa jumlah Pod yang harus dikelola, dan sebuah templat pod yang menentukan data dari berbagai Pod baru yang harus dibuat untuk memenuhi kriteria jumlah replika. Sebuah ReplicaSet selanjutnya akan memenuhi tujuannya dengan membuat dan menghapus Pod sesuai dengan kebutuhan untuk mencapai jumlah yang diinginkan. Ketika ReplicaSet butuh untuk membuat Pod baru, templat Pod akan digunakan.
Tautan dari sebuah ReplicaSet terhadap Pod yang dimiliki adalah melalui field metadata.ownerReferences pada Pod, yang menentukan sumber daya yang dimiliki oleh objek saat ini. Semua Pod yang diakuisisi oleh sebuah ReplicaSet masing-masing memiliki informasi yang mengidentifikasi ReplicaSet dalam field ownerReferences. Melalui tautan ini ReplicaSet dapat mengetahui keadaan dari Pod yang sedang dikelola dan melakukan perencanaan yang sesuai.
Sebuah ReplicaSet mengidentifikasi Pod baru untuk diakuisisi menggunakan selektornya. Jika terdapat sebuah Pod yang tidak memiliki OwnerReference atau OwnerReference yang dimiliki bukanlah sebuah Controller dan sesuai dengan selektor dari ReplicaSet, maka Pod akan langsung diakuisisi oleh ReplicaSet tersebut.
Kapan menggunakan ReplicaSet
Sebuah ReplicaSet memastikan replika-replika pod dalam jumlah yang ditentukan berjalan pada satu waktu tertentu. Namun demikian, sebuah Deployment adalah konsep dengan tingkatan yang lebih tinggi yang mengatur ReplicaSet dan mengubah Pod secara deklaratif serta berbagai fitur bermanfaat lainnya. Maka dari itu, kami merekomendasikan untuk menggunakan Deployment alih-alih menggunakan ReplicaSet secara langsung, kecuali jika kamu membutuhkan orkestrasi pembaruan yang khusus atau tidak membutuhkan pembaruan sama sekali.
Hal ini berarti kamu boleh jadi tidak akan membutuhkan manipulasi objek ReplicaSet: Gunakan Deployment dan definisikan aplikasi kamu pada bagian spec.
Contoh
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
Menyimpan manifest ini dalam frontend.yaml
dan mengirimkannya ke klaster Kubernetes akan membuat ReplicaSet yang telah didefinisikan beserta dengan Pod yang dikelola.
kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
Selanjutnya kamu bisa mendapatkan ReplicaSet yang sedang di-deploy:
kubectl get rs
Dan melihat frontend yang telah dibuat:
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 6s
Kamu juga dapat memeriksa kondisi dari ReplicaSet:
kubectl describe rs/frontend
Dan kamu akan melihat keluaran yang serupa dengan:
Name: frontend
Namespace: default
Selector: tier=frontend,tier in (frontend)
Labels: app=guestbook
tier=frontend
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=guestbook
tier=frontend
Containers:
php-redis:
Image: gcr.io/google_samples/gb-frontend:v3
Port: 80/TCP
Requests:
cpu: 100m
memory: 100Mi
Environment:
GET_HOSTS_FROM: dns
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-qhloh
1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-dnjpy
1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-9si5l
Terakhir, kamu dapat memeriksa Pod yang dibawa:
kubectl get Pods
Kamu akan melihat informasi Pod yang serupa dengan:
NAME READY STATUS RESTARTS AGE
frontend-9si5l 1/1 Running 0 1m
frontend-dnjpy 1/1 Running 0 1m
frontend-qhloh 1/1 Running 0 1m
Kamu juga dapat memastikan bahwa referensi pemilik dari pod-pod ini telah disesuaikan terhadap ReplicaSet frontend. Untuk melakukannya, yaml dari Pod yang sedang berjalan bisa didapatkan dengan:
kubectl get pods frontend-9si5l -o yaml
Keluarannya akan terlihat serupa dengan contoh berikut ini, dengan informasi ReplicaSet frontend yang ditentukan pada field ownerReferences pada bagian metadata:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: 2019-01-31T17:20:41Z
generateName: frontend-
labels:
tier: frontend
name: frontend-9si5l
namespace: default
ownerReferences:
- apiVersion: extensions/v1beta1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: frontend
uid: 892a2330-257c-11e9-aecd-025000000001
...
Akuisisi Pod Non-Templat
Walaupun kamu bisa membuat Pod biasa tanpa masalah, sangat direkomendasikan untuk memastikan Pod tersebut tidak memiliki label yang sama dengan selektor dari salah satu ReplicaSet yang kamu miliki. Hal in disebabkan sebuah ReplicaSet tidak dibatasi untuk memilki Pod sesuai dengan templatnya -- ReplicaSet dapat mengakuisisi Pod lain dengan cara yang telah dijelaskan pada bagian sebelumnya.
Mengambil contoh ReplicaSet frontend sebelumnya, dan Pod yang ditentukan pada manifest berikut:
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
tier: frontend
spec:
containers:
- name: hello1
image: gcr.io/google-samples/hello-app:2.0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
labels:
tier: frontend
spec:
containers:
- name: hello2
image: gcr.io/google-samples/hello-app:1.0
Karena Pod tersebut tidak memiliki Controller (atau objek lain) sebagai referensi pemilik yang sesuai dengan selektor dari ReplicaSet frontend, Pod tersebut akan langsung diakuisisi oleh ReplicaSet.
Misalkan kamu membuat Pod tersebut setelah ReplicaSet frontend telah di-deploy dan telah mengkonfigurasi replika Pod awal untuk memenuhi kebutuhan jumlah replika:
kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml
Pod baru akan diakuisisi oleh ReplicaSet, dan setelah itu langsung diterminasi ketika ReplicaSet melebihi jumlah yang diinginkan.
Memperoleh Pod:
kubectl get Pods
Keluaran menunjukkan bahwa Pod baru dalam keaadan telah diterminasi, atau sedang dalam proses terminasi:
NAME READY STATUS RESTARTS AGE
frontend-9si5l 1/1 Running 0 1m
frontend-dnjpy 1/1 Running 0 1m
frontend-qhloh 1/1 Running 0 1m
pod2 0/1 Terminating 0 4s
Jika kamu membuat Pod terlebih dahulu:
kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml
Dan selanjutnya membuat ReplicaSet maka:
kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
Kamu akan melihat bahwa ReplicaSet telah mengakuisisi Pod dan hanya membuat Pod yang baru sesuai dengan spec
yang ditentukan hingga jumlah dari Pod yang baru dan yang orisinil sesuai dengan jumlah yang diinginkan. Dengan memperoleh Pod:
kubectl get Pods
Akan diperlihatkan pada keluarannya:
NAME READY STATUS RESTARTS AGE
frontend-pxj4r 1/1 Running 0 5s
pod1 1/1 Running 0 13s
pod2 1/1 Running 0 13s
Dengan cara ini, sebuah ReplicaSet dapat memiliki himpunan berbagai Pod yang tidak homogen.
Menulis manifest ReplicaSet
Seperti objek API Kubernetes lainnya, sebuah ReplicaSet membutuhkan field apiVersion
, kind
, dan metadata
. Untuk ReplicaSet, nilai dari kind
yang memungkinkan hanyalah ReplicaSet. Pada Kubernetes 1.9 versi API apps/v1
pada kind
ReplicaSet adalah versi saat ini dan diaktifkan secara default. Versi API apps/v1beta2
telah dideprekasi. Lihat baris-baris awal pada contoh frontend.yaml
untuk petunjuk.
Sebuah ReplicaSet juga membutuhkan bagian .spec
.
Templat Pod
.spec.template
adalah sebuah templat pod yang juga dibutuhkan untuk mempunyai label. Pada contoh frontend.yaml
kita memiliki satu label: tier: frontend
.
Hati-hati agar tidak tumpang tindih dengan selektor dari controller lain, agar mereka tidak mencoba untuk mengadopsi Pod ini.
Untuk field restart policy dari templat, .spec.template.spec.restartPolicy
, nilai yang diperbolehkan hanyalah Always
, yang merupakan nilai default.
Selektor Pod
Field .spec.selector
adalah sebuah selektor labe. Seperti yang telah dibahas sebelumnya, field ini adalah label yang digunakan untuk mengidentifikasi Pod yang memungkinkan untuk diakuisisi. Pada contoh frontend.yaml
, selektornya adalah:
matchLabels:
tier: frontend
Pada ReplicaSet, .spec.template.metadata.labels
harus memiliki nilai yang sama dengan spec.selector
, atau akan ditolak oleh API.
.spec.selector
yang sama tetapi memiliki nilai yang berbeda pada field .spec.template.metadata.labels
dan .spec.template.spec
, setiap ReplicaSet akan mengabaikan Pod yang dibuat oleh ReplicaSet lain.
Replika
Kamu dapat menentukan jumlah Pod yang seharusnya berjalan secara konkuren dengan mengatur nilai dari .spec.replicas
. ReplicaSet akan membuat/menghapus Pod-nya hingga jumlahnya sesuai dengan field ini.
Jika nilai .spec.replicas
tidak ditentukan maka akan diatur ke nilai default 1.
Menggunakan ReplicaSet
Menghapus ReplicaSet dan Pod-nya
Untuk menghapus sebuah ReplicaSet beserta dengan Pod-nya, gunakan kubectl delete
. Garbage collector secara otomatis akan menghapus semua Pod dependen secara default.
Ketika menggunakan REST API atau library client-go
, kamu harus mengatur nilai propagationPolicy
menjadi Background
atau Foreground
pada opsi -d.
Sebagai contoh:
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"
Menghapus hanya ReplicaSet
Kamu dapat menghapus ReplicaSet tanpa memengaruhi Pod-nya menggunakan kubectl delete
dengan menggunakan opsi --cascade=false
.
Ketika menggunakan REST API atau library client-go
, kamu harus mengatur nilai propagationPolicy
menjadi Orphan
.
Sebagai contoh:
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"
Ketika ReplicaSet yang asli telah dihapus, kamu dapat membuat ReplicaSet baru untuk menggantikannya. Selama field .spec.selector
yang lama dan baru memilki nilai yang sama, maka ReplicaSet baru akan mengadopsi Pod lama namun tidak serta merta membuat Pod yang sudah ada sama dan sesuai dengan templat Pod yang baru.
Untuk memperbarui Pod dengan spec baru dapat menggunakan Deployment karena ReplicaSet tidak mendukung pembaruan secara langsung.
Mengisolasi Pod dari ReplicaSet
Kamu dapat menghapus Pod dari ReplicaSet dengan mengubah nilai labelnya. Cara ini dapat digunakan untuk menghapus Pod dari servis untuk keperluan debugging, data recovery, dan lainnya. Pod yang dihapus dengan cara ini akan digantikan seecara otomatis (dengan asumsi jumlah replika juga tidak berubah).
Mengatur jumlah Pod pada ReplicaSet
Jumlah Pod pada ReplicaSet dapat diatur dengan mengubah nilai dari field .spec.replicas
. Pengatur ReplicaSet akan memastikan Pod dengan jumlah yang telah ditentukan dan dengan nilai selektor yang sama sedang dalam keadaan berjalan.
Pengaturan jumlah Pod pada ReplicaSet menggunakan Horizontal Pod Autoscaler
Pengaturan jumlah Pod pada ReplicaSet juga dapat dilakukan mengunakan Horizontal Pod Autoscalers (HPA). Berikut adalah contoh HPA terhadap ReplicaSet yang telah dibuat pada contoh sebelumnya.
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: frontend-scaler
spec:
scaleTargetRef:
kind: ReplicaSet
name: frontend
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 50
Menyimpan manifest ini dalam hpa-rs.yaml
dan mengirimkannya ke klaster Kubernetes akan membuat HPA tersebut yang akan mengatur jumlah Pod pada ReplicaSet yang telah didefinisikan bergantung terhadap penggunaan CPU dari Pod yang direplikasi.
kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml
Opsi lainnya adalah dengan menggunakan perintah kubectl autoscale
untuk tujuan yang sama.
kubectl autoscale rs frontend --max=10
Alternatif selain ReplicaSet
Deployment (direkomendasikan)
Deployment
adalah sebuah objek yang bisa memiliki ReplicaSet dan memperbarui ReplicaSet dan Pod-nya melalui rolling update deklaratif dan server-side.
Walaupun ReplicaSet dapat digunakan secara independen, seringkali ReplicaSet digunakan oleh Deployments sebagai mekanisme untuk mengorkestrasi pembuatan, penghapusan dan pembaruan Pod. Ketika kamu menggunakan Deployments kamu tidak perlu khawatir akan pengaturan dari ReplicaSet yang dibuat. Deployments memiliki dan mengatur ReplicaSet-nya sendiri.
Maka dari itu penggunaan Deployments direkomendasikan jika kamu menginginkan ReplicaSet.
Pod sederhana
Tidak seperti pada kasus ketika pengguna secara langsung membuat Pod, ReplicaSet akan menggantikan Pod yang dihapus atau diterminasi dengan alasan apapun, seperti pada kasus dimana terjadi kegagalan node atau pemeliharaan node yang disruptif, seperti pada kasus upgrade kernel. Karena alasan ini kami merekomendasikan kamu untuk menggunakan ReplicaSet walaupun jika aplikasimu membutuhkan hanya satu Pod. Hal ini mirip dengan pengawas proses, hanya saja pada kasus ini mengawasi banyak Pod pada berbagai node alih-alih berbagai proses individu pada sebuah node. ReplicaSet mendelegasikan proses pengulangan kembali dari kontainer lokal kepada agen yang terdapat di node (sebagai contoh, Kubelet atau Docker).
Job
Gunakan Job
alih-alih ReplicaSet untuk Pod yang diharapkan untuk diterminasi secara sendirinya.
DaemonSet
Gunakan DaemonSet
alih-alih ReplicaSet untuk Pod yang menyediakan fungsi pada level mesin, seperti monitoring mesin atau logging mesin. Pod ini memiliki waktu hidup yang bergantung terhadap waktu hidup mesin: Pod perlu untuk berjalan pada mesin sebelum Pod lain dijalankan, dan aman untuk diterminasi ketika mesin siap untuk di-reboot atau dimatikan.
ReplicationController
ReplicaSet adalah suksesor dari ReplicationControllers. Keduanya memenuhi tujuan yang sama dan memiliki perilaku yang serupa, kecuali bahwa ReplicationController tidak mendukung kebutuhan selektor set-based seperti yang dijelaskan pada panduan penggunaan label. Pada kasus tersebut, ReplicaSet lebih direkomendasikan dibandingkan ReplicationController.
2.2 - ReplicationController
Deployment
yang mengonfigurasi ReplicaSet
sekarang menjadi cara yang direkomendasikan untuk melakukan replikasi.
Sebuah ReplicationController memastikan bahwa terdapat sejumlah Pod yang sedang berjalan dalam suatu waktu tertentu. Dengan kata lain, ReplicationController memastikan bahwa sebuah Pod atau sebuah kumpulan Pod yang homogen selalu berjalan dan tersedia.
Bagaimana ReplicationController Bekerja
Jika terdapat terlalu banyak Pod, maka ReplicationController akan membatasi dan mematikan Pod-Pod yang berlebih. Jika terdapat terlalu sedikit, maka ReplicationController akan memulai dan menjalankan Pod-Pod baru lainnya. Tidak seperti Pod yang dibuat secara manual, Pod-Pod yang diatur oleh sebuah ReplicationController akan secara otomatis diganti jika mereka gagal, dihapus, ataupun dimatikan. Sebagai contoh, Pod-Pod yang kamu miliki akan dibuat ulang dalam sebuah Node setelah terjadi proses pemeliharaan seperti pembaruan kernel. Untuk alasan ini, maka kamu sebaiknya memiliki sebuah ReplicationController bahkan ketika aplikasimu hanya membutuhkan satu buah Pod saja. Sebuah ReplicationController memiliki kemiripan dengan sebuah pengawas proses, tetapi alih-alih mengawasi sebuah proses individu pada sebuah Node, ReplicationController banyak Pod yang terdapat pada beberapa Node.
ReplicationController seringkali disingkat sebagai "rc" dalam diskusi, dan sebagai shortcut dalam perintah kubectl.
Sebuah contoh sederhana adalah membuat sebuah objek ReplicationController untuk menjalankan sebuah instance Pod secara berkelanjutan. Contoh pemakaian lainnya adalah untuk menjalankan beberapa replika identik dari sebuah servis yang direplikasi, seperti peladen web.
Menjalankan Sebuah Contoh ReplicationController
Contoh ReplicationController ini mengonfigurasi tiga salinan dari peladen web nginx.
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
Jalankan contoh di atas dengan mengunduh berkas contoh dan menjalankan perintah ini:
kubectl apply -f https://k8s.io/examples/controllers/replication.yaml
replicationcontroller/nginx created
Periksa status dari ReplicationController menggunakan perintah ini:
kubectl describe replicationcontrollers/nginx
Name: nginx
Namespace: default
Selector: app=nginx
Labels: app=nginx
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 0 Running / 3 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- ---- ------ -------
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-qrm3m
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-3ntk0
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-4ok8v
Tiga Pod telah dibuat namun belum ada yang berjalan, kemungkinan karena image yang sedang di-pull. Beberapa waktu kemudian, perintah yang sama akan menunjukkan:
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Untuk melihat semua Pod yang dibuat oleh ReplicationController dalam bentuk yang lebih mudah dibaca mesin, kamu dapat menggunakan perintah seperti ini:
pods=$(kubectl get pods --selector=app=nginx --output=jsonpath={.items..metadata.name})
echo $pods
nginx-3ntk0 nginx-4ok8v nginx-qrm3m
Pada perintah di atas, selektor yang dimaksud adalah selektor yang sama dengan yang terdapat pada ReplicationController (yang dapat dilihat pada keluaran kubectl describe
), dan dalam bentuk yang berbeda dengan yang terdapat pada replication.yaml
. Opsi --output=jsonpath
menentukan perintah untuh mendapatkan hanya nama dari setiap Pod yang ada pada daftar hasil.
Menulis Spesifikasi ReplicationController
Seperti semua konfigurasi Kubernetes lainnya, sebuah ReplicationController membutuhkan field apiVersion
, kind
, dan metadata
.
Untuk informasi umum mengenai berkas konfigurasi, kamu dapat melihat pengaturan objek.
Sebuah ReplicationController juga membutuhkan bagian .spec
.
Templat Pod
.spec.template
adalah satu-satunya field yang diwajibkan pada .spec
.
.spec.template
adalah sebuah templat Pod. Ia memiliki skema yang sama persis dengan sebuah Pod, namun dapat berbentuk nested dan tidak memiliki field apiVersion
ataupun kind
.
Selain field-field yang diwajibkan untuk sebuah Pod, templat Pod pada ReplicationController harus menentukan label dan kebijakan pengulangan kembali yang tepat. Untuk label, pastikan untuk tidak tumpang tindih dengan kontroler lain. Lihat selektor pod.
Nilai yang diperbolehkan untuk .spec.template.spec.restartPolicy
hanyalah Always
, yaitu nilai bawaan jika tidak ditentukan.
Untuk pengulangan kembali dari sebuah kontainer lokal, ReplicationController mendelegasikannya ke agen pada Node, contohnya Kubelet atau Docker.
Label pada ReplicationController
ReplicationController itu sendiri dapat memiliki label (.metadata.labels
). Biasanya, kamu akan mengaturnya untuk memiliki nilai yang sama dengan .spec.template.metadata.labels
; jika .metadata.labels
tidak ditentukan maka akan menggunakan nilai bawaan yaitu .spec.template.metadata.labels
. Namun begitu, kedua label ini diperbolehkan untuk memiliki nilai yang berbeda, dan .metadata.labels
tidak akan memengaruhi perilaku dari ReplicationController.
Selektor Pod
Field .spec.selector
adalah sebuah selektor label. Sebuah ReplicationController mengatur semua Pod dengan label yang sesuai dengan nilai selektor tersebut. Ia tidak membedakan antara Pod yang ia buat atau hapus atau Pod yang dibuat atau dihapus oleh orang atau proses lain. Hal ini memungkinkan ReplicationController untuk digantikan tanpa memengaruhi Pod-Pod yang sedang berjalan.
Jika ditentukan, .spec.template.metadata.labels
harus memiliki nilai yang sama dengan .spec.selector
, atau akan ditolak oleh API. Jika .spec.selector
tidak ditentukan, maka akan menggunakan nilai bawaan yaitu .spec.template.metadata.labels
.
Selain itu, kamu juga sebaiknya tidak membuat Pod dengan label yang cocok dengan selektor ini, baik secara langsung, dengan menggunakan ReplicationController lain, ataupun menggunakan kontroler lain seperti Job. Jika kamu melakukannya, ReplicationController akan menganggap bahwa ia telah membuat Pod-Pod lainnya. Kubernetes tidak akan menghentikan kamu untuk melakukan aksi ini.
Jika kamu pada akhirnya memiliki beberapa kontroler dengan selektor-selektor yang tumpang tindih, kamu harus mengatur penghapusannya sendiri (lihat di bawah).
Beberapa Replika
Kamu dapat menentukan jumlah Pod yang seharusnya berjalan secara bersamaan dengan mengatur nilai .spec.replicas
dengan jumlah Pod yang kamu inginkan untuk berjalan secara bersamaan. Jumlah yang berjalan dalam satu satuan waktu dapat lebih tinggi ataupun lebih rendah, seperti jika replika-replika tersebut melewati proses penambahan atau pengurangan, atau jika sebuah Pod melalui proses graceful shutdown, dan penggantinya telah dijalankan terlebih dahulu.
Jika kamu tidak menentukan nilai dari .spec.replicas
, maka akan digunakan nilai bawaan 1.
Bekerja dengan ReplicationController
Menghapus Sebuah ReplicationController dan Pod-nya
Untuk menghapus sebuah ReplicationController dan Pod-Pod yang berhubungan dengannya, gunakan perintah kubectl delete
. Kubectl akan mengatur ReplicationController ke nol dan menunggunya untuk menghapus setiap Pod sebelum menghapus ReplicationController itu sendiri. Jika perintah kubectl ini terhenti, maka dapat diulang kembali.
Ketika menggunakan REST API atau library klien go, maka kamu perlu melakukan langkah-langkahnya secara eksplisit (mengatur replika-replika ke 0, menunggu penghapusan Pod, dan barulah menghapus ReplicationController).
Menghapus Hanya ReplicationController
Kamu dapat menghapus ReplicationController tanpa memengaruhi Pod-Pod yang berhubungan dengannya.
Dengan menggunakan kubectl, tentukan opsi --cascade=false
ke kubectl delete
.
Ketika menggunakan REST API atau library klien go, cukup hapus objek ReplicationController.
Ketika ReplicationController yang asli telah dihapus, kamu dapat membuat ReplicationController yang baru sebagai penggantinya. Selama .spec.selector
yang lama dan baru memiliki nilai yang sama, maka ReplicationController baru akan mengadopsi Pod-Pod yang lama.
Walaupun begitu, ia tidak akan melakukan usaha apapun untuk membuat Pod-Pod yang telah ada sebelumnya untuk sesuai dengan templat Pod yang baru dan berbeda.
Untuk memperbarui Pod-Pod ke spesifikasi yang baru dengan cara yang terkontrol, gunakan pembaruan bergulir.
Mengisolasi Pod dari ReplicationController
Pod-Pod dapat dihapus dari kumpulan target sebuah ReplicationController dengan mengganti nilai dari labelnya. Teknik ini dapat digunakan untuk mencopot Pod-Pod dari servis untuk keperluan pengawakutuan (debugging), pemulihan data, dan lainnya. Pod-Pod yang dicopot dengan cara ini dapat digantikan secara otomatis (dengan asumsi bahwa jumlah replika juga tidak berubah).
Pola penggunaan umum
Penjadwalan ulang
Seperti yang telah disebutkan sebelumnya, baik kamu memiliki hanya 1 Pod untuk tetap dijalankan, ataupun 1000, ReplicationController akan memastikan tersedianya jumlah Pod yang telat ditentukan, bahkan ketika terjadi kegagalan Node atau terminasi Pod (sebagai contoh karena adanya tindakan dari agen kontrol lain).
Penskalaan
ReplicationController memudahkan penskalaan jumlah replika, baik meningkatkan ataupun mengurangi, secara manual ataupun dengan agen kontrol penskalaan otomatis, dengan hanya mengubah nilai dari field replicas
.
Pembaruan bergulir
ReplicationController didesain untuk memfasilitasi pembaruan bergulir untuk sebuah servis dengan mengganti Pod-Pod satu per satu.
Seperti yang telah dijelaskan di #1353, pendekatan yang direkomendasikan adalah dengan membuat ReplicationController baru dengan 1 replika, skala kontroler yang baru (+1) atau yang lama (-1) satu per satu, dan kemudian hapus kontroler lama setelah menyentuh angka 0 replika. Hal ini memungkinkan pembaruan dilakukan dengan dapat diprediksi terlepas dari adanya kegagalan yang tak terduga.
Idealnya, kontroler pembaruan bergulir akan memperhitungkan kesiapan dari aplikasi, dan memastikan cukupnya jumlah Pod yang secara produktif meladen kapanpun.
Dua ReplicationController diharuskan untuk memiliki setidaknya satu label yang berbeda, seperti tag image dari kontainer utama dari Pod, karena pembaruan bergulir biasanya dilakukan karena adanya pembaruan image.
Pembaruan bergulir diimplementasikan pada perkakas klien kubectl rolling-update
. Lihat kubectl rolling-update
task untuk contoh-contoh yang lebih konkrit.
Operasi rilis majemuk
Selain menjalankan beberapa rilis dari sebuah aplikasi ketika proses pembaruan bergulir sedang berjalan, adalah hal yang awam untuk menjalankan beberapa rilis untuk suatu periode waktu tertentu, atau bahkan secara kontinu, menggunakan operasi rilis majemuk. Operasi-operasi ini akan dibedakan menggunakan label.
Sebagai contoh, sebuah servis dapat menyasar semua Pod dengan tier in (frontend), environment in (prod)
. Anggap kamu memiliki 10 Pod tiruan yang membangun tier ini tetapi kamu ingin bisa menggunakan 'canary' terhadap versi baru dari komponen ini. Kamu dapat mengatur sebuah ReplicationController dengan nilai replicas
9 untuk replika-replikanya, dengan label tier=frontend, environment=prod, track=stable
, dan ReplicationController lainnya dengan nilai replicas
1 untuk canary, dengan label tier=frontend, environment=prod, track=canary
. Sekarang servis sudah mencakup baik canary maupun Pod-Pod yang bukan canary. Kamu juga dapat mencoba-coba ReplicationController secara terpisah untuk melakukan pengujian, mengamati hasilnya, dan lainnya.
Menggunakan ReplicationController dengan Service
Beberapa ReplicationController dapat berada di belakang sebuah Service, sedemikian sehingga, sebagai contoh, sebagian traffic dapat ditujukan ke versi lama, dan sebagian lainnya ke versi yang baru.
Sebuah ReplicationController tidak akan berhenti dengan sendirinya, namun ia tidak diekspektasikan untuk berjalan selama Service-Service yang ada. Service dapat terdiri dari berbagai Pod yang dikontrol beberapa ReplicationController, dan terdapat kemungkinan bahwa beberapa ReplicationController untuk dibuat dan dimatikan dalam jangka waktu hidup Service (contohnya adalah untuk melakukan pembaruan Pod-Pod yang menjalankan Service). Baik Service itu sendiri dan kliennya harus tetap dalam keadaan tidak mempunyai pengetahuan terhadap ReplicationController yang memelihara Pod-Pod dari Service tersebut.
Menulis program untuk Replikasi
Pod-Pod yang dibuat oleh ReplicationController ditujukan untuk dapat sepadan dan memiliki semantik yang identik, walaupun konfigurasi mereka dapat berbeda seiring keberjalanan waktunya. Ini adalah contoh yang cocok untuk peladen stateless, namun ReplicationController juga dapat digunakan untuk memelihara ketersediaan dari aplikasi-aplikasi yang master-elected, sharded, worker-pool. Aplikasi-aplikasi seperti itu sebaiknya menggunakan mekanisme penetapan kerja yang dinamis, seperti antrian kerja RabbitMQ, berlainan dengan pengubahan statis/satu kali dari konfigurasi setiap Pod, yang dipandang sebagai sebuah anti-pattern. Pengubahan apapun yang dilakukan terhadap Pod, seperti auto-sizing vertikal dari sumber daya (misalnya cpu atau memori), sebaiknya dilakukan oleh proses kontroller luring lainnya, dan bukan oleh ReplicationController itu sendiri.
Tanggung Jawab ReplicationController
ReplicationController hanya memastikan ketersediaan dari sejumlah Pod yang cocok dengan selektor label dan berjalan dengan baik. Saat ini, hanya Pod yang diterminasi yang dijadikan pengecualian dari penghitungan. Kedepannya, kesiapan dan informasi yang ada lainnya dari sistem dapat menjadi pertimbangan, kami dapat meningkatkan kontrol terhadap kebijakan penggantian, dan kami berencana untuk menginformasikan kejadian (event) yang dapat digunakan klien eksternal untuk implementasi penggantian yang sesuai dan/atau kebijakan pengurangan.
ReplicationController akan selalu dibatasi terhadap tanggung jawab spesifik ini. Ia tidak akan melakukan probe kesiapan atau keaktifan. Daripada melakukan auto-scaling, ia ditujukan untuk dikontrol oleh auto-scaler eksternal (seperti yang didiskusikan pada #492), yang akan mengganti field replicas
. Kami tidak akan menambahkan kebijakan penjadwalan (contohnya spreading) untuk ReplicationController. Ia juga tidak seharusnya melakukan verifikasi terhadap Pod-Pod yang sedang dikontrol yang cocok dengan spesifikasi templat saat ini, karena hal itu dapat menghambat auto-sizing dan proses otomatis lainnya. Demikian pula batas waktu penyelesaian, pengurutan dependencies, ekspansi konfigurasi, dan fitur-fitur lain yang seharusnya berada di komponen lain. Kami juga bahkan berencana untuk mengeluarkan mekanisme pembuatan Pod secara serentak (#170).
ReplicationController ditujukan untuk menjadi primitif komponen yang dapat dibangun untuk berbagai kebutuhan. Kami menargetkan API dengan tingkatan yang lebih tinggi dan/atau perkakas-perkakas untuk dibangun di atasnya dan primitif tambahan lainnya untuk kenyamanan pengguna kedepannya. Operasi-operasi makro yang sudah didukung oleh kubectl (run, scale, rolling-update) adalah contoh proof-of-concept dari konsep ini. Sebagai contohnya, kita dapat menganggap sesuatu seperti Asgard yang mengatur beberapa ReplicationController, auto-scaler, servis, kebijakan penjadwalan, canary, dan yang lainnya.
Objek API
ReplicationController adalah sebuah sumber daya top-level pada REST API Kubernetes. Detil dari objek API dapat ditemukan di: objek API ReplicationController.
Alternatif untuk ReplicationController
ReplicaSet
ReplicaSet
adalah kelanjutan dari ReplicationController yang mendukung selektor selektor label set-based yang baru. Umumnya digunakan oleh Deployment
sebagai mekanisme untuk mengorkestrasi pembuatan, penghapusan, dan pembaruan Pod.
Perhatikan bahwa kami merekomendasikan untuk menggunakan Deployment sebagai ganti dari menggunakan ReplicaSet secara langsung, kecuali jika kamu membutuhkan orkestrasi pembaruan khusus atau tidak membutuhkan pembaruan sama sekali.
Deployment (Direkomendasikan)
Deployment
adalah objek API tingkat tinggi yang memperbarui ReplicaSet dan Pod-Pod di bawahnya yang mirip dengan cara kerja kubectl rolling-update
. Deployment direkomendasikan jika kamu menginginkan fungsionalitas dari pembaruan bergulir ini, karena tidak seperti kubectl rolling-update
, Deployment memiliki sifat deklaratif, server-side, dan memiliki beberapa fitur tambahan lainnya.
Pod sederhana
Tidak seperti pada kasus ketika pengguna secara langsung membuat Pod, ReplicationController menggantikan Pod-Pod yang dihapus atau dimatikan untuk alasan apapun, seperti pada kasus kegagalan Node atau pemeliharaan Node yang disruptif, seperti pembaruan kernel. Untuk alasan ini, kami merekomendasikan kamu untuk menggunakan ReplicationController bahkan ketika aplikasimu hanya membutuhkan satu Pod saja. Anggap hal ini mirip dengan pengawas proses, hanya pada kasus ini mengawasi banyak Pod yang terdapat pada berbagai Node dan bukan proses-proses tunggal pada satu Node. ReplicationController mendelegasikan pengulangan kontainer lokal ke agen yang terdapat dalam Node (contohnya Kubelet atau Docker).
Job
Gunakan Job
sebagai ganti ReplicationController untuk Pod-Pod yang diharapkan diterminasi dengan sendirinya (seperti batch jobs).
DaemonSet
Gunakan DaemonSet
sebagai ganti ReplicationController untuk Pod-Pod yang menyediakan fungsi pada level mesin, seperti pengamatan mesin atau pencatatan mesin. Pod-Pod ini memiliki waktu hidup yang bergantung dengan waktu hidup mesin: Pod butuh untuk dijalankan di mesin sebelum Pod-Pod lainnya dimulai, dan aman untuk diterminasi ketika mesin sudah siap untuk dinyalakan ulang atau dimatikan.
Informasi lanjutan
2.3 - Deployment
Deployment menyediakan pembaruan Pods dan ReplicaSets secara deklaratif.
Kamu mendeskripsikan sebuah state yang diinginkan dalam Deployment, kemudian Deployment Pengontrol mengubah state sekarang menjadi seperti pada deskripsi secara bertahap. Kamu dapat mendefinisikan Deployment untuk membuat ReplicaSets baru atau untuk menghapus Deployment yang sudah ada dan mengadopsi semua resourcenya untuk Deployment baru.
Penggunaan
Berikut adalah penggunaan yang umum pada Deployment:
- Membuat Deployment untuk merilis ReplicaSet. ReplicaSet membuat Pod di belakang layar. Cek status rilis untuk tahu proses rilis sukses atau tidak.
- Mendeklarasikan state baru dari Pods dengan membarui PodTemplateSpec milik Deployment. ReplicaSet baru akan dibuat dan Deployment mengatur perpindahan Pod secara teratur dari ReplicaSet lama ke ReplicaSet baru. Tiap ReplicaSet baru akan mengganti revisi Deployment.
- Mengembalikan ke revisi Deployment sebelumnya jika state Deployment sekarang tidak stabil. Tiap pengembalian mengganti revisi Deployment.
- Memperbesar Deployment untuk memfasilitasi beban yang lebih.
- Menjeda Deployment untuk menerapkan perbaikan pada PodTemplateSpec-nya, lalu melanjutkan untuk memulai rilis baru.
- Memakai status Deployment sebagai indikator ketika rilis tersendat.
- Membersihkan ReplicaSet lama yang sudah tidak terpakai.
Membuat Deployment
Berikut adalah contoh Deployment. Dia membuat ReplicaSet untuk membangkitkan tiga Pod nginx
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Dalam contoh ini:
-
Deployment baru akan dibuat dengan nama
nginx-deployment
, tertulis pada kolom.metadata.name
. -
Deployment membuat tiga Pod yang direplikasi, ditandai dengan kolom
replicas
. -
Kolom
selector
mendefinisikan bagaimana Deployment menemukan Pod yang diatur. Dalam kasus ini, kamu hanya perlu memilih sebuah label yang didefinisikan pada templat Pod (app: nginx
). Namun, aturan pemilihan yang lebih canggih mungkin dilakukan asal templat Pod-nya memenuhi aturan.Catatan: KolommatchLabels
berbentuk pasangan {key,value}. Sebuah {key,value} dalam mapmatchLabels
ekuivalen dengan elemen padamatchExpressions
, yang mana kolom key adalah "key", operator adalah "In", dan larik values hanya berisi "value". Semua prasyarat darimatchLabels
maupunmatchExpressions
harus dipenuhi agar dapat dicocokkan. -
Kolom
template
berisi sub kolom berikut:- Pod dilabeli
app: nginx
dengan kolomlabels
. - Spesifikasi templat Pod atau kolom
.template.spec
menandakan bahwa Pod mennjalankan satu kontainernginx
, yang menjalankan imagenginx
Docker Hub dengan versi 1.7.9. - Membuat satu kontainer bernama
nginx
sesuai kolomname
.
Ikuti langkah-langkah berikut untuk membuat Deployment di atas:
Sebelum memulai, pastikan klaster Kubernetes sedang menyala dan bekerja.
-
Buat Deployment dengan menjalankan perintah berikut:
Catatan: Kamu dapat menambahkan argument--record
untuk menulis perintah yang dijalankan pada anotasi sumber dayakubernetes.io/change-cause
. Ini berguna untuk pemeriksaan di masa depan. Contohnya yaitu untuk melihat perintah yang dijalankan pada tiap revisi Deployment.
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
- Jalankan
kubectl get deployments
untuk mengecek apakah Deployment telah dibuat. Jika Deployment masih sedang pembuatan, keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 0 0 0 1s
Ketika kamu memeriksa Deployments pada klastermu, kolom berikut akan tampil:
* `NAME` menampilkan daftar nama Deployment pada klaster. * `DESIRED` menampilkan jumlah replika aplikasi yang diinginkan sesuai yang didefinisikan saat pembuatan Deployment. Ini adalah _state_ yang diinginkan. * `CURRENT` menampilkan berapa jumlah replika yang sedang berjalan. * `UP-TO-DATE` menampilkan jumlah replika yang diperbarui agar sesuai state yang diinginkan. * `AVAILABLE` menampilkan jumlah replika aplikasi yang dapat diakses pengguna. * `AGE` menampilkan lama waktu aplikasi telah berjalan.
Perhatikan bahwa jumlah replika yang diinginkan adalah tiga sesuai kolom
.spec.replicas
.- Untuk melihat status rilis Deployment, jalankan
kubectl rollout status deployment.v1.apps/nginx-deployment
. Keluaran akan tampil seperti berikut:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated... deployment "nginx-deployment" successfully rolled out
- Jalankan
kubectl get deployments
lagi beberapa saat kemudian. Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 18s
Perhatikan bahwa Deployment telah membuat ketiga replika dan semua replika sudah merupakan yang terbaru (mereka mengandung pembaruan terakhir templat Pod) dan dapat diakses.
- Untuk melihat ReplicaSet (
rs
) yang dibuat Deployment, jalankankubectl get rs
. Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE nginx-deployment-75675f5897 3 3 3 18s
Perhatikan bahwa nama ReplicaSet selalu dalam format
[NAMA-DEPLOYMENT]-[KATA-ACAK]
. Kata acak dibangkitkan secara acak dan menggunakan pod-template-hash sebagai benih.- Untuk melihat label yang dibangkitkan secara otomatis untuk tiap Pod, jalankan
kubectl get pods --show-labels
. Perintah akan menghasilkan keluaran berikut:
NAME READY STATUS RESTARTS AGE LABELS nginx-deployment-75675f5897-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453 nginx-deployment-75675f5897-kzszj 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453 nginx-deployment-75675f5897-qqcnn 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453
ReplicaSet yang dibuat menjamin bahwa ada tiga Pod
nginx
.Catatan: Kamu harus memasukkan selektor dan label templat Pod yang benar pada Deployment (dalam kasus ini,app: nginx
). Jangan membuat label atau selektor yang beririsan dengan kontroler lain (termasuk Deployment dan StatefulSet lainnya). Kubernetes tidak akan mencegah adanya label yang beririsan. Namun, jika beberapa kontroler memiliki selektor yang beririsan, kontroler itu mungkin akan konflik dan berjalan dengan tidak semestinya. - Pod dilabeli
Label pod-template-hash
Label pod-template-hash
ditambahkan oleh Deployment kontroler pada tiap ReplicaSet yang dibuat atau diadopsi Deployment.
Label ini menjamin anak-anak ReplicaSet milik Deployment tidak tumpang tindih. Dia dibangkitkan dengan melakukan hash pada PodTemplate
milik ReplicaSet dan memakainya sebagai label untuk ditambahkan ke selektor ReplicaSet, label templat Pod, dan Pod apapun yang ReplicaSet miliki.
Membarui Deployment
.spec.template
), contohnya perubahan kolom label atau image container. Yang lain, seperti replika, tidak akan memicu rilis.
Ikuti langkah-langkah berikut untuk membarui Deployment:
-
Ganti Pod nginx menjadi image
nginx:1.9.1
dari imagenginx:1.7.9
.kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment image updated
Alternatif lainnya, kamu dapat
edit
Deployment dan mengganti.spec.template.spec.containers[0].image
daringinx:1.7.9
kenginx:1.9.1
:kubectl edit deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment edited
-
Untuk melihat status rilis, jalankan:
kubectl rollout status deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
atau
deployment "nginx-deployment" successfully rolled out
Untuk menampilkan detail lain dari Deployment yang terbaru:
-
Setelah rilis sukses, kamu dapat melihat Deployment dengan menjalankan
kubectl get deployments
. Keluaran akan tampil seperti berikut:NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 36s
-
Jalankan
kubectl get rs
to see that the Deployment updated the Pods dengan membuat ReplicaSet baru dan menggandakannya menjadi 3 replika, sembari menghapus ReplicaSet menjadi 0 replika.kubectl get rs
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE nginx-deployment-1564180365 3 3 3 6s nginx-deployment-2035384211 0 0 0 36s
-
Menjalankan
get pods
sekarang hanya akan menampilkan Pod baru:kubectl get pods
Keluaran akan tampil seperti berikut:
NAME READY STATUS RESTARTS AGE nginx-deployment-1564180365-khku8 1/1 Running 0 14s nginx-deployment-1564180365-nacti 1/1 Running 0 14s nginx-deployment-1564180365-z9gth 1/1 Running 0 14s
Selanjutnya ketika ingin membarui Pod, kamu hanya perlu mengganti templat Pod Deployment lagi.
Deployment memastikan hanya ada beberapa Pod yang mati saat pembaruan berlangsung. Umumnya, dia memastikan paling sedikit ada 75% jumlah Pod yang diinginkan menyala (25% maksimal tidak dapat diakses).
Deployment juga memastikan hanya ada beberapa Pod yang dibuat melebihi jumlah Pod yang diinginkan. Umumnya, dia memastikan paling banyak ada 125% jumlah Pod yang diinginkan menyala (25% tambahan maksimal).
Misalnya, jika kamu lihat Deployment diatas lebih jauh, kamu akan melihat bahwa pertama-tama dia membuat Pod baru, kemudian menghapus beberapa Pod lama, dan membuat yang baru. Dia tidak akan menghapus Pod lama sampai ada cukup Pod baru menyala, dan pula tidak membuat Pod baru sampai ada cukup Pod lama telah mati. Dia memastikan paling sedikit 2 Pod menyala dan paling banyak total 4 Pod menyala.
-
Melihat detil Deployment:
kubectl describe deployments
Keluaran akan tampil seperti berikut:
Name: nginx-deployment Namespace: default CreationTimestamp: Thu, 30 Nov 2017 10:56:25 +0000 Labels: app=nginx Annotations: deployment.kubernetes.io/revision=2 Selector: app=nginx Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=nginx Containers: nginx: Image: nginx:1.9.1 Port: 80/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3 Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1 Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2 Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2 Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1 Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3 Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0
Disini bisa dilihat ketika pertama Deployment dibuat, dia membuat ReplicaSet (nginx-deployment-2035384211) dan langsung menggandakannya menjadi 3 replika. Saat Deployment diperbarui, dia membuat ReplicaSet baru (nginx-deployment-1564180365) dan menambah 1 replika kemudian mengecilkan ReplicaSet lama menjadi 2, sehingga paling sedikit 2 Pod menyala dan paling banyak 4 Pod dibuat setiap saat. Dia kemudian lanjut menaik-turunkan ReplicaSet baru dan ReplicaSet lama, dengan strategi pembaruan rolling yang sama. Terakhir, kamu akan dapat 3 replika di ReplicaSet baru telah menyala, dan ReplicaSet lama akan hilang (berisi 0).
Perpanjangan (alias banyak pembaruan secara langsung)
Setiap kali Deployment baru is teramati oleh Deployment kontroler, ReplicaSet dibuat untuk membangkitkan Pod sesuai keinginan.
Jika Deployment diperbarui, ReplicaSet yang terkait Pod dengan label .spec.selector
yang cocok,
namun kolom .spec.template
pada templat tidak cocok akan dihapus. Kemudian, ReplicaSet baru akan
digandakan sebanyak .spec.replicas
dan semua ReplicaSet lama dihapus.
Jika kamu mengubah Deployment saat rilis sedang berjalan, Deployment akan membuat ReplicaSet baru tiap perubahan dan memulai penggandaan. Lalu, dia akan mengganti ReplicaSet yang dibuat sebelumnya -- mereka ditambahkan ke dalam daftar ReplicaSet lama dan akan mulai dihapus.
Contohnya, ketika kamu membuat Deployment untuk membangkitkan 5 replika nginx:1.7.9
,
kemudian membarui Deployment dengan versi nginx:1.9.1
ketika ada 3 replika nginx:1.7.9
yang dibuat.
Dalam kasus ini, Deployment akan segera menghapus 3 replika Pod nginx:1.7.9
yang telah dibuat, dan mulai membuat
Pod nginx:1.9.1
. Dia tidak akan menunggu kelima replika nginx:1.7.9
selesai baru menjalankan perubahan.
Mengubah selektor label
Umumnya, sekali dibuat, selektor label tidak boleh diubah. Sehingga disarankan untuk direncanakan dengan hati-hati sebelumnya. Bagaimanapun, jika kamu perlu mengganti selektor label, lakukan dengan seksama dan pastikan kamu tahu segala konsekuensinya.
apps/v1
, selektor label Deployment tidak bisa diubah ketika selesai dibuat.
- Penambahan selektor mensyaratkan label templat Pod di spek Deployment untuk diganti dengan label baru juga. Jika tidak, galat validasi akan muncul. Perubahan haruslah tidak tumpang-tindih, dengan kata lain selektor baru tidak mencakup ReplicaSet dan Pod yang dibuat dengan selektor lama. Sehingga, semua ReplicaSet lama akan menggantung sedangkan ReplicaSet baru tetap dibuat.
- Pengubahan selektor mengubah nilai pada kunci selektor -- menghasilkan perilaku yang sama dengan penambahan.
- Penghapusan selektor menghilangkan kunci yang ada pada selektor Deployment -- tidak mensyaratkan perubahan apapun pada label templat Pod. ReplicaSet yang ada tidak menggantung dan ReplicaSet baru tidak dibuat. Tapi perhatikan bahwa label yang dihapus masih ada pada Pod dan ReplicaSet masing-masing.
Membalikkan Deployment
Kadang, kamu mau membalikkan Deployment; misalnya, saat Deployment tidak stabil, seperti crash looping. Umumnya, semua riwayat rilis Deployment disimpan oleh sistem sehingga kamu dapat kembali kapanpun kamu mau (kamu dapat mengubahnya dengan mengubah batas riwayat revisi).
.spec.template
) berubah, misalnya jika kamu membarui label atau image kontainer pada templat.
Pembaruan lain, seperti penggantian skala Deployment, tidak membuat revisi Deployment, jadi kamu dapat memfasilitasi
penggantian skala secara manual atau otomatis secara simultan. Artinya saat kamu membalikkan ke versi sebelumnya,
hanya bagian templat Pod Deployment yang dibalikkan.
-
Misal kamu membuat saltik saat mengganti Deployment, dengan memberi nama image dengan
nginx:1.91
alih-alihnginx:1.9.1
:kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.91 --record=true
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment image updated
-
Rilis akan tersendat. Kamu dapat memeriksanya dengan melihat status rilis:
kubectl rollout status deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
-
Tekan Ctrl-C untuk menghentikan pemeriksaan status rilis di atas. Untuk info lebih lanjut tentang rilis tersendat, baca disini.
-
Kamu lihat bahwa jumlah replika lama (
nginx-deployment-1564180365
dannginx-deployment-2035384211
) adalah 2, dan replika baru (nginx-deployment-3066724191) adalah 1.kubectl get rs
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE nginx-deployment-1564180365 3 3 3 25s nginx-deployment-2035384211 0 0 0 36s nginx-deployment-3066724191 1 1 0 6s
-
Lihat pada Pod yang dibuat. Akan ada 1 Pod dibuat dari ReplicaSet baru tersendat loop(?) ketika penarikan image.
kubectl get pods
Keluaran akan tampil seperti berikut:
NAME READY STATUS RESTARTS AGE nginx-deployment-1564180365-70iae 1/1 Running 0 25s nginx-deployment-1564180365-jbqqo 1/1 Running 0 25s nginx-deployment-1564180365-hysrc 1/1 Running 0 25s nginx-deployment-3066724191-08mng 0/1 ImagePullBackOff 0 6s
Catatan: Controller Deployment menghentikan rilis yang buruk secara otomatis dan juga berhenti meningkatkan ReplicaSet baru. Ini tergantung pada parameter rollingUpdate (secara khususmaxUnavailable
) yang dimasukkan. Kubernetes umumnya mengatur jumlahnya menjadi 25%. -
Tampilkan deskripsi Deployment:
kubectl describe deployment
Keluaran akan tampil seperti berikut:
Name: nginx-deployment Namespace: default CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700 Labels: app=nginx Selector: app=nginx Replicas: 3 desired | 1 updated | 4 total | 3 available | 1 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=nginx Containers: nginx: Image: nginx:1.91 Port: 80/TCP Host Port: 0/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True ReplicaSetUpdated OldReplicaSets: nginx-deployment-1564180365 (3/3 replicas created) NewReplicaSet: nginx-deployment-3066724191 (1/1 replicas created) Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3 22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1 22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2 22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2 21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 1 21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3 13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0 13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
Untuk memperbaikinya, kamu harus kembali ke revisi Deployment yang sebelumnya stabil.
Mengecek Riwayat Rilis Deployment
Ikuti langkah-langkah berikut untuk mengecek riwayat rilis:
-
Pertama, cek revisi Deployment sekarang:
kubectl rollout history deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
deployments "nginx-deployment" REVISION CHANGE-CAUSE 1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml --record=true 2 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true 3 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.91 --record=true
CHANGE-CAUSE
disalin dari anotasi Deploymentkubernetes.io/change-cause
ke revisi saat pembuatan. Kamu dapat menentukan pesanCHANGE-CAUSE
dengan:- Menambahkan anotasi pada Deployment dengan
kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.9.1"
- Menambahkan argumen
--record
untuk menyimpan perintahkubectl
yang menyebabkan perubahan sumber daya. - Mengganti manifest sumber daya secara manual.
- Menambahkan anotasi pada Deployment dengan
-
Untuk melihat detil tiap revisi, jalankan:
kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
Keluaran akan tampil seperti berikut:
deployments "nginx-deployment" revision 2 Labels: app=nginx pod-template-hash=1159050644 Annotations: kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true Containers: nginx: Image: nginx:1.9.1 Port: 80/TCP QoS Tier: cpu: BestEffort memory: BestEffort Environment Variables: <none> No volumes.
Kembali ke Revisi Sebelumnya
Ikuti langkah-langkah berikut untuk membalikkan Deployment dari versi sekarang ke versi sebelumnya, yaitu versi 2.
-
Sekarang kamu telah menentukan akan mengembalikan rilis sekarang ke sebelumnya:
kubectl rollout undo deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment
Gantinya, kamu dapat kambali ke revisi tertentu dengan menambahkan argumen
--to-revision
:kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment
Untuk detil lebih lanjut perintah terkait rilis, baca
rilis kubectl
.Deployment sekarang dikembalikan ke revisi stabil sebelumnya. Seperti terlihat, ada event
DeploymentRollback
yang dibentuk oleh kontroler Deployment untuk pembalikan ke revisi 2. -
Cek apakah rilis telah sukses dan Deployment berjalan seharusnya, jalankan:
kubectl get deployment nginx-deployment
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 30m
-
Tampilkan deskripsi Deployment:
kubectl describe deployment nginx-deployment
Keluaran akan tampil seperti berikut:
Name: nginx-deployment Namespace: default CreationTimestamp: Sun, 02 Sep 2018 18:17:55 -0500 Labels: app=nginx Annotations: deployment.kubernetes.io/revision=4 kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true Selector: app=nginx Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=nginx Containers: nginx: Image: nginx:1.9.1 Port: 80/TCP Host Port: 0/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: nginx-deployment-c4747d96c (3/3 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-75675f5897 to 3 Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 1 Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 2 Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 2 Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 1 Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 3 Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 0 Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-595696685f to 1 Normal DeploymentRollback 15s deployment-controller Rolled back deployment "nginx-deployment" to revision 2 Normal ScalingReplicaSet 15s deployment-controller Scaled down replica set nginx-deployment-595696685f to 0
Mengatur Skala Deployment
Kamu dapat mengatur skala Deployment dengan perintah berikut:
kubectl scale deployment.v1.apps/nginx-deployment --replicas=10
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment scaled
Dengan asumsi horizontal Pod autoscaling dalam klaster dinyalakan, kamu dapat mengatur autoscaler untuk Deployment-mu dan memilih jumlah minimal dan maksimal Pod yang mau dijalankan berdasarkan penggunaan CPU dari Pod.
kubectl autoscale deployment.v1.apps/nginx-deployment --min=10 --max=15 --cpu-percent=80
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment scaled
Pengaturan skala proporsional
Deployment RollingUpdate mendukung beberapa versi aplikasi berjalan secara bersamaan. Ketika kamu atau autoscaler mengubah skala Deployment RollingUpdate yang ada di tengah rilis (yang sedang berjalan maupun terjeda), kontroler Deployment menyeimbangkan replika tambahan dalam ReplicaSet aktif (ReplicaSet dengan Pod) untuk mencegah resiko. Ini disebut pengaturan skala proporsional.
Sebagai contoh, kamu menjalankan Deployment dengan 10 replika, maxSurge=3, dan maxUnavailable=2.
-
Pastikan ada 10 replica di Deployment-mu yang berjalan.
kubectl get deploy
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 10 10 10 10 50s
-
Ganti ke image baru yang kebetulan tidak bisa ditemukan dari dalam klaster.
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:sometag
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment image updated
-
Penggantian image akan memulai rilis baru dengan ReplicaSet nginx-deployment-1989198191, namun dicegah karena persyaratan
maxUnavailable
yang disebut di atas. Cek status rilis:kubectl get rs
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE nginx-deployment-1989198191 5 5 0 9s nginx-deployment-618515232 8 8 8 1m
-
Kemudian, permintaan peningkatan untuk Deployment akan masuk. Autoscaler menambah replika Deployment menjadi 15. Controller Deployment perlu menentukan dimana 5 replika ini ditambahkan. Jika kamu memakai pengaturan skala proporsional, kelima replika akan ditambahkan ke ReplicaSet baru. Dengan pengaturan skala proporsional, kamu menyebarkan replika tambahan ke semua ReplicaSet. Proporsi terbesar ada pada ReplicaSet dengan replika terbanyak dan proporsi yang lebih kecil untuk replika dengan ReplicaSet yang lebih sedikit. Sisanya akan diberikan ReplicaSet dengan replika terbanyak. ReplicaSet tanpa replika tidak akan ditingkatkan.
Dalam kasus kita di atas, 3 replika ditambahkan ke ReplicaSet lama dan 2 replika ditambahkan ke ReplicaSet baru. Proses rilis akan segera memindahkan semua ReplicaSet baru, dengan asumsi semua replika dalam kondisi sehat. Untuk memastikannya, jalankan:
kubectl get deploy
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 15 18 7 8 7m
Status rilis mengkonfirmasi bagaimana replika ditambahkan ke tiap ReplicaSet.
kubectl get rs
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 7 7 0 7m
nginx-deployment-618515232 11 11 11 7m
Menjeda dan Melanjutkan Deployment
Kamu dapat menjeda Deployment sebelum memicu satu atau lebih pembaruan kemudian meneruskannya. Hal ini memungkinkanmu menerapkan beberapa perbaikan selama selang jeda tanpa melakukan rilis yang tidak perlu.
-
Sebagai contoh, Deployment yang baru dibuat: Lihat detil Deployment:
kubectl get deploy
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 3 3 3 3 1m
Lihat status rilis:
kubectl get rs
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 1m
-
Jeda dengan menjalankan perintah berikut:
kubectl rollout pause deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment paused
-
Lalu ganti kolom image Deployment:
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment image updated
-
Perhatikan tidak ada rilis baru yang muncul:
kubectl rollout history deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
deployments "nginx" REVISION CHANGE-CAUSE 1 <none>
-
Lihat status rilis untuk memastikan Deployment berhasil diperbarui:
kubectl get rs
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 2m
-
Kamu bisa membuat pembaruan sebanyak yang kamu mau. Contohnya pembaruan sumber daya yang akan dipakai:
kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment resource requirements updated
The state awal Deployment sebelum jeda akan melanjutkan fungsinya, tapi perubahan Deployment tidak akan berefek apapun selama Deployment masih terjeda.
-
Kemudian, mulai kembali Deployment dan perhatikan ReplicaSet baru akan muncul dengan semua perubahan baru:
kubectl rollout resume deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment resumed
-
Perhatikan status rilis sampai selesai.
kubectl get rs -w
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE nginx-2142116321 2 2 2 2m nginx-3926361531 2 2 0 6s nginx-3926361531 2 2 1 18s nginx-2142116321 1 2 2 2m nginx-2142116321 1 2 2 2m nginx-3926361531 3 2 1 18s nginx-3926361531 3 2 1 18s nginx-2142116321 1 1 1 2m nginx-3926361531 3 3 1 18s nginx-3926361531 3 3 2 19s nginx-2142116321 0 1 1 2m nginx-2142116321 0 1 1 2m nginx-2142116321 0 0 0 2m nginx-3926361531 3 3 3 20s
-
Lihat status rilis terakhir:
kubectl get rs
Keluaran akan tampil seperti berikut:
NAME DESIRED CURRENT READY AGE nginx-2142116321 0 0 0 2m nginx-3926361531 3 3 3 28s
Status Deployment
Deployment melalui berbagai state dalam daur hidupnya. Dia dapat berlangsung selagi merilis ReplicaSet baru, bisa juga selesai, atau juga gagal.
Deployment Berlangsung
Kubernetes menandai Deployment sebagai progressing saat salah satu tugas di bawah dikerjakan:
- Deployment membuat ReplicaSet baru.
- Deployment menaikkan kapasitas ReplicaSet terbaru.
- Deployment menurunkan kapasitas ReplicaSet yang lebih lama.
- Pod baru menjadi siap atau dapat diakses (siap selama setidaknya MinReadySeconds).
Kamu dapat mengawasi perkembangan Deployment dengan kubectl rollout status
.
Deployment Selesai
Kubernetes menandai Deployment sebagai complete saat memiliki karakteristik berikut:
- Semua replika terkait Deployment telah diperbarui ke versi terbaru yang dispecify, artinya semua pembaruan yang kamu inginkan telah selesai.
- Semua replika terkait Deployment dapat diakses.
- Tidak ada replika lama untuk Deployment yang berjalan.
Kamu dapat mengecek apakah Deployment telah selesai dengan kubectl rollout status
.
Jika rilis selesai, kubectl rollout status
akan mengembalikan nilai balik nol.
kubectl rollout status deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out
$ echo $?
0
Deployment Gagal
Deployment-mu bisa saja terhenti saat mencoba deploy ReplicaSet terbaru tanpa pernah selesai. Ini dapat terjadi karena faktor berikut:
- Kuota tidak mencukupi
- Kegagalan pengecekan kesiapan
- Galat saat mengunduh image
- Tidak memiliki ijin
- Limit ranges
- Konfigurasi runtime aplikasi yang salah
Salah satu cara untuk mendeteksi kondisi ini adalah untuk menjelaskan parameter tenggat pada spesifikasi Deployment:
(.spec.progressDeadlineSeconds
). .spec.progressDeadlineSeconds
menyatakan
lama kontroler Deployment menunggu sebelum mengindikasikan (pada status Deployment) bahwa kemajuan Deployment
tersendat dalam detik.
Perintah kubectl
berikut menetapkan spek dengan progressDeadlineSeconds
untuk membuat kontroler
melaporkan kemajuan Deployment yang sedikit setelah 10 menit:
kubectl patch deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
Keluaran akan tampil seperti berikut:
deployment.apps/nginx-deployment patched
Ketika tenggat sudah lewat, kontroler Deployment menambah DeploymentCondition dengan atribut
berikut ke .status.conditions
milik Deployment:
- Type=Progressing
- Status=False
- Reason=ProgressDeadlineExceeded
Lihat konvensi Kubernetes API untuk info lebih lanjut tentang kondisi status.
Reason=ProgressDeadlineExceeded
.
Orkestrator yang lebih tinggi dapat memanfaatkannya untuk melakukan tindak lanjut. Misalnya, mengembalikan Deployment ke versi sebelumnya.
Kamu dapat mengalami galat sejenak pada Deployment disebabkan timeout yang dipasang terlalu kecil atau hal-hal lain yang terjadi sementara. Misalnya, kamu punya kuota yang tidak mencukupi. Jika kamu mendeskripsikan Deployment kamu akan menjumpai pada bagian ini:
kubectl describe deployment nginx-deployment
Keluaran akan tampil seperti berikut:
<...>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
ReplicaFailure True FailedCreate
<...>
Jika kamu menjalankan kubectl get deployment nginx-deployment -o yaml
, Deployment status akan muncul seperti berikut:
status:
availableReplicas: 2
conditions:
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: Replica set "nginx-deployment-4262182780" is progressing.
reason: ReplicaSetUpdated
status: "True"
type: Progressing
- lastTransitionTime: 2016-10-04T12:25:42Z
lastUpdateTime: 2016-10-04T12:25:42Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
object-counts, requested: pods=1, used: pods=3, limited: pods=2'
reason: FailedCreate
status: "True"
type: ReplicaFailure
observedGeneration: 3
replicas: 2
unavailableReplicas: 2
Begitu tenggat kemajuan Deployment terlewat, Kubernetes membarui status dan alasan untuk kondisi Progressing:
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
ReplicaFailure True FailedCreate
Kamu dapat menangani isu keterbatasan kuota dengan menurunkan jumlah Deployment, bisa dengan menghapus kontrolers
yang sedang berjalan, atau dengan meningkatkan kuota pada namespace. Jika kuota tersedia, kemudian kontroler Deployment
akan dapat menyelesaikan rilis Deployment. Kamu akan melihat bahwa status Deployment berubah menjadi kondisi sukses (Status=True
dan Reason=NewReplicaSetAvailable
).
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
Type=Available
dengan Status=True
artinya Deployment-mu punya ketersediaan minimum. Ketersediaan minimum diatur
oleh parameter yang dibuat pada strategi deployment. Type=Progressing
dengan Status=True
berarti Deployment
sedang dalam rilis dan masih berjalan atau sudah selesai berjalan dan jumlah minimum replika tersedia
(lihat bagian Alasan untuk kondisi tertentu - dalam kasus ini Reason=NewReplicaSetAvailable
berarti Deployment telah selesai).
Kamu dapat mengecek apakah Deployment gagal berkembang dengan perintah kubectl rollout status
. kubectl rollout status
mengembalikan nilai selain nol jika Deployment telah melewati tenggat kemajuan.
kubectl rollout status deployment.v1.apps/nginx-deployment
Keluaran akan tampil seperti berikut:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
$ echo $?
1
Menindak Deployment yang gagal
Semua aksi yang dapat diterapkan pada Deployment yang selesai berjalan juga pada Deployment gagal. Kamu dapat menaik/turunkan replika, membalikkan ke versi sebelumnya, atau menjedanya jika kamu perlu menerapkan beberapa perbaikan pada templat Pod Deployment.
Kebijakan Pembersihan
Kamu dapat mengisi kolom .spec.revisionHistoryLimit
di Deployment untuk menentukan banyak ReplicaSet
pada Deployment yang ingin dipertahankan. Sisanya akan di garbage-collected di balik layar. Umumnya, nilai kolom berisi 10.
Deployment Canary
Jika kamu ingin merilis ke sebagian pengguna atau server menggunakan Deployment, kamu dapat membuat beberapa Deployment, satu tiap rilis, dengan mengikuti pola canary yang didesripsikan pada mengelola sumber daya.
Menulis Spesifikasi Deployment
Sebagaimana konfigurasi Kubernetes lainnya, Deployment memerlukan kolom apiVersion
, kind
, dan metadata
.
Untuk informasi umum tentang penggunaan berkas konfigurasi, lihat dokumen deploy aplikasi,
mengatur kontainer, dan memakai kubectl untuk mengatur sumber daya.
Deployment juga perlu bagian .spec
.
Templat Pod
Dalam .spec
hanya ada kolom .spec.template
dan .spec.selector
yang wajib diisi.
.spec.template
adalah templat Pod. Dia memiliki skema yang sama dengan Pod. Bedanya dia bersarang dan tidak punya apiVersion
atau kind
.
Selain kolom wajib untuk Pod, templat Pod pada Deployment harus menentukan label dan aturan menjalankan ulang yang tepat. Untuk label, pastikaan tidak bertumpang tindih dengan kontroler lainnya. Lihat selektor).
.spec.template.spec.restartPolicy
hanya boleh berisi Always
,
yang tidak ditentukan pada bawaan.
Replika
.spec.replicas
adalah kolom opsional yang mengatur jumlah Pod yang diinginkan. Setelan bawaannya berisi 1.
Selektor
.spec.selector
adalah kolom wajib yang mengatur selektor label
untuk Pod yang dituju oleh Deployment ini.
.spec.selector
harus sesuai .spec.template.metadata.labels
, atau akan ditolak oleh API.
Di versi API apps/v1
, .spec.selector
dan .metadata.labels
tidak berisi .spec.template.metadata.labels
jika tidak disetel.
Jadi mereka harus disetel secara eksplisit. Perhatikan juga .spec.selector
tidak dapat diubah setelah Deployment dibuat pada apps/v1
.
Deployment dapat mematikan Pod yang labelnya cocok dengan selektor jika templatnya berbeda
dari .spec.template
atau total jumlah Pod melebihi .spec.replicas
. Dia akan membuat Pod baru
dengan .spec.template
jika jumlah Pod kurang dari yang diinginkan.
Jika kamu punya beberapa kontroler dengan selektor bertindihan, mereka akan saling bertikai dan tidak akan berjalan semestinya.
Strategi
.spec.strategy
mengatur strategi yang dipakai untuk mengganti Pod lama dengan yang baru.
.spec.strategy.type
dapat berisi "Recreate" atau "RollingUpdate". Nilai bawaannya adalah "RollingUpdate".
Membuat Ulang Deployment
Semua Pod yang ada dimatikan sebelum yang baru dibuat ketika nilai .spec.strategy.type==Recreate
.
Membarui Deployment secara Bergulir
Deployment membarui Pod secara bergulir
saat .spec.strategy.type==RollingUpdate
. Kamu dapat menentukan maxUnavailable
dan maxSurge
untuk mengatur
proses pembaruan bergulir.
Ketidaktersediaan Maksimum
.spec.strategy.rollingUpdate.maxUnavailable
adalah kolom opsional yang mengatur jumlah Pod maksimal
yang tidak tersedia selama proses pembaruan. Nilainya bisa berupa angka mutlak (contohnya 5)
atau persentase dari Pod yang diinginkan (contohnya 10%). Angka mutlak dihitung berdasarkan persentase
dengan pembulatan ke bawah. Nilai tidak bisa nol jika .spec.strategy.rollingUpdate.maxSurge
juga nol.
Nilai bawaannya yaitu 25%.
Sebagai contoh, ketika nilai berisi 30%, ReplicaSet lama dapat segera diperkecil menjadi 70% dari Pod yang diinginkan saat pembaruan bergulir dimulai. Seketika Pod baru siap, ReplicaSet lama dapat lebih diperkecil lagi, diikuti dengan pembesaran ReplicaSet, menjamin total jumlah Pod yang siap kapanpun ketika pembaruan paling sedikit 70% dari Pod yang diinginkan.
Kelebihan Maksimum
.spec.strategy.rollingUpdate.maxSurge
adalah kolom opsional yang mengatur jumlah Pod maksimal yang
dapat dibuat melebihi jumlah Pod yang diinginkan. Nilainya bisa berupa angka mutlak (contohnya 5) atau persentase
dari Pod yang diinginkan (contohnya 10%). Nilai tidak bisa nol jika MaxUnavailable
juga nol. Angka mutlak
dihitung berdasarkan persentase dengan pembulatan ke bawah. Nilai bawaannya yaitu 25%.
Sebagai contoh, ketika nilai berisi 30%, ReplicaSet baru dapat segera diperbesar saat pembaruan bergulir dimulai, sehingga total jumlah Pod yang baru dan lama tidak melebihi 130% dari Pod yang diinginkan. Saat Pod lama dimatikan, ReplicaSet baru dapat lebih diperbesar lagi, menjamin total jumlah Pod yang siap kapanpun ketika pembaruan paling banyak 130% dari Pod yang diinginkan.
Tenggat Kemajuan dalam Detik
.spec.progressDeadlineSeconds
adalah kolom opsional yang mengatur lama tunggu dalam dalam detik untuk Deployment-mu berjalan
sebelum sistem melaporkan lagi bahwa Deployment gagal - ditunjukkan dengan kondisi Type=Progressing
, Status=False
,
dan Reason=ProgressDeadlineExceeded
pada status sumber daya. Controller Deployment akan tetap mencoba ulang Deployment.
Nantinya begitu pengembalian otomatis diimplementasikan, kontroler Deployment akan membalikkan Deployment segera
saat dia menjumpai kondisi tersebut.
Jika ditentukan, kolom ini harus lebih besar dari .spec.minReadySeconds
.
Lama Minimum untuk Siap dalam Detik
.spec.minReadySeconds
adalah kolom opsional yang mengatur lama minimal sebuah Pod yang baru dibuat
seharusnya siap tanpa ada kontainer yang rusak, untuk dianggap tersedia, dalam detik.
Nilai bawaannya yaitu 0 (Pod akan dianggap tersedia segera ketika siap). Untuk mempelajari lebih lanjut
kapan Pod dianggap siap, lihat Pemeriksaan Kontainer.
Kembali Ke
Kolom .spec.rollbackTo
telah ditinggalkan pada versi API extensions/v1beta1
dan apps/v1beta1
, dan sudah tidak didukung mulai versi API apps/v1beta2
.
Sebagai gantinya, disarankan untuk menggunakan kubectl rollout undo
sebagaimana diperkenalkan dalam Kembali ke Revisi Sebelumnya.
Batas Riwayat Revisi
Riwayat revisi Deployment disimpan dalam ReplicaSet yang dia kendalikan.
.spec.revisionHistoryLimit
adalah kolom opsional yang mengatur jumlah ReplicaSet lama yang dipertahankan
untuk memungkinkan pengembalian. ReplicaSet lama ini mengambil sumber daya dari etcd
dan memunculkan keluaran
dari kubectl get rs
. Konfigurasi tiap revisi Deployment disimpan pada ReplicaSet-nya; sehingga, begitu ReplicaSet lama dihapus,
kamu tidak mampu lagi membalikkan revisi Deployment-nya. Umumnya, 10 ReplicaSet lama akan dipertahankan,
namun nilai idealnya tergantung pada frekuensi dan stabilitas Deployment-deployment baru.
Lebih spesifik, mengisi kolom dengan nol berarti semua ReplicaSet lama dengan 0 replika akan dibersihkan. Dalam kasus ini, rilis Deployment baru tidak dapat dibalikkan, sebab riwayat revisinya telah dibersihkan.
Terjeda
.spec.paused
adalah kolom boolean opsional untuk menjeda dan melanjutkan Deployment. Perbedaan antara Deployment yang terjeda
dan yang tidak hanyalah perubahan apapun pada PodTemplateSpec Deployment terjeda tidak akan memicu rilis baru selama masih terjeda.
Deployment umumnya tidak terjeda saat dibuat.
Alternatif untuk Deployment
kubectl rolling update
kubectl rolling update
membarui Pod dan ReplicationController
dengan cara yang serupa. Namun, Deployments lebih disarankan karena deklaratif, berjalan di sisi server, dan punya fitur tambahan,
seperti pembalikkan ke revisi manapun sebelumnya bahkan setelah pembaruan rolling selesais.
2.4 - StatefulSet
StatefulSet merupakan salah satu objek API workload yang digunakan untuk aplikasi stateful.
Melakukan proses manajemen deployment dan scaling dari sebuah set Pods, serta menjamin mekanisme ordering dan keunikan dari Pod ini.
Seperti halnya Deployment, sebuah StatefulSet akan melakukan proses manajemen Pod yang didasarkan pada spec container identik. Meskipun begitu tidak seperti sebuah Deployment, sebuah StatefulSet akan menjamin identitas setiap Pod yang ada. Pod ini akan dibuat berdasarkan spec yang sama, tetapi tidak dapat digantikan satu sama lainnya: setiap Pod memiliki identifier persisten yang akan di-maintain meskipun pod tersebut di (re)schedule.
Sebuah StatefulSet beroperasi dengan pola yang sama dengan Kontroler lainnya. Kamu dapat mendefinisikan state yang diinginkan pada objek StatefulSet, dan kontroler StatefulSet akan membuat update yang dibutuhkan dari state saat ini.
Menggunakan StatefulSet
StatefulSet akan sangat bermanfaat apabila digunakan untuk aplikasi yang membutuhkan salah satu atau beberapa fungsi berikut.
- Memiliki identitas jaringan unik yang stabil.
- Penyimpanan persisten yang stabil.
- Mekanisme scaling dan deployment yang graceful tertara berdasarkan urutan.
- Mekanisme rolling update yang otomatis berdasarkan urutan.
Stabil dalam poin-poin di atas memiliki arti yang sama dengan persisten pada Pod saat dilakukan (re)scheduling. Jika suatu aplikasi tidak membutuhkan identitas yang stabil atau deployment yang memiliki urutan, penghapusan, atau mekanisme scaling, kamu harus melakukan deploy aplikasi dengan controller yang menyediakan replika stateless. Controller seperti Deployment atau ReplicaSet akan lebih sesuai dengan kebutuhan kamu.
Keterbatasan
- StatefulSet merupakan sumber daya beta sebelum 1.9 dan tidak tersedia pada Kubernetes rilis sebelum versi 1.5.
- Penyimpanan untuk sebuah Pod harus terlebih dahulu di-provision dengan menggunakan sebuah Provisioner PersistentVolume berdasarkan
storage class
yang dispesifikasikan, atau sudah ditentukan sebelumnya oleh administrator. - Menghapus dan/atau scaling sebuah StatefulSet tidak akan menghapus volume yang berkaitan dengan StatefulSet tersebut. Hal ini dilakukan untuk menjamin data yang disimpan, yang secara umum dinilai lebih berhaga dibandingkan dengan mekanisme penghapusan data secara otomatis pada sumber daya terkait.
- StatefulSet saat ini membutuhkan sebuah Headless Service yang nantinya akan bertanggung jawab terhadap pada identitas jaringan pada Pod. Kamulah yang bertanggung jawab untuk membuat Service tersebut.
- StatefulSet tidak menjamin terminasi Pod ketika sebuah StatefulSet dihapus. Untuk mendapatkan terminasi Pod yang terurut dan graceful pada StatefulSet, kita dapat melakukan scale down Pod ke 0 sebelum penghapusan.
- Ketika menggunakan Rolling Update dengan
Kebijakan Manajemen Pod (
OrderedReady
) secara default, hal ini memungkinkan untuk mendapatkan state yang lebih terperinci yang membutuhkan mekanisme intervensi manual untuk perbaikan.
Komponen-Komponen
Contoh di bawah ini akna menunjukkan komponen-komponen penyusun StatefulSet.
- Sebuah Service Headless, dengan nama nginx, digunakan untuk mengontrol domain jaringan.
- StatefulSet, dengan nama web, memiliki Spek yang mengindikasikan terdapat 3 replika Container yang akan dihidupkan pada Pod yang unik.
- Field
volumeClaimTemplates
akan menyediakan penyimpanan stabil menggunakan PersistentVolume yang di-provision oleh sebuah Provisioner PersistentVolume.
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # harus sesuai dengan .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # nilai default-nya adalah 1
template:
metadata:
labels:
app: nginx # harus sesuai dengan .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
Selector Pod
Kamu harus menspesifikasikan field .spec.selector
dari sebuah StatefulSet untuk menyesuaikan dengan label yang ada pada .spec.template.metadata.labels
. Sebelum Kubernetes 1.8, field .spec.selector
dapat diabaikan. Sejak versi 1.8 dan versi selanjutnya, apabila tidak terdapat selector Pod yang sesuai maka akan menghasilkan eror pada validasi pembuatan StatefulSet.
Identitas Pod
Pod pada StatefulSet memiliki identitas unik yang tersusun berdasarkan skala ordinal, sebuah identitas jaringan yang stabil, serta penyimpanan yang stabil. Identitas yang ada pada Pod ini akan tetap melekat, meskipun Pod tersebut dilakukan (re)schedule pada Node yang berbeda.
Indeks Ordinal
Untuk sebuah StatefulSet dengan N buah replika, setiap Pod di dalam StatefulSet akan diberi nama pada suatu indeks ordinal tertentu, dari 0 hingga N-1, yang unik pada Set ini.
ID Jaringan yang Stabil
Setiap Pod di dalam StatefulSet memiliki hostname diturunkan dari nama SatetulSet tersebut
serta ordinal Pod tersebut. Pola pada hostname yang terbentuk adalah
$(statefulset name)-$(ordinal)
. Contoh di atas akan menghasilkan tiga Pod
dengan nama web-0,web-1,web-2
.
Sebuah StatefulSet dapat menggunakan sebuah Service Headless
untuk mengontrol domain dari Pod yang ada. Domain yang diatur oleh Service ini memiliki format:
$(service name).$(namespace).svc.cluster.local
, dimana "cluster.local" merupakan
domain klaster.
Seiring dibuatnya setiap Pod, Pod tersebut akan memiliki subdomain DNS-nya sendiri, yang memiliki format:
$(podname).$(governing service domain)
, dimana Service yang mengatur didefinisikan oleh
field serviceName
pada StatefulSet.
Seperti sudah disebutkan di dalam bagian keterbatasan, kamulah yang bertanggung jawab untuk membuat Service Headless yang bertanggung jawab terhadap identitas jaringan pada Pod.
Di sini terdapat beberapa contoh penggunaan Domain Klaster, nama Service, nama StatefulSet, dan bagaimana hal tersebut berdampak pada nama DNS dari Pod StatefulSet.
Domain Klaster | Service (ns/nama) | StatefulSet (ns/nama) | Domain StatefulSet | DNS Pod | Hostname Pod |
---|---|---|---|---|---|
cluster.local | default/nginx | default/web | nginx.default.svc.cluster.local | web-{0..N-1}.nginx.default.svc.cluster.local | web-{0..N-1} |
cluster.local | foo/nginx | foo/web | nginx.foo.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.cluster.local | web-{0..N-1} |
kube.local | foo/nginx | foo/web | nginx.foo.svc.kube.local | web-{0..N-1}.nginx.foo.svc.kube.local | web-{0..N-1} |
cluster.local
kecuali
nilainya dikonfigurasi.
Penyimpanan Stabil
Kubernetes membuat sebuah PersistentVolume untuk setiap
VolumeClaimTemplate. Pada contoh nginx di atas, setiap Pod akan menerima sebuah PersistentVolume
dengan StorageClass my-storage-class
dan penyimpanan senilai 1 Gib yang sudah di-provisioning. Jika tidak ada StorageClass
yang dispesifikasikan, maka StorageClass default akan digunakan. Ketika sebuah Pod dilakukan (re)schedule
pada sebuah Node, volumeMounts
akan me-mount PersistentVolumes yang terkait dengan
PersistentVolume Claim-nya. Perhatikan bahwa, PersistentVolume yang terkait dengan
PersistentVolumeClaim dari Pod tidak akan dihapus ketika Pod, atau StatefulSet dihapus.
Penghapusan ini harus dilakukan secara manual.
Label Pod Name
Ketika sebuah controller StatefulSet membuat sebuah Pod, controller ini akan menambahkan label, statefulset.kubernetes.io/pod-name
,
yang akan diaktifkan pada nama Pod. Label ini akan mengizinkan kamu untuk meng-attach sebuah Service pada Pod spesifik tertentu.
di StatefulSet.
Jaminan Deployment dan Mekanisme Scaling
- Untuk sebuah StatefulSet dengan N buah replika, ketika Pod di-deploy, Pod tersebut akan dibuat secara berurutan dengan urutan nilai {0..N-1}.
- Ketika Pod dihapus, Pod tersebut akan dihentikan dengan urutan terbalik, yaitu {N-1..0}.
- Sebelum operasi scaling diaplikasikan pada sebuah Pod, semua Pod sebelum Pod tersebut haruslah sudah dalam status Running dan Ready.
- Sebelum sebuah Pod dihentikan, semua Pod setelah Pod tersebut haruslah sudah terlebih dahulu dihentikan.
StatefulSet tidak boleh menspesifikasikan nilai dari pod.Spec.TerminationGracePeriodSeconds
menjadi 0. Hal ini tidaklah aman dan tidak disarankan. Untuk penjelasan lebih lanjut, silakan lihat penghapusan paksa Pod pada StatefulSet.
Ketika contoh nginx di atas dibuat, tiga Pod akan di-deploy dengan urutan web-0, web-1, web-2. web-1 tidak akan di-deploy sebelum web-0 berada dalam status Running dan Ready, dan web-2 tidak akan di-deploy sebelum web-1 berada dalam status Running dan Ready. Jika web-0 gagal, setelah web-1 berada dalam status Running and Ready, tapi sebelum web-2 dibuat, maka web-2 tidak akan dibuat hingga web-0 sukses dibuat ulang dan berada dalam status Running dan Ready.
Jika seorang pengguna akan melakukan mekanisme scale pada contoh di atas dengan cara melakukan patch,
pada StatefulSet sehingga replicas=1
, maka web-2 akan dihentikan terlebih dahulu.
web-1 tidak akan dihentikan hingga web-2 benar-benar berhenti dan dihapus.
Jika web-0 gagal setelah web-2 diterminasi dan berada dalam status mati,
tetapi sebelum web-1 dihentikan, maka web-1 tidak akan dihentikan hingga
web-0 berada dalam status Running dan Ready.
Kebijakan Manajemen Pod
Pada Kubernetes versi 1.7 dan setelahnya, StatefulSet mengizinkan kamu untuk
melakukan mekanisme urutan tadi menjadi lebih fleksibel dengan tetap
menjamin keunikan dan identitas yang ada melalui field .spec.podManagementPolicy
.
Manajemen OrderedReady pada Pod
Manajemen OrderedReady
pada Pod merupakan nilai default dari StatefulSet.
Hal ini akan mengimplementasikan perilaku yang dijelaskan di atas.
Manajemen Pod secara Paralel
Manajemen Pod secara paralel
akan menyebabkan kontroler StatefulSet untuk
memulai atau menghentikan semua Pod yang ada secara paralel, dan tidak
menunggu Pod berada dalam status Running dan Ready atau sudah dihentikan secara menyeluruh
sebelum me-launch atau menghentikan Pod yang lain. Opsi ini hanya akan memengaruhi operasi
scaling. Operasi pembaruan tidak akan terpengaruh.
Strategi Update
Pada Kubernetes versi 1.7 dan setelahnya, field .spec.updateStrategy
pada StatefulSet
memungkinkan-mu untuk melakukan konfigurasi dan menonaktifkan otomatisasi
rolling updates untuk container, label, resource request/limits, dan
annotation pada Pod yang ada di dalam sebuah StatefulSet.
Mekanisme Strategi Update On Delete
Mekanisme strategi update OnDelete
mengimplementasikan perilaku legasi (versi 1.6 dan sebelumnya).
Ketika sebuah field .spec.updateStrategy.type
pada StatefulSet diubah menjadi OnDelete
maka kontroler StatefulSet tidak akan secara otomatis melakukan update
pada Pod yang ada di dalam StatefulSet tersebut. Pengguna haruslah secara manual
melakukan penghapusan Pod agar kontroler membuat Pod baru yang mengandung modifikasi
yang dibuat pada field .spec.template
StatefulSet.
Mekanisme Strategi Update Rolling Updates
Mekanisme strategi update RollingUpdate
mengimplementasikan otomatisasi rolling update
untuk Pod yang ada pada StatefulSet. Strategi inilah yang diterapkan ketika .spec.updateStrategy
tidak dispesifikasikan.
Ketika field .spec.updateStrategy.type
diubah nilainya menjadi RollingUpdate
, maka
kontroler StatefulSet akan menghapus dan membuat setiap Pod di dalam StatefulSet. Kemudian
hal ini akan diterapkan dengan urutan yang sama dengan mekanisme terminasi Pod (dari nilai ordinal terbesar ke terkecil),
yang kemudian akan melakukan update Pod satu per satu. Mekanisme ini akan memastikan sebuah Pod yang di-update
berada dalam status Running dan Ready sebelum meng-update Pod dengan nilai ordinal lebih rendah.
Mekanisme Strategi Update dengan Partisi
Mekanisme strategi update RollingUpdate
dapat dipartisi, dengan cara menspesifikasikan nilai
dari .spec.updateStrategy.rollingUpdate.partition
. Jika nilai dari field ini dispesifikasikan,
maka semua Pod dengan nilai ordinal yang lebih besar atau sama dengan nilai partisi akan diupdate ketika
nilai .spec.template
pada StatefulSet diubah. Semua Pod dengan nilai ordinal yang lebih kecil
dari partisi tidak akan diupdate, dan, bahkan setelah Pod tersebut dihapus, Pod ini akan digantikan
dengan Pod versi sebelumnya. Jika nilai .spec.updateStrategy.rollingUpdate.partition
lebih besar dari
nilai .spec.replicas
, update pada .spec.template
tidak akan dipropagasi pada Pod-Pod-nya.
Pada sebagian besar kasus, kamu tidak akan perlu menggunakan partisi, tapi hal tersebut
akan sangat berguna apabila kamu ingin mekakukan mekanisme update canary.
Mekanisme Strategi Update yang Dipaksa (Forced Rollback)
Ketika menggunakan strategi update Rolling Updates dengan nilai default
Kebijakan Manajemen Pod (OrderedReady
),
hal ini memungkinkan adanya kondisi broken yang membutuhkan intervensi secara manual
agar kondisi ini dapat diperbaiki.
Jika kamu melakukan update pada template Pod untuk konfigurasi yang tidak pernah berada dalam status Running dan Ready (sebagai contohnya, apabila terdapat kode binary yang buruk atau error pada konfigurasi di level aplikasi), maka StatefulSet akan menghentikan proses rollout dan berada dalam status wait.
Dalam kondisi ini, maka templat Pod tidak akan diubah secara otomatis pada konfigurasi sebelumnya Hal ini terjadi karena adanya isu, StatefulSet akan tetap berada dalam kondisi wait untuk menunggu Pod yang bermasalah untuk menjadi Ready (yang tidak akan terjadi) dan sebelum StatefulSet ini berusaha untuk melakukan revert pada konfigurasi sebelumnya.
Setelah melakukan mekanisme revert templat, kamu juga harus menghapus semua Pod di dalam StatefulSet tersebut yang telah berusaha untuk menggunakan konfigurasi yang broken. StatefulSet akan mulai membuat Pod dengan templat konfigurasi yang sudah di-revert.
Selanjutnya
- Ikuti contoh yang ada pada bagaimana cara melakukan deployi aplikasi stateful.
- Ikuti contoh yang ada pada bagaimana cara melakukan deploy Cassandra dengan StatefulSets.
2.5 - DaemonSet
DaemonSet memastikan semua atau sebagian Node memiliki salinan sebuah Pod. Ketika Node baru ditambahkan ke klaster, Pod ditambahkan ke Node tersebut. Ketika Node dihapus dari klaster, Pod akan dibersihkan oleh garbage collector. Menghapus DaemonSet akan menghapus semua Pod yang ia buat.
Beberapa penggunaan umum DaemonSet, yaitu:
- menjalankan daemon penyimpanan di klaster, seperti
glusterd
,ceph
, di setiap Node. - menjalankan daemon pengumpulan log di semua Node, seperti
fluentd
ataulogstash
. - menjalankan daemon pemantauan Node di setiap Node, seperti Prometheus Node Exporter, Flowmill, Sysdig Agent,
collectd
, Dynatrace OneAgent, AppDynamics Agent, Datadog agent, New Relic agent, Gangliagmond
atau Instana Agent.
Dalam kasus sederhana, satu DaemonSet, mencakup semua Node, akan digunakan untuk setiap jenis daemon. Pengaturan yang lebih rumit bisa saja menggunakan lebih dari satu DaemonSet untuk satu jenis daemon, tapi dengan flag dan/atau permintaan cpu/memori yang berbeda untuk jenis hardware yang berbeda.
Menulis Spek DaemonSet
Buat DaemonSet
Kamu bisa definisikan DaemonSet dalam berkas YAML. Contohnya, berkas
daemonset.yaml
di bawah mendefinisikan DaemonSet yang menjalankan image Docker
fluentd-elasticsearch:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- Buat DaemonSet berdasarkan berkas YAML:
kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml
Field Wajib
Seperti semua konfigurasi Kubernetes lainnya, DaemonSet membutuhkan field
apiVersion
, kind
, dan metadata
. Untuk informasi umum tentang berkas konfigurasi, lihat dokumen men-deploy aplikasi,
pengaturan kontainer, dan pengelolaan objek dengan kubectl.
DaemonSet juga membutuhkan bagian .spec
.
Templat Pod
.spec.template
adalah salah satu field wajib di dalam .spec
.
.spec.template
adalah sebuah templat Pod. Skemanya benar-benar sama dengan Pod, kecuali bagian bahwa ia bersarang/nested dan tidak memiliki apiVersion
atau kind
.
Selain field wajib untuk Pod, templat Pod di DaemonSet harus menspesifikasikan label yang sesuai (lihat selektor Pod).
Templat Pod di DaemonSet harus memiliki RestartPolicy
yang bernilai Always
, atau tidak dispesifikasikan, sehingga default menjadi Always
.
DaemonSet dengan nilai Always
membuat Pod akan selalu di-restart saat kontainer
keluar/berhenti atau terjadi crash.
Selektor Pod
Field .spec.selector
adalah selektor Pod. Cara kerjanya sama dengan .spec.selector
pada Job.
Pada Kubernetes 1.8, kamu harus menspesifikasikan selektor Pod yang cocok dengan label pada .spec.template
.
Selektor Pod tidak akan lagi diberi nilai default ketika dibiarkan kosong. Nilai default selektor tidak
cocok dengan kubectl apply
. Juga, sesudah DaemonSet dibuat, .spec.selector
tidak dapat diubah.
Mengubah selektor Pod dapat menyebabkan Pod orphan yang tidak disengaja, dan membingungkan pengguna.
Objek .spec.selector
memiliki dua field:
matchLabels
- bekerja seperti.spec.selector
pada ReplicationController.matchExpressions
- bisa digunakan untuk membuat selektor yang lebih canggih dengan mendefinisikan key, daftar value dan operator yang menyatakan hubungan antara key dan value.
Ketika keduanya dispesifikasikan hasilnya diperoleh dari operasi AND.
Jika .spec.selector
dispesifikasikan, nilainya harus cocok dengan .spec.template.metadata.labels
. Konfigurasi yang tidak cocok akan ditolak oleh API.
Selain itu kamu tidak seharusnya membuat Pod apapun yang labelnya cocok dengan selektor tersebut, entah secara langsung, via DaemonSet lain, atau via workload resource lain seperti ReplicaSet. Jika kamu coba buat, Pengontrol DaemonSet akan berpikir bahwa Pod tersebut dibuat olehnya. Kubernetes tidak akan menghentikan kamu melakukannya. Contoh kasus di mana kamu mungkin melakukan ini dengan membuat Pod dengan nilai yang berbeda di sebuah Node untuk testing.
Menjalankan Pod di Sebagian Node
Jika kamu menspesifikasikan .spec.template.spec.nodeSelector
, maka controller DaemonSet akan
membuat Pod pada Node yang cocok dengan selektor
Node. Demikian juga, jika kamu menspesifikasikan .spec.template.spec.affinity
,
maka controller DaemonSet akan membuat Pod pada Node yang cocok dengan Node affinity.
Jika kamu tidak menspesifikasikan sama sekali, maka controller DaemonSet akan
membuat Pod pada semua Node.
Bagaimana Pod Daemon Dijadwalkan
Dijadwalkan oleh default scheduler
Kubernetes 1.17 [stable]
DaemonSet memastikan bahwa semua Node yang memenuhi syarat menjalankan salinan Pod. Normalnya, Node yang menjalankan Pod dipilih oleh scheduler Kubernetes. Namun, Pod DaemonSet dibuat dan dijadwalkan oleh controller DaemonSet. Hal ini mendatangkan masalah-masalah berikut:
- Inkonsistensi perilaku Pod: Pod normal yang menunggu dijadwalkan akan dibuat
dalam keadaan
Pending
, tapi Pod DaemonSet tidak seperti itu. Ini membingungkan untuk pengguna. - Pod preemption ditangani oleh default scheduler. Ketika preemption dinyalakan, controller DaemonSet akan membuat keputusan penjadwalan tanpa memperhitungkan prioritas Pod dan preemption.
ScheduleDaemonSetPods
mengizinkan kamu untuk menjadwalkan DaemonSet
menggunakan default scheduler daripada controller DaemonSet, dengan
menambahkan syarat NodeAffinity
pada Pod DaemonSet daripada syarat
.spec.nodeName
. Kemudian, default scheduler digunakan untuk mengikat Pod ke
host target. Jika afinitas Node dari Pod DaemonSet sudah ada, maka ini
akan diganti. Controller DaemonSet hanya akan melakukan operasi-operasi ini
ketika membuat atau mengubah Pod DaemonSet, dan tidak ada perubahan yang terjadi
pada spec.template
DaemonSet.
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
Sebagai tambahan, toleration node.kubernetes.io/unschedulable:NoSchedule
ditambahkan secara otomatis pada Pod DaemonSet. Default scheduler akan
mengabaikan Node unschedulable
ketika menjadwalkan Pod DaemonSet.
Taint dan Toleration
Meskipun Pod Daemon menghormati taint dan toleration, toleration berikut ini akan otomatis ditambahkan ke Pod DaemonSet sesuai dengan fitur yang bersangkutan.
Toleration Key | Effect | Versi | Deskripsi |
---|---|---|---|
node.kubernetes.io/not-ready |
NoExecute | 1.13+ | Pod DaemonSet tidak akan menjadi evicted ketika ada masalah Node seperti partisi jaringan. |
node.kubernetes.io/unreachable |
NoExecute | 1.13+ | Pod DaemonSet tidak akan menjadi evicted ketika ada masalah Node seperti partisi jaringan. |
node.kubernetes.io/disk-pressure |
NoSchedule | 1.8+ | |
node.kubernetes.io/memory-pressure |
NoSchedule | 1.8+ | |
node.kubernetes.io/unschedulable |
NoSchedule | 1.12+ | Pod DaemonSet mentoleransi atribut unschedulable default scheduler. |
node.kubernetes.io/network-unavailable |
NoSchedule | 1.12+ | Pod DaemonSet yang menggunakan jaringan host mentoleransi atribut network-unavailable default scheduler. |
Berkomunikasi dengan Pod Daemon
Beberapa pola yang mungkin digunakan untuk berkomunikasi dengan Pod dalam DaemonSet, yaitu:
- Push: Pod dalam DaemonSet diatur untuk mengirim pembaruan status ke servis lain, contohnya stats database. Pod ini tidak memiliki klien.
- IP Node dan Konvensi Port: Pod dalam DaemonSet dapat menggunakan
hostPort
, sehingga Pod dapat diakses menggunakan IP Node. Klien tahu daftar IP Node dengan suatu cara, dan tahu port berdasarkan konvensi. - DNS: Buat headless service dengan Pod selektor yang sama,
dan temukan DaemonSet menggunakan resource
endpoints
atau mengambil beberapa A record dari DNS. - Service: Buat Servis dengan Pod selektor yang sama, dan gunakan Servis untuk mengakses daemon pada Node random. (Tidak ada cara mengakses spesifik Node)
Melakukan Pembaruan DaemonSet
Jika label Node berubah, DaemonSet akan menambahkan Pod ke Node cocok yang baru dan menghapus Pod dari Node tidak cocok yang baru.
Kamu bisa mengubah Pod yang dibuat DaemonSet. Namun, Pod tidak membolehkan perubahan semua field. Perlu diingat, controller DaemonSet akan menggunakan templat yang asli di waktu selanjutnya Node baru (bahkan dengan nama yang sama) dibuat.
Kamu bisa menghapus DaemonSet. Jika kamu spesifikasikan --cascade=false
dengan kubectl
, maka
Pod akan dibiarkan pada Node. Jika kamu pada waktu kemudian membuat DaemonSet baru dengan selektor
yang sama, DaemonSet yang baru akan mengadopsi Pod yang sudah ada. Jika ada Pod yang perlu diganti,
DaemonSet akan mengganti sesuai dengan updateStrategy
.
Kamu bisa melakukan rolling update pada DaemonSet.
Alternatif DaemonSet
Init Scripts
Kamu mungkin menjalankan proses daemon dengan cara menjalankan mereka langsung pada Node (e.g.
menggunakan init
, upstartd
, atau systemd
). Tidak ada salahnya seperti itu. Namun, ada beberapa
keuntungan menjalankan proses daemon via DaemonSet.
- Kemampuan memantau dan mengatur log daemon dengan cara yang sama dengan aplikasi.
- Bahasa dan alat Konfigurasi yang sama (e.g. Templat Pod,
kubectl
) untuk daemon dan aplikasi. - Menjalankan daemon dalam kontainer dengan batasan resource meningkatkan isolasi antar daemon dari kontainer aplikasi. Namun, hal ini juga bisa didapat dengan menjalankan daemon dalam kontainer tapi tanpa Pod (e.g. dijalankan langsung via Docker).
Pod Polosan
Dimungkinkan untuk membuat Pod langsung dengan menspesifikasikan Node mana untuk dijalankan. Namun, DaemonSet akan menggantikan Pod yang untuk suatu alasan dihapus atau dihentikan, seperti pada saat kerusakan Node atau pemeliharaan Node yang mengganggu seperti pembaruan kernel. Oleh karena itu, kamu perlu menggunakan DaemonSet daripada membuat Pod satu per satu.
Pod Statis
Dimungkinkan untuk membuat Pod dengan menulis sebuah berkas ke direktori tertentu yang di-watch oleh Kubelet. Pod ini disebut dengan istilah Pod statis. Berbeda dengan DaemonSet, Pod statis tidak dapat dikelola menggunakan kubectl atau klien API Kubernetes yang lain. Pod statis tidak bergantung kepada apiserver, membuat Pod statis berguna pada kasus-kasus bootstrapping klaster.
Deployment
DaemonSet mirip dengan Deployment sebab mereka sama-sama membuat Pod, dan Pod yang mereka buat punya proses yang seharusnya tidak berhenti (e.g. peladen web, peladen penyimpanan)
Gunakan Deployment untuk layanan stateless, seperti frontend, di mana proses scaling naik dan turun jumlah replika dan rolling update lebih penting daripada mengatur secara tepat di host mana Pod berjalan. Gunakan DaemonSet ketika penting untuk satu salinan Pod selalu berjalan di semua atau sebagian host, dan ketika Pod perlu berjalan sebelum Pod lainnya.
2.6 - Garbage Collection
Peran daripada garbage collector Kubernetes adalah untuk menghapus objek tertentu yang sebelumnya mempunyai pemilik, tetapi tidak lagi mempunyai pemilik.
Pemilik dan dependen
Beberapa objek Kubernetes adalah pemilik dari objek lainnya. Sebagai contoh, sebuah ReplicaSet adalah pemilik dari sekumpulan Pod. Objek-objek yang dimiliki disebut dependen dari objek pemilik. Setiap objek dependen memiliki sebuah kolom metadata.ownerReferences
yang menunjuk ke objek pemilik.
Terkadang, Kubernetes menentukan nilai dari ownerReference
secara otomatis. Sebagai contoh, ketika kamu membuat sebuah ReplicaSet, Kubernetes secara otomatis akan menentukan tiap kolom ownerReference
dari tiap Pod di dalam ReplicaSet. Pada versi 1.8, Kubernetes secara otomatis menentukan nilai dari ownerReference
untuk objek yang diciptakan atau diadopsi oleh ReplicationController, ReplicaSet, StatefulSet, DaemonSet, Deployment, Job dan CronJob.
Kamu juga bisa menspesifikasikan hubungan antara pemilik dan dependen dengan cara menentukan kolom ownerReference
secara manual.
Berikut adalah berkas untuk sebuah ReplicaSet yang memiliki tiga Pod:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: my-repset
spec:
replicas: 3
selector:
matchLabels:
pod-is-for: garbage-collection-example
template:
metadata:
labels:
pod-is-for: garbage-collection-example
spec:
containers:
- name: nginx
image: nginx
Jika kamu membuat ReplicaSet tersebut dan kemudian melihat metadata Pod, kamu akan melihat kolom OwnerReferences:
kubectl apply -f https://k8s.io/examples/controllers/replicaset.yaml
kubectl get pods --output=yaml
Keluaran menunjukkan bahwa pemilik Pod adalah sebuah ReplicaSet bernama my-repset
:
apiVersion: v1
kind: Pod
metadata:
...
ownerReferences:
- apiVersion: apps/v1
controller: true
blockOwnerDeletion: true
kind: ReplicaSet
name: my-repset
uid: d9607e19-f88f-11e6-a518-42010a800195
...
Referensi pemilik lintas namespace tidak diperbolehkan oleh desain. Artinya:
- Dependen dengan cakupan namespace hanya bisa menspesifikasikan pemilik jika berada di namespace yang sama, dan pemilik memiliki cakupan klaster.
- Dependen dengan cakupan klaster hanya bisa menspesifikasikan pemilik yang memiliki cakupan klaster, tetapi tidak berlaku untuk pemilik yang memiliki cakupan klaster.
Mengontrol bagaimana garbage collector menghapus dependen
Ketika kamu menghapus sebuah objek, kamu bisa menspesifikasi apakah dependen objek tersebut juga dihapus secara otomatis. Menghapus dependen secara otomatis disebut cascading deletion. Cascading deletion memiliki dua mode: background dan foreground.
Foreground cascading deletion
Pada foreground cascading deletion, pertama objek utama akan memasuki keadaan "deletion in progress". Pada saat keadaan "deletion in progress", kondisi-kondisi berikut bernilai benar:
- Objek masih terlihat via REST API
deletionTimestamp
objek telah ditentukanmetadata.finalizers
objek memiliki nilaiforegroundDeletion
.
Ketika dalam keadaan "deletion in progress", garbage collector menghapus dependen dari objek. Ketika garbage collector telah menghapus semua "blocking" dependen (objek dengan ownerReference.blockOwnerDeleteion=true
), garbage collector menghapus objek pemilik.
Jika kolom ownerReferences
sebuah objek ditentukan oleh sebuah controller (seperti Deployment atau Replicaset), blockOwnerDeletion
akan ditentukan secara otomatis dan kamu tidak perlu memodifikasi kolom ini secara manual.
Background cascading deletion
Pada background cascading deletion, Kubernetes segera menghapus objek pemilik dan garbage collector kemudian menghapus dependen pada background.
Mengatur kebijakan cascading deletion
Untuk mengatur kebijakan cascading deletion, tambahkan kolom propagationPolicy
pada argumen deleteOptions
ketika menghapus sebuah Object. Nilai yang dapat digunakan adalah "Orphan", "Foreground", atau "Background".
Sebelum Kubernetes 1.9, kebijakan default dari garbage collection untuk banyak resource controller adalah orphan. Ini meliputi ReplicationController, ReplicaSet, StatefulSet, DaemonSet, dan Deployment. Untuk jenis pada kelompok versi extensions/v1beta1
, apps/v1beta1
, dan apps/v1beta2
, kecuali kamu menspesifikasikan dengan cara lain, objek dependen adalah orphan secara default. Pada Kubernetes 1.9, untuk semua jenis pada kelompok versi apps/v1
, objek dependen dihapus secara default.
Berikut sebuah contoh yang menghapus dependen di background:
kubectl proxy --port=8080
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \
-H "Content-Type: application/json"
Berikut adalah sebuah contoh yang mengapus dependen di foreground:
kubectl proxy --port=8080
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
-H "Content-Type: application/json"
Berikut adalah contoh orphan yang dependen:
kubectl proxy --port=8080
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
-H "Content-Type: application/json"
kubectl juga mendukung cascading deletion. Untuk menghapus dependen secara otomatis dengan menggunakan kubectl, Ubah nilai --cascade
menjadi true. Untuk orphan yang dependen, ubah nilai --cascade
menjadi false. Nilai default untuk --cascade
adalah true.
Berikut adalah contoh yang membuat dependen ReplicaSet menjadi orphan:
kubectl delete replicaset my-repset --cascade=false
Catatan tambahan untuk Deployment
Sebelum versi 1.7, ketika menggunakan cascading delete dengan Deployment, kamu harus menggunakan propagationPolicy: Foreground
untuk menghapus tidak hanya ReplicaSet yang telah diciptakan, tetapi juga Pod yang mereka miliki. Jika tipe propagationPolicy tidak digunakan, hanya ReplicaSet yag akan dihapus, dan Pod akan menjadi orphan. Lihat kubeadm/#149 untuk informasi lebih lanjut.
Isu yang diketahui
Ditemukan pada #26120
Selanjutnya
2.7 - Pengendali TTL untuk Sumber Daya yang Telah Selesai Digunakan
Kubernetes v1.12 [alpha]
Pengendali TTL menyediakan mekanisme TTL yang membatasi umur dari suatu objek sumber daya yang telah selesai digunakan. Pengendali TTL untuk saat ini hanya menangani Jobs, dan nantinya bisa saja digunakan untuk sumber daya lain yang telah selesai digunakan misalnya saja Pod atau sumber daya khusus (custom resource) lainnya.
Peringatan Fitur Alpha: fitur ini tergolong datam fitur alpha dan dapat diaktifkan dengan
feature gate
TTLAfterFinished
.
Pengendali TTL
Pengendali TTL untuk saat ini hanya mendukung Job. Sebuah operator klaster
dapat menggunakan fitur ini untuk membersihkan Job yang telah dieksekusi (baik
Complete
atau Failed
) secara otomatis dengan menentukan field
.spec.ttlSecondsAfterFinished
pada Job, seperti yang tertera di
contoh.
Pengendali TTL akan berasumsi bahwa sebuah sumber daya dapat dihapus apabila
TTL dari sumber daya tersebut telah habis. Proses dihapusnya sumber daya ini
dilakukan secara berantai, dimana sumber daya lain yang
berkaitan akan ikut terhapus. Perhatikan bahwa ketika sebuah sumber daya dihapus,
siklus hidup yang ada akan menjaga bahwa finalizer akan tetap dijalankan sebagaimana mestinya.
Waktu TTL dalam detik dapat diatur kapan pun. Terdapat beberapa contoh untuk mengaktifkan field
.spec.ttlSecondsAfterFinished
pada suatu Job:
- Spesifikasikan field ini pada manifest sumber daya, sehingga Job akan dihapus secara otomatis beberapa saat setelah selesai dieksekusi.
- Aktifkan field ini pada sumber daya yang sudah selesai dieksekusi untuk menerapkan fitur ini.
- Gunakan sebuah mengubah (mutating) _admission) untuk mengaktifkan field ini secara dinamis pada saat pembuatan sumber daya. Administrator klaster dapat menggunakan hal ini untuk menjamin kebijakan (policy) TTL pada sumber daya yang telah selesai digunakan.
- Gunakan sebuah mengubah (mutating) _admission untuk mengaktifkan field ini secara dinamis setelah sumber daya selesai digunakan dan TTL didefinisikan sesuai dengan status, label, atau hal lain yang diinginkan.
Peringatan
Mengubah TTL Detik
Perhatikan bahwa periode TTL, yaitu field .spec.ttlSecondsAfterFinished
pada Job,
dapat dimodifikasi baik setelah sumber daya dibuat atau setelah selesai digunakan.
Meskipun begitu, setelah Job dapat dihapus (TTL sudah habis), sistem tidak akan
menjamin Job tersebut akan tetap ada, meskipun nilai TTL berhasil diubah.
Time Skew
Karena pengendali TTL menggunakan cap waktu (timestamp) yang disimpan di sumber daya Kubernetes untuk menentukan apakah TTL sudah habis atau belum, fitur ini tidak sensitif terhadap time skew yang ada pada klaster dan bisa saja menghapus objek pada waktu yang salah bagi objek tersebut akibat adanya time skew.
Pada Kubernetes, NTP haruslah dilakukan pada semua node untuk mecegah adanya time skew (lihat #6159). Clock tidak akan selalu tepat, meskipun begitu perbedaan yang ada haruslah diminimalisasi. Perhatikan bahwa hal ini dapat terjadi apabila TTL diaktifkan dengan nilai selain 0.
Selanjutnya
2.8 - Jobs
Sebuah Job membuat satu atau beberapa Pod dan menjamin bahwa jumlah Pod yang telah dispesifikasikan sebelumnya berhasil dijalankan. Pada saat Pod telah dihentikan, Job akan menandainya sebagai Job yang sudah berhasil dijalankan. Ketika jumlah sukses yang dispesifikasikan sebelumnya sudah terpenuhi, maka Job tersebut dianggap selesai. Menghapus sebuah Job akan menghapus semua Pod yang dibuat oleh Job tersebut.
Sebuah kasus sederhana yang dapat diberikan adalah membuat sebuah objek Job untuk menjamin sebuah Pod dijalankan hingga selesai. Objek Job ini akan membuat sebuah Pod baru apabila Pod pertama gagal atau dihapus (salah satu contohnya adalah akibat adanya kegagalan pada perangkat keras atau terjadinya reboot pada Node).
Kamu juga dapat menggunakan Job untuk menjalankan beberapa Pod secara paralel.
Menjalankan Contoh Job
Berikut merupakan contoh konfigurasi Job. Job ini melakukan komputasi π hingga digit ke 2000 kemudian memberikan hasilnya sebagai keluaran. Job tersebut memerlukan waktu 10 detik untuk dapat diselesaikan.
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
Kamu dapat menjalankan contoh tersebut dengan menjalankan perintah berikut:
kubectl apply -f https://k8s.io/examples/controllers/job.yaml
job "pi" created
Perhatikan status dari Job yang baru dibuat dengan menggunakan perintahkubectl
:
kubectl describe jobs/pi
Name: pi
Namespace: default
Selector: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
job-name=pi
Annotations: <none>
Parallelism: 1
Completions: 1
Start Time: Tue, 07 Jun 2016 10:56:16 +0200
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
job-name=pi
Containers:
pi:
Image: perl
Port:
Command:
perl
-Mbignum=bpi
-wle
print bpi(2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: pi-dtn4q
Untuk melihat Pod yang sudah selesai dari sebuah Job, kamu dapat menggunakan perintah kubectl get pods
.
Untuk menampilkan semua Pod yang merupakan bagian dari suatu Job di mesin kamu dalam bentuk yang mudah dipahami, kamu dapat menggunakan perintah berikut ini:
pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath='{.items[*].metadata.name}')
echo $pods
pi-aiw0a
Disini, selektor yang ada merupakan selektor yang sama dengan yang ada pada Job.
Opsi --output=jsonpath
menspesifikasikan bahwa ekspresi yang hanya
menampilkan nama dari setiap Pod pada list yang dikembalikan.
Untuk melihat keluaran standar dari salah satu pod:
kubectl logs $pods
Keluaran yang dihasilkan akan sama dengan:
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
Menulis Spek Job
Sama halnya dengan konfigurasi Kubernetes lainnya, sebuah Job memerlukan field
apiVersion
, kind
, dan metadata
.
Sebuah Job juga membutuhkan sebuah bagian .spec
.
Templat Pod
Field .spec.template
merupakan satu-satunya field wajib pada .spec
.
Field .spec.template
merupakan sebuah templat Pod. Field ini memiliki skema yang sama dengan yang ada pada Pod,
kecuali field ini bersifat nested dan tidak memiliki field apiVersion
atau field kind
.
Sebagai tambahan dari field wajib pada sebuah Job, sebuah tempat pod pada Job haruslah menspesifikasikan label yang sesuai (perhatikan selektor pod) dan sebuah mekanisme restart yang sesuai.
Hanya sebuah RestartPolicy
yang sesuai dengan Never
atau OnFailure
yang bersifat valid.
Selektor Pod
Field .spec.selector
bersifat opsional. Dan dalam sebagian besar kasus, kamu tidak perlu memberikan
spesifikasi untuk hal ini. Perhatikan bagian menspesifikasikan selektor Pod kamu sendiri.
Job Paralel
Terdapat tiga jenis utama dari task yang sesuai untuk dijalankan sebagai sebuah Job:
- Job non-paralel
- secara umum, hanya sebuah Pod yang dimulai, kecuali jika Pod tersebut gagal.
- Job akan dianggap sudah selesai dikerjakan apabila Pod dari Job tersebut sudah selesai dijalankan dan mengalami terminasi dengan status sukses.
- Job paralel dengan jumlah nilai penyelesaian tetap:
- berikan spesifikasi pada
.spec.completions
dengan nilai non-negatif. - Job yang ada merupakan representasi dari task yang dikerjakan, dan akan dianggap selesai apabila terdapat lebih dari satu Pod yang sukses untuk setiap nilai yang ada dalam jangkauan 1 hingga
.spec.completions
. - belum diimplementasikan saat ini: Setiap Pod diberikan nilai indeks yang berbeda di dalam jangkauan 1 hingga
.spec.completions
.
- Job paralel dengan sebuah work queue:
- jangan berikan spesifikasi pada
.spec.completions
, nilai default-nya merupakan.spec.parallelism
. - Pod yang ada haruslah dapat berkoordinasi satu sama lain atau dengan Service eksternal lain untuk menentukan apa yang setiap Pod tadi perlu lakukan. Sebagai contohnya, sebuah Pod bisa saja melakukan fetch job batch hingga N kali pada work queue
- setiap Pod secara independen mampu menentukan apakah Pod lainnya telah menyelesaikan tugasnya dengan baik atau belum, dengan kata lain suatu Job telah dikatakan selesai
- ketika Pod mana pun dari sebuah Job berhenti dalam keadaan sukses, maka tidak ada Pod lain yang akan dibuat untuk Job tersebut.
- apabila salah satu Pod sudah dihentikan sekali dalam keadaan sukses, maka Job akan ditandai sebagai sukses.
- apabila sebuah Pod sudah dihentikan dalam keadaan sukses, tidak boleh ada Pod lain yang mengerjakan task tersebut. Dengan kata lain, semua Pod tersebut haruslah dalam keadaan akan dihentikan.
Untuk sebuah Job yang non-paralel, kamu tidak perlu menspesifikasikan field .spec.completions
dan .spec.parallelism
. Ketika kedua field tersebut
dalam keadaan tidak dispesifikasikan, maka nilai defult-nya akan diubah menjadi 1.
Untuk sebuah Job dengan jumlah nilai penyelesaian tetap, kamu harus memberikan spesifikasi nilai
dari .spec.completions
dengan nilai yang diinginkan. Kamu dapat menspesifikasikan .spec.parallelism
,
atau jika kamu tidak melakukannya nilai dari field ini akan memiliki nilai default 1.
Untuk sebuah Job work queue, kamu harus meninggalkan spesifikasi field .spec.completions
menjadi kosong, serta
memberikan nilai pada .spec.parallelism
menjadi sebuah bilangan bulat non negatif.
Untuk informasi lebih lanjut mengenai bagaimana menggunakan Job dengan jenis yang berbeda, kamu dapat melihat bagian pola job.
Mengendalikan Paralelisme
Paralelisme yang diminta (.spec.parallelism
) dapat diaktifkan dengan cara
memberikan nilai bilangan bulat non-negatif. Jika tidak dispesifikasikan maka nilainya akan
secara default yaitu 1. Jika dispesifikasikan sebagai 0, maka Job akan secara otomatis dihentikan sementara
hingga nilainya dinaikkan.
Paralelisme yang sebenarnya (jumlah Pod yang dijalankan pada satu waktu tertentu) bisa saja lebih atau kurang dari nilai yang diharapkan karena adanya alasan berikut:
- Untuk Job fixed completion count, nilai sebenarnya dari jumlah Pod yang dijalankan secara paralel tidak akan melebihi jumlah
completion yang tersisa. Nilai yang lebih tinggi dari.spec.parallelism
secara efektif, akan diabaikan. - Untuk Job work queue, tidak akan ada Pod yang dimulai setelah ada Pod yang berhasil -- meskipun begitu, sisa Pod yang ada akan diizinkan untuk menyelesaikan tugasnya.
- Jika sebuah Pengontrol Job tidak memiliki waktu untuk memberikan reaksi.
- Jika sebuah controller Job gagal membuat Pod dengan alasan apa pun (kurangnya
ResourceQuota
, kurangnya permission, dkk.), maka bisa saja terdapat lebih sedikit Pod dari yang diminta. - Jika controller Job melakukan throttle pembuatan Pod karena terdapat gagalnya pembuatan Pod yang berlebihan sebelumnya pada Job yang sama.
- Ketika sebuah Pod dihentikan secara graceful, maka Pod tersebut akan membutuhkan waktu untuk berhenti.
Mengatasi Kegagalan Pod dan Container
Sebuah Container pada sebuah Pod bisa saja mengalami kegagalan karena berbagai alasan
yang berbeda, misalnya saja karena proses yang ada di dalamnya berakhir dengan exit code
yang tidak sama dengan nol, atau Container yang ada di-kill karena menyalahi batasan memori, dkk.
Jika hal ini terjadi, dan .spec.template.spec.restartPolicy = "OnFailure"
, maka Pod
akan tetap ada di dalam node, tetapi Container tersebut akan dijalankan kembali. Dengan demikian,
program kamu harus dapat mengatasi kasus dimana program tersebut di-restart secara lokal, atau jika
tidak maka spesifikasikan .spec.template.spec.restartPolicy = "Never"
. Perhatikan
lifecycle pod untuk informasi lebih lanjut mengenai restartPolicy
.
Sebuah Pod juga dapat gagal secara menyeluruh, untuk beberapa alasan yang mungkin, misalnya saja,
ketika Pod tersebut dipindahkan dari Node (ketika Node diperbarui, di-restart, dihapus, dsb.), atau
jika sebuah Container dalam Pod gagal dan .spec.template.spec.restartPolicy = "Never"
. Ketika
sebuah Pod gagal, maka controller Job akan membuat sebuah Pod baru. Ini berarti aplikasi kamu haruslah
bisa mengatasi kasus dimana aplikasimu dimulai pada Pod yang baru. Secara khusus apabila aplikasi kamu
berurusan dengan berkas temporer, locks, keluaran yang tak lengkap dan hal-hal terkait dengan
program yang dijalankan sebelumnya.
Perhatikan bahwa bahakan apabila kamu menspesifikasikan .spec.parallelism = 1
dan .spec.completions = 1
dan
.spec.template.spec.restartPolicy = "Never"
, program yang sama bisa saja tetap dijalankan lebih dari sekali.
Jika kamu menspesifikasikan .spec.parallelism
dan .spec.completions
dengan nilai yang lebih besar dari 1,
maka bisa saja terdapat keadaan dimana terdapat beberapa Pod yang dijalankan pada waktu yang sama.
Dengan demikian, Pod kamu haruslah fleksibel terhadap adanya konkurensi.
Mekanisme Kebijakan Backoff apabila Terjadi Kegagalan
Terdapat situasi dimana kamu ingin membuat suatu Job gagal
setelah dijalankan mekanisme retry beberapa kali akibat adanya kesalahan pada konfigurasi
dsb. Untuk melakukan hal tersebut, spesifikasikan .spec.backoffLimit
dengan nilai retry yang diinginkan
sebelum menerjemahkan Job dalam keadaan gagal. Secara default, nilai dari field tersebut adalah 6.
Pod yang gagal dijalankan dan terkait dengan suatu Job tertentu akan dibuat kembali oleh
controller Job dengan delay back-off eksponensial (10 detik, 20 detik, 40 detik ...)
yang dibatasi pada 6 menit. Penghitungan back-off akan diulang jika tidak terdapat Pod baru yang gagal
sebelum siklus pengecekan status Job selanjutnya.
restartPolicy = "OnFailure"
, perhatikan bahwa Container kamu yang menjalankan
Job tersebut akan dihentikan ketika limit back-off telah dicapai. Hal ini akan membuat proses debugging semakin sulit.
Dengan demikian, kami memberikan saran untuk menspesifikasikan restartPolicy = "Never"
ketika melakukan
proses debugging atau menggunakan mekanisme logging untuk menjamin keluaran
dari Job yang gagal agar tidak terus menerus hilang.
Terminasi dan Clean Up Job
Ketika sebuah Job selesai dijalankan, tidak akan ada lagi Pod yang dibuat,
meskipun begitu Pod yang ada juga tidak akan dihapus. Dengan demikian kamu masih bisa mengakses log
yang ada dari Pod yang sudah dalam status complete untuk mengecek apabila terjadi eror, warning, atau hal-hal
yang dapat digunakan untuk proses pelaporan dan identifikasi. Objek Job itu sendiri akan tetap ada,
sehingga kamu tetap bisa melihat statusnya. Penghapusan objek akan diserahkan sepenuhnya pada pengguna
apabila Job tidak lagi digunakan. Penghapusan Job dengan perintah kubectl
(misalnya, kubectl delete jobs/pi
atau kubectl delete -f ./job.yaml
).
Ketika kamu menghapus Job menggunakan perintah kubectl
, semua Pod yang terkait dengan Job tersebut akan ikut dihapus.
Secara default, sebuah Job akan dijalankan tanpa adanya interupsi kecuali terdapat Pod yang gagal, (restartPolicy=Never
) atau terdapat
Container yang dihentikan dalam kondisi error (restartPolicy=OnFailure
), suatu keadaan dimana Job akan dijalankan dengan mekanisme
yang dijelaskan di atas berdasarkan pada .spec.backoffLimit
.
Apabila .spec.backoffLimit
telah mencapai limit, maka Job akan ditandai sebagai gagal dan Pod yang saat ini sedang dijalankan juga akan dihentikan.
Cara lain untuk menghentikan sebuah Job adalah dengan mengatur deadline aktif.
Untuk melakukannya kamu dapat menspesifikasikan field .spec.activeDeadlineSeconds
dari sebuah Job dengan suatu angka dalam satuan detik. Field activeDeadlineSeconds
diterapkan pada durasi dari sebuah Job, tidak peduli seberapa banyak Pod yang dibuat.
Setelah sebuah Job mencapai limit activeDeadlineSeconds
, semua Pod yang dijalankan akan dihentikan
dan status dari Job tersebut akan berubah menjadi type: Failed
dengan reason: DeadlineExceeded
.
Perhatikan bahwa field .spec.activeDeadlineSeconds
pada Job memiliki tingkat
presedensi di atas .spec.backoffLimit
. Dengan demikian, sebuah Job
yang sedang mencoba melakukan restart pada suatu Pod-nya tidak akan melakukan
pembuatan Pod yang baru apabila Job tersebut telah mencapai limit yang didefinisikan pada
activeDeadlineSeconds
, bahkan apabila nilai dari backoffLimit
belum tercapai.
Contoh:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-timeout
spec:
backoffLimit: 5
activeDeadlineSeconds: 100
template:
spec:
Containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
Perhatikan bahwa baik spek Job dan spek templat Pod di dalam Job memiliki field activeDeadlineSeconds
.
Pastikan kamu telah menspesifikasikan nilai tersebut pada level yang dibutuhkan.
Mekanisme Clean Up Otomatis pada Job yang Sudah Selesai
Job yang sudah selesai biasanya tidak lagi dibutuhkan di dalam sistem. Tetap menjaga keberadaan objek-objek tersebut di dalam sistem akan memberikan tekanan tambahan pada API server. Jika sebuah Job yang diatur secara langsung oleh controller dengan level yang lebih tinggi, seperti CronJob, maka Job ini dapat di-clean up oleh CronJob berdasarkan policy berbasis kapasitas yang dispesifikasikan.
Mekanisme TTL untuk Job yang Telah Selesai Dijalankan
Kubernetes v1.12 [alpha]
Salah satu cara untuk melakukan clean up Job yang telah selesai dijalankan
(baik dengan status Complete
atau Failed
) secara otomatis adalah dengan
menerapkan mekanisme TTL yang disediakan oleh
controller TTL untuk
sumber daya yang telah selesai digunakan, dengan cara menspesifikasikan
field .spec.ttlSecondsAfterFinished
dari Job tersebut.
Ketika controller TTL melakukan proses clean up pada Job, maka controller tersebut akan menghapus objek-objek terkait seperti Pod, serta Job itu sendiri. Perhatikan bahwa ketika suatu Job dihapus, maka lifecycle-nya akan menjamin, mekanisme finalizer yang ada akan tetap dihargai.
Sebagai contoh:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-ttl
spec:
ttlSecondsAfterFinished: 100
template:
spec:
Containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
Job pi-with-ttl
akan dihapus secara otomatis, dalam jangka waktu 100
detik setelah Job tersebut selesai dijalankan.
Jika field ini dispesifikasikan sebagai 0
, maka Job akan secara otomatis dihapus
segera setelah Job tersebut selesai dijalankan. Jika field tersebut tidak dispesifikasikan,
maka Job ini tidak akan dihapus oleh controller TTL setelah Job ini selesai dijalankan.
Perhatikan bahwa mekanisme TTL ini merupakan fitur alpha, dengan gerbang fitur TTLAfterFinished
.
Untuk informasi lebih lanjut, kamu dapat membaca dokumentasi untuk
controller TTL untuk
sumber daya yang telah selesai dijalankan.
Pola Job
Sebuah objek Job dapat digunakan untuk mendukung eksekusi paralel yang dapat diandalkan pada Pod. Objek Job tidak di-desain untuk mendukung proses paralel bersifat closely-communicating, seperti yang secara umum ditemukan dalam komputasi ilmiah. Meskipun begitu objek ini mendukung set work item yang independen namun saling terkait satu sama lainnya. Ini termasuk surel yang harus dikirim, frame yang harus di-render, berkas yang harus di-transcoded, jangkauan key yang ada di dalam basis data NoSQL, dsb.
Pada suatu sistem yang kompleks, terdapat beberapa set work item yang berbeda. Di sini, kami hanya mempertimbangkan work item yang ingin digunakan oleh pengguna untuk melakukan manajemen secara bersamaan — sebuah batch job.
Terdapat beberapa perbedaan pola pada komputasi paralel, setiap pola memiliki kelebihan dan kekurangannya masing-masing. Kekurangan dan kelebihan ini dijabarkan sebagai berikut:
- Satu objek Job untuk setiap work item, atau sebuah Job untuk semua work item. Pilihan kedua akan lebih baik apabila digunakan untuk jumlah work item yang lebih besar. Sementara itu, pilihan pertama akan mengakibatkan overhead bagi pengguna dan juga sistem untuk mengaur jumlah objek Job yang cukup banyak.
- Jumlah Pod yang dibuat sesuai dengan jumlah work item atau setiap Pod dapat memproses beberapa work item sekaligus. Pilihan pertama secara umum memerlukan modifikasi lebih sedikit untuk kode dan Container yang suda ada. Pilihan kedua akan lebih baik jika digunakan untuk jumlah work item yang lebih banyak, untuk alasan yang sama dengan poin sebelumnya.
- Beberapa pendekatan menggunakan prinsip work queue. Hal ini membutuhkan sebuah service queue yang dijalankan, serta modifikasi untuk program atau Container yang sudah ada untuk mengizinkannya menggunakan working queue. Pendekatan lain akan lebih mudah untuk digunakan bagi aplikasi yang sudah ada.
Tradeoff yang dirangkum di sini, dengan kolom 2 dan 4 berkaitan dengan tradeoff yang dijelaskan di atas. Nama dari pola yang ada juga terkait dengan contoh dan deskripsi lebih lanjut.
Pola | Objek dengan satu Job | Pod yang lebih sedikit tadi work items? | Penggunaan app tanpa modifikasi? | Dapat dijalankan pada Kube versi 1.1? |
---|---|---|---|---|
Perluasan Templat Job | ✓ | ✓ | ||
Queue dengan Pod untuk setiap Work Item | ✓ | sometimes | ✓ | |
Queue dengan Variabel Pod Count | ✓ | ✓ | ✓ | |
Job Single dengan penempatan Kerja Statis | ✓ | ✓ |
Ketika kamu menspesifikasikan completion dengan .spec.completions
, setiap Pod yang dibuat oleh controller Job
memiliki spec
yang identik. Artinya
semua Pod untuk sebuah task akan memiliki perintah yang sama serta image, volume, serta variabel environment yang (hampir) sama.
Pola ini merupakan salah satu cara berbeda yang diterapkan untuk mengatur Pod agar dapat bekerja untuk hal yang berbeda-beda.
Tabel ini menunjukkan pengaturan yang dibutuhkan untuk .spec.parallelism
dan .spec.completions
bagi setiap pola.
Disini, W
merupakan jumlah dari work item.
Pattern | .spec.completions |
.spec.parallelism |
---|---|---|
Job Template Expansion | 1 | should be 1 |
Queue with Pod Per Work Item | W | any |
Queue with Variable Pod Count | 1 | any |
Single Job with Static Work Assignment | W | any |
Penggunaan Tingkat Lanjut
Menspesifikasikan Selektor Pod Kamu Sendiri
Secara umum, ketika kamu membuat sebuah objek Job, kamu
tidak menspesifikasikan .spec.selector
. Sistem akan memberikan nilai
default pada field ini ketika Job dibuat. Sistem akan memilih nilai dari selektor yang ada
dan memastikan nilainya tidak akan beririsan dengan Job lainnya.
Meskipun demikian, pada beberapa kasus, kamu bisa saja memiliki kebutuhan untuk meng-override
nilai dari selektor ini. Untuk melakukannya, kamu dapat menspesifikasikan .spec.selector
dari Job.
Berhati-hatilah ketika kamu melakukan proses ini. Jika kamu menspesifikasikan sebuah label
selektor yang tidak unik pada Pod yang ada di dalam Job tersebut, serta sesuai dengan Pod yang tidak
terkait dengan Job tadi, maka Pod dari Job yang tidak terkait dengan Job tadi akna dihapus, atau Job ini
akan menghitung completion dari Pod lain sebagai tolak ukur suksesnya Job tersebut, atau bisa saja salah satu
atau kedua Job tidak dapat membuat Pod baru yang digunakan untuk menyelesaikan Job tersebut.
Jika selektor yang tidak unik dipilih, maka controller lain (misalnya ReplicationController) dan Pod
yang ada di dalamnya bisa saja memiliki perilaku yang tidak dapat diprediksi. Kubernetes tidak akan
mencegah kemungkinan terjadinya hal ini ketika kamu menspesifikasikan nilai .spec.selector
.
Berikut merupakan contoh skenario dimana kamu ingin menggunakan fitur ini.
Misalnya saja Job dengan nama old
sudah dijalankan.
Dan kamu ingin Pod yang sudah dijalankan untuk tetap berada pada state tersebut,
tapi kamu juga ingin Pod selanjutnya yang dibuat untuk menggunakan templat Pod yang berbeda dan agar
Job tersebut memiliki nama yang berbeda. Kamu tidak dapat mengubah Job karena field ini
merupakan nilai yang tidak bisa diubah. Dengan demikian, kamu menghapus Job old
tetapi tetap membiarkan Pod yang ada untuk jalan, menggunakan perintah kubectl delete jobs/old --cascade=false
.
Sebelum menghapus Job tadi, kamu mencatat selektor yang digunakan oleh Job tadi:
kubectl get job old -o yaml
kind: Job
metadata:
name: old
...
spec:
selector:
matchLabels:
controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...
Kemudian kamu membuat sebuah Job baru dengan nama new
dan kamu secara eksplisit menspesifikasikan selektor yang sama.
Karena Pod dengan selektor yang sama memiliki label controller-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002
,
maka Pod-Pod lama tadi dikendalikan juga oleh Job new
.
Kamu harus menspesifikasikan manualSelector: true
pada Job yang baru
karena kamu tidak menggunakan selektor yang diberikan secara default oleh sistem.
kind: Job
metadata:
name: new
...
spec:
manualSelector: true
selector:
matchLabels:
controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...
Job yang baru tadi kemudian akan memiliki uid yang berbeda dari a8f3d00d-c6d2-11e5-9f87-42010af00002
. Pengaturan
manualSelector: true
memberikan perintah pada sistem bahwa kamu mengetahui apa yang kamu lakukan
dan untuk mengizikan ketidaksesuaian ini untuk terjadi.
Alternatif
Pod Polosan
Ketika node dimana Pod dijalankan berada dalam kondisi reboot atau gagal, Pod tadi akan dihentikan dan tidak akan di-restart. Meskipun demikian, sebuah Job akan membuat Pod baru yang menggantikan Pod lama yang dihentikan. Untuk alasan inilah, kami memberikan rekomendasi agar kamu menggunakan sebuah Job dibandingkan dengan Pod yang biasa, bahkan jika aplikasi yang kamu gunakan hanya memerlukan sebuah Pod.
Replication Controller
Job merupakan komplemen dari Replication Controller. Sebuah Replication Controller mengatur Pod yang diharapkan untuk tidak dihentikan (misalnya, web server), dan sebuah Job mengatur Pod yang diharapkan untuk berhenti (misalnya, batch task).
Seperti yang sudah dibahas pada Lifecycle Pod, Job
hanya pantas
digunakan untuk Pod dengan RestartPolicy
yang sama dengan OnFailure
atau Never
.
(Perhatikan bahwa: Jika RestartPolicy
tidak dispesifikasikan, nilai defaultnya adalah Always
.)
Job Tunggal akan menginisiasi Kontroller Pod
Pola lain yang mungkin diterapkan adalah untuk sebuah Job tunggal untuk membuat sebuah Pod yang kemudian akan membuat Pod lainnya, bersifat selayaknya controller kustom bagi Pod tersebut. Hal ini mengizinkan fleksibilitas optimal, tetapi cukup kompleks untuk digunakan dan memiliki integrasi terbatas dengan Kubernetes.
Salah satu contoh dari pola ini adalah sebuah Job yang akan menginisiasi sebuah Pod yang menjalankan script yang kemudian akan menjalankan controller master Spark (kamu dapat melihatnya di contoh Spark), yang menjalankan driver Spark, dan kemudian melakukan mekanisme clean up.
Keuntungan dari pendekatan ini adalah proses keseluruhan yang memiliki jaminan completion dari sebuah Job, tetapi kontrol secara mutlak atas Pod yang dibuat serta tugas yang diberikan pada Pod tersebut.
CronJob
Kamu dapat menggunakan CronJob
untuk membuat Job yang akan
dijalankan pada waktu/tanggal yang spesifik, mirip dengan perangkat lunak cron
yang ada pada Unix.
2.9 - CronJob
Suatu CronJob menciptakan Job yang dijadwalkan berdasarkan waktu tertentu.
Satu objek CronJob sepadan dengan satu baris pada file crontab (cron table). CronJob tersebut menjalankan suatu pekerjaan secara berkala pada waktu tertentu, dituliskan dalam format Cron.
schedule:
pada CronJob mengikuti zona waktu dari master di mana Job diinisiasi.
Untuk panduan dalam berkreasi dengan cron job, dan contoh spec file untuk suatu cron job, lihat Menjalankan otomasi task dengan cron job.
Limitasi Cron Job
Suatu cron job menciptakan kurang lebih satu objek Job setiap penjadwalan. Istilah yang digunakan adalah "kurang lebih" karena terdapat beberapa kasus yang menyebabkan dua Job terbuat, atau tidak ada Job sama sekali yang terbuat. Kemungkinan-kemungkinan seperti itu memang diusahakan untuk tidak sering terjadi, tapi tidak ada jaminan kemungkinan-kemungkinan tersebut tidak akan pernah terjadi. Oleh karena itu, Job sudah sepantasnya memiliki sifat idempoten.
Jika pengaturan startingDeadlineSeconds
menggunakan nilai yang besar atau tidak diatur (menggunakan nilai default)
dan jika pengaturan concurrencyPolicy
dijadikan Allow
, Job yang terbuat akan dijalankan paling tidak satu kali.
CronJob controller memeriksa berapa banyak jadwal yang terlewatkan sejak waktu terakhir eksekusi hingga saat ini. Jika terdapat lebih dari 100 jadwal yang terlewat, maka CronJob controller tidak memulai Job dan mencatat kesalahan:
Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.
Perlu diingat bahwa jika pengaturan startingDeadlineSeconds
memiliki suatu nilai (bukan nil
), CronJob controller akan menghitung berapa banyak Job yang terlewatkan dari sejak startingDeadlineSeconds
hingga sekarang dan bukan sejak waktu terakhir eksekusi. Misalnya: Jika startingDeadlineSeconds
memiliki nilai 200
, CronJob controller akan menghitung berapa banyak Job yang terlewatkan dalam 200 detik terakhir.
Suatu CronJob dianggap terlewat jika ia gagal diciptakan pada waktu yang semestinya. Misalnya: Jika pengaturan concurrencyPolicy
dijadikan Forbid
dan suatu CronJob dicoba dijadwalkan saat masih ada penjadwalan sebelumnya yang masih berjalan, maka ia akan dianggap terlewat.
Contoh: Suatu CronJob akan menjadwalkan Job baru tiap satu menit dimulai sejak 08:30:00
, dan startingDeadlineSeconds
tidak diatur.
Jika CronJob controller tidak aktif dari 08:29:00
sampai 10:21:00
, Job tidak akan dijalankan karena jumlah Job yang terlewat
sudah lebih dari 100.
Sebagai ilustrasi lebih lanjut, misalkan suatu CronJob diatur untuk menjadwalkan Job baru setiap satu menit dimulai sejak 08:30:00
,
dan startingDeadlineSeconds
memiliki nilai 200
. Jika CronJob controller tidak aktif seperti pada contoh sebelumnya (08:29:00
sampai 10:21:00
),
Job akan tetap dijalankan pada 10:22:00. Hal ini terjadi karena CronJob controller memeriksa banyaknya jadwal yang terlewatkan pada 200 detik terakhir
(dalam kasus ini: 3 jadwal terlewat), dan bukan dari sejak waktu eksekusi terakhir.
CronJob hanya bertanggung-jawab untuk menciptakan Job yang sesuai dengan jadwalnya sendiri, dan Job tersebut bertanggung jawab terhadap pengelolaan Pod yang direpresentasikan olehnya.