Taint dan Toleration

Afinitas Node, seperti yang dideskripsikan di sini, adalah salah satu properti dari Pod yang menyebabkan pod tersebut memiliki preferensi untuk ditempatkan di sekelompok Node tertentu (preferensi ini dapat berupa soft constraints atau hard constraints yang harus dipenuhi). Taint merupakan kebalikan dari afinitas -- properti ini akan menyebabkan Pod memiliki preferensi untuk tidak ditempatkan pada sekelompok Node tertentu.

Taint dan toleration bekerja sama untuk memastikan Pod dijadwalkan pada Node yang sesuai. Satu atau lebih taint akan diterapkan pada suatu node; hal ini akan menyebabkan node tidak akan menerima pod yang tidak mengikuti taint yang sudah diterapkan.

Konsep

Kamu dapat menambahkan taint pada sebuah node dengan menggunakan perintah kubectl taint. Misalnya,

kubectl taint nodes node1 key=value:NoSchedule

akan menerapkan taint pada node node1. Taint tersebut memiliki key key, value value, dan effect taint NoSchedule. Hal ini artinya pod yang ada tidak akan dapat dijadwalkan pada node1 kecuali memiliki taint yang sesuai.

Untuk menghilangkan taint yang ditambahkan dengan perintah di atas, kamu dapat menggunakan perintah di bawah ini:

kubectl taint nodes node1 key:NoSchedule-

Kamu dapat memberikan spesifikasi toleration untuk pod pada bagian PodSpec. Kedua toleration yang diterapkan di bawa ini "sesuai" dengan taint yang taint yang dibuat dengan perintah kubectl taint di atas, sehingga sebuah pod dengan toleration yang sudah didefinisikan akan mampu di-schedule ke node node:

tolerations:
- key: "key"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"
tolerations:
- key: "key"
  operator: "Exists"
  effect: "NoSchedule"

Sebuah toleration "sesuai" dengan sebuah taint jika key dan efek yang ditimbulkan sama:

  • operator dianggap Exists (pada kasus dimana tidak ada value yang diberikan), atau
  • operator dianggap Equal dan value yang ada sama

Operator bernilai Equal secara default jika tidak diberikan spesifikasi khusus.

Contoh yang diberikan di atas menggunakan effect untuk NoSchedule. Alternatif lain yang dapat digunakan adalah effect untuk PreferNoSchedule. PreferNoSchedule merupakan "preferensi" yang lebih fleksibel dari NoSchedule -- sistem akan mencoba untuk tidak menempatkan pod yang tidak menoleransi taint pada node, tapi hal ini bukan merupakan sesuatu yang harus dipenuhi. Jenis ketiga dari effect adalah NoExecute, akan dijelaskan selanjutnya.

Kamu dapat menerapkan beberapa taint sekaligus pada node atau beberapa toleration sekaligus pada sebuah pod. Mekanisme Kubernetes dapat memproses beberapa taint dan toleration sekaligus sama halnya seperti sebuah filter: memulai dengan taint yang ada pada node, kemudian mengabaikan taint yang sesuai pada pod yang memiliki toleration yang sesuai; kemudian taint yang diterapkan pada pod yang sudah disaring tadi akan menghasilkan suatu effect pada pod. Secara khusus:

  • jika terdapat taint yang tidak tersaring dengan effect NoSchedule maka Kubernetes tidak akan menempatkan pod pada node tersebut
  • jika tidak terdapat taint yang tidak tersaring dengan effect NoSchedule tapi terdapat setidaknya satu taint yang tidak tersaring dengan effect PreferNoSchedule maka Kubernetes akan mencoba untuk tidak akan menempatkan pod pada node tersebut
  • jika terdapat taint yang tidak tersaring dengan effect NoExecute maka pod akan berada dalam kondisi evicted dari node (jika pod tersebut sudah terlanjur ditempatkan pada node tersebut), dan tidak akan di-schedule lagi pada node tersebut.

Sebagai contoh, bayangkan kamu memberikan taint pada node sebagai berikut:

kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule

Dan pod memiliki dua toleration:

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"

Pada kasus ini, pod tidak akan di-schedule pada node, karena tidak ada toleration yang sesuai dengan taint ketiga. Akan tetapi, pod yang sebelumnya sudah dijalankan di node dimana taint ditambahkan akan tetap jalan, karena taint ketiga merupakan taint yang tidak ditoleransi oleh pod.

Pada umumnya, jika sebuah taint memiliki effect NoExecute ditambahkan pada node, maka semua pod yang tidak menoleransi taint tersebut akan berada dalam state evicted secara langsung, dan semua pod yang menoleransi taint tersebut tidak akan berjalan seperti biasanya (tidak dalam state evicted). Meskipun demikian, toleration dengan effect NoExecute dapat dispesfikasikan sebagai field opsional tolerationSeconds yang memberikan perintah berapa lama suatu pod akan berada pada node apabila sebuah taint ditambahkan. Contohnya:

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600

ini berarti apabila sebuah pod sedang dalam berada dalam state running, kemudian sebuah taint yang sesuai ditambahkan pada node, maka pod tersebut akan tetap berada di dalam node untuk periode 3600 detik sebelum state-nya berubah menjadi evicted. Jika taint dihapus sebelum periode tersebut, maka pod tetap berjalan sebagaimana mestinya.

Contoh Penggunaan

Taint dan toleration adalah mekanisme fleksibel yang digunakan untuk memaksa pod agar tidak dijadwalkan pada node-node tertentu atau mengubah state pod menjadi evicted. Berikut adalah beberapa contoh penggunaannya:

  • Node-Node yang Sifatnya Dedicated: Jika kamu ingin menggunakan sekumpulan node dengan penggunaan eksklusif dari sekumpulan pengguna, kamu dapat menambahkan taint pada node-node tersebut (misalnya, kubectl taint nodes nodename dedicated=groupName:NoSchedule) dan kemudian menambahkan toleration yang sesuai pada pod-pod yang berada di dalamnya (hal ini dapat dilakukan dengan mudah dengan cara menulis admission controller yang bersifat khusus). Pod-pod dengan toleration nantinya akan diperbolehkannya untuk menggunakan node yang sudah di-taint (atau dengan kata lain didedikasikan penggunaannya) maupun node lain yang ada di dalam klaster. Jika kamu ingin mendedikasikan node khusus yang hanya digunakan oleh pod-pod tadi serta memastikan pod-pod tadi hanya menggunakan node yang didedikasikan, maka kamu harus menambahkan sebuah label yang serupa dengan taint yang diberikan pada sekelompok node (misalnya, dedicated=groupName), dan admission controller sebaiknya menambahkan afininitas node untuk memastikan pod-pod tadi hanya dijadwalkan pada node dengan label dedicated=groupName.

  • Node-Node dengan Perangkat Keras Khusus: Pada suatu klaster dimana sebagian kecuali node memiliki perangkat keras khusus (misalnya GPU), kita ingin memastikan hanya pod-pod yang membutuhkan GPU saja yang dijadwalkan di node dengan GPU. Hal ini dapat dilakukan dengan memberikan taint pada node yang memiliki perangkat keras khusus (misalnya, kubectl taint nodes nodename special=true:NoSchedule atau kubectl taint nodes nodename special=true:PreferNoSchedule) serta menambahkan toleration yang sesuai pada pod yang menggunakan node dengan perangkat keras khusus. Seperti halnya pada kebutuhan dedicated node, hal ini dapat dilakukan dengan mudah dengan cara menulis admission controller yang bersifat khusus. Misalnya, kita dapat menggunakan Extended Resource untuk merepresentasikan perangkat keras khusus, kemudian taint node dengan perangkat keras khusus dengan nama extended resource dan jalankan admission controller ExtendedResourceToleration. Setelah itu, karena node yang ada sudah di-taint, maka tidak akan ada pod yang tidak memiliki toleration yang akan dijadwalkan pada node tersebut_. Meskipun begitu, ketika kamu membuat suatu _pod_ yang membutuhkan _extended resource_, maka _admission controller_ dari ExtendedResourceToleration akan mengoreksi _toleration_ sehingga _pod_ tersebut dapat dijadwalkan pada _node_ dengan perangkat keras khusus. Dengan demikian, kamu tidak perlu menambahkan _toleration_ secara manual pada pod yang ada.

  • Eviction berbasis Taint (fitur beta): Konfigurasi eviction per pod yang terjadi ketika pod mengalami gangguan, hal ini akan dibahas lebih lanjut di bagian selanjutnya.

Eviction berbasis Taint

Sebelumnya, kita sudah pernah membahas soal effect taint NoExecute, yang memengaruhi pod yang sudah dijalankan dengan cara sebagai berikut:

  • pod yang tidak menoleransi taint akan segera diubah state-nya menjadi evicted
  • pod yang menoleransi taint yang tidak menspesifikasikan tolerationSeconds pada spesifikasi toleration yang ada akan tetap berada di dalam node tanpa adanya batas waktu tertentu
  • pod yang menoleransi taint yang menspesifikasikan tolerationSeconds spesifikasi toleration yang ada akan tetap berada di dalam node hingga batas waktu tertentu

Sebagai tambahan, Kubernetes 1.6 memperkenalkan dukungan alfa untuk merepresentasikan node yang bermasalah. Dengan kata lain, node controller akan secara otomatis memberikan taint pada sebuah node apabila node tersebut memenuhi kriteria tertentu. Berikut merupakan taint yang secara default disediakan:

  • node.kubernetes.io/not-ready: Node berada dalam state not ready. Hal ini terjadi apabila value dari NodeCondition Ready adalah "False".
  • node.kubernetes.io/unreachable: Node berada dalam state unreachable dari node controller Hal ini terjadi apabila value dari NodeCondition Ready adalah "Unknown".
  • node.kubernetes.io/out-of-disk: Node kehabisan kapasitas disk.
  • node.kubernetes.io/memory-pressure: Node berada diambang kapasitas memori.
  • node.kubernetes.io/disk-pressure: Node berada diambang kapasitas disk.
  • node.kubernetes.io/network-unavailable: Jaringan pada Node bersifat unavailable.
  • node.kubernetes.io/unschedulable: Node tidak dapat dijadwalkan.
  • node.cloudprovider.kubernetes.io/uninitialized: Ketika kubelet dijalankan dengan penyedia layanan cloud "eksternal", taint ini akan diterapkan pada node untuk menandai node tersebut tidak digunakan. Setelah kontroler dari cloud-controller-manager melakukan inisiasi node tersebut, maka kubelet akan menghapus taint yang ada.

Pada versi 1.13, fitur TaintBasedEvictions diubah menjadi beta dan diaktifkan secara default, dengan demikian taint-taint tersebut secara otomatis ditambahkan oleh NodeController (atau kubelet) dan logika normal untuk melakukan eviction pada pod dari suatu node tertentu berdasarkan value dari Ready yang ada pada NodeCondition dinonaktifkan.

Fitur beta ini, bersamaan dengan tolerationSeconds, mengizinkan sebuah pod untuk menspesifikasikan berapa lama pod harus tetap sesuai dengan sebuah node apabila node tersebut bermasalah.

Misalnya, sebuah aplikasi dengan banyak state lokal akan lebih baik untuk tetap berada di suatu node pada saat terjadi partisi jaringan, dengan harapan partisi jaringan tersebut dapat diselesaikan dan mekanisme eviction pod tidak akan dilakukan. Toleration yang ditambahkan akan berbentuk sebagai berikut:

tolerations:
- key: "node.kubernetes.io/unreachable"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 6000

Perhatikan bahwa Kubernetes secara otomatis menambahkan toleration untuk node.kubernetes.io/not-ready dengan tolerationSeconds=300 kecuali konfigurasi lain disediakan oleh pengguna. Kubernetes juga secara otomatis menambahkan toleration untuk node.kubernetes.io/unreachable dengan tolerationSeconds=300 kecuali konfigurasi lain disediakan oleh pengguna.

Toleration yang ditambahkan secara otomatis ini menjamin bahwa perilaku default dari suatu pod adalah tetap bertahan selama 5 menit pada node apabila salah satu masalah terdeteksi. Kedua toleration default tadi ditambahkan oleh DefaultTolerationSeconds admission controller.

Pod-pod pada DaemonSet dibuat dengan toleration NoExecute untuk taint tanpa tolerationSeconds:

  • node.kubernetes.io/unreachable
  • node.kubernetes.io/not-ready

Hal ini menjamin pod-pod yang merupakan bagian dari DaemonSet tidak pernah berada di dalam state evicted apabila terjadi permasalahan pada node.

Taint pada Node berdasarkan Kondisi Tertentu

Pada versi 1.12, fitur TaintNodesByCondition menjadi fitur beta, dengan demikian lifecycle dari kontroler node akan secara otomatis menambahkan taint sesuai dengan kondisi node. Hal yang sama juga terjadi pada scheduler, scheduler tidak bertugas memeriksa kondisi node tetapi kondisi taint. Hal ini memastikan bahwa kondisi node tidak memengaruhi apa yang dijadwalkan di node. Pengguna dapat memilih untuk mengabaikan beberapa permasalahan yang ada pada node (yang direpresentasikan oleh kondisi Node) dengan menambahkan toleration Pod NoSchedule. Sedangkan taint dengan effect NoExecute dikendalikan oleh TaintBasedEviction yang merupakan fitur beta yang diaktifkan secara default oleh Kubernetes sejak versi 1.13.

Sejak Kubernetes versi 1.8, kontroler DaemonSet akan secara otomatis menambahkan toleration NoSchedule pada semua daemon untuk menjaga fungsionalitas DaemonSet.

  • node.kubernetes.io/memory-pressure
  • node.kubernetes.io/disk-pressure
  • node.kubernetes.io/out-of-disk (hanya untuk pod yang bersifat critical)
  • node.kubernetes.io/unschedulable (versi 1.10 atau yang lebih baru)
  • node.kubernetes.io/network-unavailable (hanya untuk jaringan host)

Menambahkan toleration ini menjamin backward compatibility. Kamu juga dapat menambahkan toleration lain pada DaemonSet.