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.
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.
controllers/job.yaml
|
---|
|
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
Sama halnya dengan konfigurasi Kubernetes lainnya, sebuah Job memerlukan field
apiVersion
, kind
, dan metadata
.
Sebuah Job juga membutuhkan sebuah bagian .spec
.
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.
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.
Terdapat tiga jenis utama dari task yang sesuai untuk dijalankan sebagai sebuah Job:
.spec.completions
dengan nilai non-negatif..spec.completions
..spec.completions
..spec.completions
, nilai default-nya merupakan .spec.parallelism
.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.
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:
.spec.parallelism
secara efektif, akan diabaikan.ResourceQuota
, kurangnya permission, dkk.),
maka bisa saja terdapat lebih sedikit Pod dari yang diminta.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.
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.
Catatan: Isu #54870 masih ada untuk versi Kubernetes sebelum 1.12.
Catatan: Jika Job yang kamu miliki memilikirestartPolicy = "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 menspesifikasikanrestartPolicy = "Never"
ketika melakukan proses debugging atau menggunakan mekanisme logging untuk menjamin keluaran dari Job yang gagal agar tidak terus menerus hilang.
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.
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.
Kubernetes v1.12
alphaalpha
(misalnya, v1alpha1
).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.
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:
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 |
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.
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.
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
.)
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.
Kamu dapat menggunakan CronJob
untuk membuat Job yang akan
dijalankan pada waktu/tanggal yang spesifik, mirip dengan perangkat lunak cron
yang ada pada Unix.
Apakah halaman ini berguna?
Thanks for the feedback. If you have a specific, answerable question about how to use Kubernetes, ask it on Stack Overflow. Open an issue in the GitHub repo if you want to report a problem or suggest an improvement.