--- title: Jobs content_type: concept feature: title: Eksekusi batch description: > Selain Service, Kubernetes juga dapat melakukan manajemen workload batch dan CI, melakukan penggantian Container-Container yang gagal, jika diinginkan. weight: 70 --- 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. {{% codenew file="controllers/job.yaml" %}} Kamu dapat menjalankan contoh tersebut dengan menjalankan perintah berikut: ```shell kubectl apply -f https://k8s.io/examples/controllers/job.yaml ``` ``` job "pi" created ``` Perhatikan status dari Job yang baru dibuat dengan menggunakan perintah`kubectl`: ```shell 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: 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: Mounts: Volumes: 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: ```shell 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: ```shell kubectl logs $pods ``` Keluaran yang dihasilkan akan sama dengan: ```shell 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`](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status). ### Templat Pod _Field_ `.spec.template` merupakan satu-satunya _field_ wajib pada `.spec`. _Field_ `.spec.template` merupakan sebuah [templat Pod](/id/docs/concepts/workloads/pods/pod-overview/#pod-templates). _Field_ ini memiliki skema yang sama dengan yang ada pada [Pod](/docs/user-guide/pods), 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](#pod-selektor)) dan sebuah mekanisme _restart_ yang sesuai. Hanya sebuah [`RestartPolicy`](/id/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy) 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](#menspesifikasikan-selektor-pod-kamu-sendiri). ### Job Paralel Terdapat tiga jenis utama dari _task_ yang sesuai untuk dijalankan sebagai sebuah Job: 1. 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. 1. 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`. 1. 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](#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 {{< glossary_tooltip term_id="controller" >}} 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](/id/docs/concepts/workloads/pods/pod-lifecycle/#example-states) 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. {{< note >}} Isu [#54870](https://github.com/kubernetes/kubernetes/issues/54870) masih ada untuk versi Kubernetes sebelum 1.12. {{< /note >}} {{< note >}} Jika Job yang kamu miliki memiliki `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. {{< /note >}} ## 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: ```yaml 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](/docs/concepts/workloads/pods/init-Containers/#detailed-behavior) 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](/id/docs/concepts/workloads/controllers/cron-jobs/), maka Job ini dapat di-_clean up_ oleh CronJob berdasarkan _policy_ berbasis kapasitas yang dispesifikasikan. ### Mekanisme TTL untuk Job yang Telah Selesai Dijalankan {{< feature-state for_k8s_version="v1.12" state="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](/id/docs/concepts/workloads/controllers/ttlafterfinished/) 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: ```yaml 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](/id/docs/concepts/workloads/controllers/ttlafterfinished/) 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](/docs/tasks/job/parallel-processing-expansion/) | | | ✓ | ✓ | | [Queue dengan Pod untuk setiap _Work Item_](/docs/tasks/job/coarse-parallel-processing-work-queue/) | ✓ | | sometimes | ✓ | | [Queue dengan Variabel _Pod Count_](/docs/tasks/job/fine-parallel-processing-work-queue/) | ✓ | ✓ | | ✓ | | Job Single dengan penempatan Kerja Statis | ✓ | | ✓ | | Ketika kamu menspesifikasikan _completion_ dengan `.spec.completions`, setiap Pod yang dibuat oleh _controller_ Job memiliki [`spec`](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status) 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](/docs/tasks/job/parallel-processing-expansion/) | 1 | should be 1 | | [Queue with Pod Per Work Item](/docs/tasks/job/coarse-parallel-processing-work-queue/) | W | any | | [Queue with Variable Pod Count](/docs/tasks/job/fine-parallel-processing-work-queue/) | 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](/docs/user-guide/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](/id/docs/concepts/workloads/pods/pod-lifecycle/), `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](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/spark/README.md)), 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 {#cron-jobs} Kamu dapat menggunakan [`CronJob`](/id/docs/concepts/workloads/controllers/cron-jobs/) untuk membuat Job yang akan dijalankan pada waktu/tanggal yang spesifik, mirip dengan perangkat lunak `cron` yang ada pada Unix.