|
| 1 | +--- |
| 2 | +title: Batasan Persebaran Topologi Pod |
| 3 | +content_template: templates/concept |
| 4 | +weight: 50 |
| 5 | +--- |
| 6 | + |
| 7 | +{{% capture overview %}} |
| 8 | + |
| 9 | +{{< feature-state for_k8s_version="v1.18" state="beta" >}} |
| 10 | + |
| 11 | +Kamu dapat menggunakan batasan perseberan topologi (_topology spread constraints_) |
| 12 | +untuk mengatur bagaimana {{< glossary_tooltip text="Pod" term_id="Pod" >}} akan disebarkan |
| 13 | +pada klaster yang ditetapkan sebagai _failure-domains_, seperti wilayah, zona, Node dan domain |
| 14 | +topologi yang ditentukan oleh pengguna. Ini akan membantu untuk mencapai ketersediaan yang tinggi |
| 15 | +dan juga penggunaan sumber daya yang efisien. |
| 16 | + |
| 17 | +{{% /capture %}} |
| 18 | + |
| 19 | +{{% capture body %}} |
| 20 | + |
| 21 | +## Persyaratan |
| 22 | + |
| 23 | +### Mengaktifkan Gerbang Fitur |
| 24 | + |
| 25 | +[Gerbang fitur (_feature gate_)](/docs/reference/command-line-tools-reference/feature-gates/) |
| 26 | +`EvenPodsSpread` harus diaktifkan untuk |
| 27 | +{{< glossary_tooltip text="API Server" term_id="kube-apiserver" >}} **dan** |
| 28 | +{{< glossary_tooltip text="penjadwal (_scheduler_)" term_id="kube-scheduler" >}}. |
| 29 | + |
| 30 | +### Label Node |
| 31 | + |
| 32 | +Batasan persebaran topologi bergantung dengan label pada Node untuk menentukan |
| 33 | +domain topologi yang memenuhi untuk semua Node. Misalnya saja, sebuah Node bisa memiliki |
| 34 | +label sebagai berikut: `node=node1,zone=us-east-1a,region=us-east-1` |
| 35 | + |
| 36 | +Misalkan kamu memiliki klaster dengan 4 Node dengan label sebagai berikut: |
| 37 | + |
| 38 | +``` |
| 39 | +NAME STATUS ROLES AGE VERSION LABELS |
| 40 | +node1 Ready <none> 4m26s v1.16.0 node=node1,zone=zoneA |
| 41 | +node2 Ready <none> 3m58s v1.16.0 node=node2,zone=zoneA |
| 42 | +node3 Ready <none> 3m17s v1.16.0 node=node3,zone=zoneB |
| 43 | +node4 Ready <none> 2m43s v1.16.0 node=node4,zone=zoneB |
| 44 | +``` |
| 45 | + |
| 46 | +Maka klaster tersebut secara logika akan dilihat sebagai berikut: |
| 47 | + |
| 48 | +``` |
| 49 | ++---------------+---------------+ |
| 50 | +| zoneA | zoneB | |
| 51 | ++-------+-------+-------+-------+ |
| 52 | +| node1 | node2 | node3 | node4 | |
| 53 | ++-------+-------+-------+-------+ |
| 54 | +``` |
| 55 | + |
| 56 | +Tanpa harus memberi label secara manual, kamu dapat menggunakan [label ternama] |
| 57 | +(/docs/reference/kubernetes-api/labels-annotations-taints/) yang terbuat dan terkumpulkan |
| 58 | +secara otomatis pada kebanyakan klaster. |
| 59 | + |
| 60 | +## Batasan Persebaran untuk Pod |
| 61 | + |
| 62 | +### API |
| 63 | + |
| 64 | +_Field_ `pod.spec.topologySpreadConstraints` diperkenalkan pada versi 1.16 sebagai berikut: |
| 65 | + |
| 66 | +```yaml |
| 67 | +apiVersion: v1 |
| 68 | +kind: Pod |
| 69 | +metadata: |
| 70 | + name: mypod |
| 71 | +spec: |
| 72 | + topologySpreadConstraints: |
| 73 | + - maxSkew: <integer> |
| 74 | + topologyKey: <string> |
| 75 | + whenUnsatisfiable: <string> |
| 76 | + labelSelector: <object> |
| 77 | +``` |
| 78 | +
|
| 79 | +Kamu dapat mendefinisikan satu atau lebih `topologySpreadConstraint` untuk menginstruksikan |
| 80 | +kube-scheduler mengenai cara peletakan tiap Pod baru dengan menggunakan kondisi Pod yang |
| 81 | +sudah ada dalam klaster kamu. _Field_ yang ada adalah: |
| 82 | + |
| 83 | +- **maxSkew** menentukan batasan yang menandakan Pod tidak tersebar secara merata. |
| 84 | +Ini merupakan nilai maksimal dari selisih jumlah Pod yang sama untuk setiap 2 domain topologi |
| 85 | +yang sama. Nilai ini harus lebih dari 0. |
| 86 | +- **topologyKey** adalah kunci dari label Node. Jika terdapat dua Node memiliki label dengan |
| 87 | +kunci ini dan memiliki nilai yang identik untuk label tersebut, maka penjadwal akan menganggap |
| 88 | +kedua Noode dalam topologi yang sama. Penjadwal akan mencoba untuk menyeimbangkan jumlah Pod |
| 89 | +dalam setiap domain topologi. |
| 90 | +- **whenUnsatisfiable** mengindikasikan cara menangani Pod yang tidak memenuhi batasan persebaran: |
| 91 | + - `DoNotSchedule` (_default_) memberitahukan penjadwal untuk tidak menjadwalkan Pod tersebut. |
| 92 | + - `ScheduleAnyway` memberitahukan penjadwal untuk tetap menjadwalkan Pod namun tetap menjaga ketidakseimbangan Node sekecil mungkin. |
| 93 | +- **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](/id/docs/concepts/overview/working-with-objects/labels/#selektor-label) untuk lebih detailnya. |
| 94 | + |
| 95 | +Kamu juga bisa membaca lebih detail mengenai _field_ ini dengan menjalankan perintah |
| 96 | +`kubectl explain Pod.spec.topologySpreadConstraints`. |
| 97 | + |
| 98 | +### Contoh: Satu TopologySpreadConstraint |
| 99 | + |
| 100 | +Misalkan kamu memiliki klaster dengan 4 Node dimana 3 Pod berlabel `foo:bar` terdapat pada node1, |
| 101 | +node2 dan node3 (`P` merepresentasikan Pod): |
| 102 | + |
| 103 | +``` |
| 104 | ++---------------+---------------+ |
| 105 | +| zoneA | zoneB | |
| 106 | ++-------+-------+-------+-------+ |
| 107 | +| node1 | node2 | node3 | node4 | |
| 108 | ++-------+-------+-------+-------+ |
| 109 | +| P | P | P | | |
| 110 | ++-------+-------+-------+-------+ |
| 111 | +``` |
| 112 | + |
| 113 | +Jika kita ingin Pod baru akan disebar secara merata berdasarkan Pod yang telah ada pada semua zona, |
| 114 | +maka _spec_ bernilai sebagai berikut: |
| 115 | + |
| 116 | +{{< codenew file="pods/topology-spread-constraints/one-constraint.yaml" >}} |
| 117 | + |
| 118 | +`topologyKey: zone` berarti persebaran merata hanya akan digunakan pada Node dengan pasangan label |
| 119 | +"zone: <nilai apapun>". `whenUnsatisfiable: DoNotSchedule` memberitahukan penjadwal untuk membiarkan |
| 120 | +tetap ditunda jika Pod yang baru tidak memenuhi batasan yang diterapkan. |
| 121 | + |
| 122 | +Jika penjadwal menempatkan Pod baru pada "zoneA", persebaran Pod akan menjadi [3, 1], menjadikan |
| 123 | +ketidakseimbangan menjadi bernilai 2 (3 - 1), yang mana akan melanggar batasan `maxSkew: 1`. |
| 124 | +Dalam contoh ini, Pod baru hanya dapat ditempatkan pada "zoneB": |
| 125 | + |
| 126 | +``` |
| 127 | ++---------------+---------------+ +---------------+---------------+ |
| 128 | +| zoneA | zoneB | | zoneA | zoneB | |
| 129 | ++-------+-------+-------+-------+ +-------+-------+-------+-------+ |
| 130 | +| node1 | node2 | node3 | node4 | OR | node1 | node2 | node3 | node4 | |
| 131 | ++-------+-------+-------+-------+ +-------+-------+-------+-------+ |
| 132 | +| P | P | P | P | | P | P | P P | | |
| 133 | ++-------+-------+-------+-------+ +-------+-------+-------+-------+ |
| 134 | +``` |
| 135 | + |
| 136 | +Kamu dapat mengatur spesifikasi Pod untuk memenuhi beberapa persyaratan berikut: |
| 137 | + |
| 138 | +- Ubah nilai `maxSkew` menjadi lebih besar, misal "2", sehingga Pod baru dapat ditempatkan pada "zoneA". |
| 139 | +- Ubah nilai `topologyKey` menjadi "node" agar Pod disebarkan secara merata pada semua Node, bukan zona. Pada contoh di atas, jika `maxSkew` tetap bernilai "1", maka Pod baru hanya akan ditempatkan pada "node4". |
| 140 | +- Ubah nilai `whenUnsatisfiable: DoNotSchedule` menjadi `whenUnsatisfiable: ScheduleAnyway` untuk |
| 141 | +menjamin agar semua Pod baru akan tetap dijadwalkan (misalkan saja API penjadwalan lain tetap |
| 142 | +terpenuhi). Namun, ini lebih suka ditempatkan pada domain topologi yang memiliki lebih sedikit |
| 143 | +Pod yang sesuai. (Harap diperhatikan bahwa preferensi ini digabungkan bersama dengan prioritas |
| 144 | +penjadwalan internal yang lain, seperti rasio penggunaan sumber daya, dan lain sebagainya.) |
| 145 | + |
| 146 | +### Contoh: Beberapa TopologySpreadConstraint |
| 147 | + |
| 148 | +Ini dibuat berdasarkan contoh sebelumnya. Misalkan kamu memiliki klaster dengan 4 Node dengan |
| 149 | +3 Pod berlabel `foo:bar` yang ditempatkan pada node1, node2 dan node3. (`P` merepresentasikan Pod): |
| 150 | + |
| 151 | +``` |
| 152 | ++---------------+---------------+ |
| 153 | +| zoneA | zoneB | |
| 154 | ++-------+-------+-------+-------+ |
| 155 | +| node1 | node2 | node3 | node4 | |
| 156 | ++-------+-------+-------+-------+ |
| 157 | +| P | P | P | | |
| 158 | ++-------+-------+-------+-------+ |
| 159 | +``` |
| 160 | + |
| 161 | +Kamu dapat menggunakan 2 TopologySpreadConstraint untuk mengatur persebaran Pod pada zona dan Node: |
| 162 | + |
| 163 | +{{< codenew file="pods/topology-spread-constraints/two-constraints.yaml" >}} |
| 164 | + |
| 165 | +Dalam contoh ini, untuk memenuhi batasan pertama, Pod yang baru hanya akan ditempatkan pada "zoneB", |
| 166 | +sedangkan untuk batasan kedua, Pod yang baru hanya akan ditempatkan pada "node4". Maka hasil dari |
| 167 | +2 batasan ini akan digunakan (_AND_), sehingga opsi untuk menempatkan Pod hanya pada "node4". |
| 168 | + |
| 169 | +Beberapa batasan dapat berujung pada konflik. Misalnya saja kamu memiliki klaster dengan 3 Node |
| 170 | +pada 2 zona berbeda: |
| 171 | + |
| 172 | +``` |
| 173 | ++---------------+-------+ |
| 174 | +| zoneA | zoneB | |
| 175 | ++-------+-------+-------+ |
| 176 | +| node1 | node2 | node3 | |
| 177 | ++-------+-------+-------+ |
| 178 | +| P P | P | P P | |
| 179 | ++-------+-------+-------+ |
| 180 | +``` |
| 181 | + |
| 182 | +Jika kamu menerapkan "two-constraints.yaml" pada klaster ini, kamu akan mendapatkan "mypod" tetap |
| 183 | +dalam kondisi `Pending`. Ini dikarenakan oleh: untuk memenuhi batasan pertama, "mypod" hanya dapat |
| 184 | +ditempatkan pada "zoneB", sedangkan untuk batasan kedua, "mypod" hanya dapat ditempatkan pada |
| 185 | +"node2". Tidak ada hasil penggabungan dari "zoneB" dan "node2". |
| 186 | + |
| 187 | +Untuk mengatasi situasi ini, kamu bisa menambahkan nilai `maxSkew` atau mengubah salah satu dari |
| 188 | +batasan untuk menggunakan `whenUnsatisfiable: ScheduleAnyway`. |
| 189 | + |
| 190 | +### Konvensi |
| 191 | + |
| 192 | +Ada beberapa konvensi implisit yang perlu diperhatikan di sini: |
| 193 | + |
| 194 | +- Hanya Pod dengan Namespace yang sama dengan Pod baru yang bisa menjadi kandidat yang cocok. |
| 195 | + |
| 196 | +- Node tanpa memiliki `topologySpreadConstraints[*].topologyKey` akan dilewatkan. Ini berarti: |
| 197 | + 1. 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". |
| 198 | + 2. 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". |
| 199 | + |
| 200 | +- Harap diperhatikan mengenai hal yang terjadi jika nilai `topologySpreadConstraints[*].labelSelector` pada Pod yang baru tidak sesuai dengan labelnya. |
| 201 | +Pada contoh di atas, jika kita menghapus label pada Pod yang baru, maka Pod akan tetap ditempatkan |
| 202 | +pada "zoneB" karena batasan yang ada masih terpenuhi. Namun, setelah ditempatkan, nilai |
| 203 | +ketidakseimbangan pada klaster masih tetap tidak berubah, zoneA tetap memiliki 2 Pod dengan label |
| 204 | +{foo:bar} dan zoneB memiliki 1 Pod dengan label {foo:bar}. Jadi jika ini tidak yang kamu harapkan, |
| 205 | +kami menyarankan nilai dari `topologySpreadConstraints[*].labelSelector` disamakan dengan labelnya. |
| 206 | + |
| 207 | +- Jika Pod yang baru memiliki `spec.nodeSelector` atau `spec.affinity.nodeAffinity`, Node yang tidak |
| 208 | +sesuai dengan nilai tersebut akan dilewatkan. |
| 209 | + |
| 210 | + Misalkan kamu memiliki klaster dengan 5 Node dari zoneA sampai zoneC: |
| 211 | + |
| 212 | + ``` |
| 213 | + +---------------+---------------+-------+ |
| 214 | + | zoneA | zoneB | zoneC | |
| 215 | + +-------+-------+-------+-------+-------+ |
| 216 | + | node1 | node2 | node3 | node4 | node5 | |
| 217 | + +-------+-------+-------+-------+-------+ |
| 218 | + | P | P | P | | | |
| 219 | + +-------+-------+-------+-------+-------+ |
| 220 | + ``` |
| 221 | + |
| 222 | + dan kamu mengetahui bahwa "zoneC" harus tidak diperhitungkan. Dalam kasus ini, kamu dapat membuat |
| 223 | + berkas yaml seperti di bawah, jadi "mypod" akan ditempatkan pada "zoneB", bukan "zoneC". |
| 224 | + Demikian juga `spec.nodeSelector` akan digunakan. |
| 225 | + |
| 226 | + {{< codenew file="pods/topology-spread-constraints/one-constraint-with-nodeaffinity.yaml" >}} |
| 227 | + |
| 228 | +### Batasan _default_ pada tingkat klaster |
| 229 | + |
| 230 | +{{< feature-state for_k8s_version="v1.18" state="alpha" >}} |
| 231 | + |
| 232 | +Ini memungkinkan untuk mengatur batasan persebaran topologi bawaan untuk klaster. |
| 233 | +Batasan persebaran topologi bawaan akan digunakan pada Pod jika dan hanya jika: |
| 234 | + |
| 235 | +- Hal ini tidak mendefinisikan batasan apapun pada `.spec.topologySpreadConstraints`. |
| 236 | +- Hal ini milik sebuah Service, ReplicationController, ReplicaSet atau StatefulSet. |
| 237 | + |
| 238 | +Batasan bawaan akan diatur sebagai bagian dari argumen pada _plugin_ `PodTopologySpread` |
| 239 | +di dalam sebuah [profil penjadwalan](/docs/reference/scheduling/profiles). |
| 240 | +Batasan dispesifikasikan dengan [API yang sama dengan di atas](#api), kecuali bagian `labelSelector` |
| 241 | +harus kosong. _selector_ akan dihitung dari Service, ReplicationController, ReplicaSet atau |
| 242 | +StatefulSet yang dimiliki oleh Pod tersebut. |
| 243 | + |
| 244 | +Sebuah contoh konfigurasi sebagai berikut: |
| 245 | + |
| 246 | + |
| 247 | +```yaml |
| 248 | +apiVersion: kubescheduler.config.k8s.io/v1alpha2 |
| 249 | +kind: KubeSchedulerConfiguration |
| 250 | +
|
| 251 | +profiles: |
| 252 | + pluginConfig: |
| 253 | + - name: PodTopologySpread |
| 254 | + args: |
| 255 | + defaultConstraints: |
| 256 | + - maxSkew: 1 |
| 257 | + topologyKey: failure-domain.beta.kubernetes.io/zone |
| 258 | + whenUnsatisfiable: ScheduleAnyway |
| 259 | +``` |
| 260 | + |
| 261 | +{{< note >}} |
| 262 | +Nilai yang dihasilkan oleh batasan penjadwalan bawaan mungkin akan konflik dengan |
| 263 | +nilai yang dihasilkan oleh |
| 264 | +[`DefaultPodTopologySpread` plugin](/docs/reference/scheduling/profiles/#scheduling-plugins). |
| 265 | +Direkomendasikan untuk kamu menonaktifkan _plugin_ ini dalam profil penjadwalan ketika |
| 266 | +menggunakan batasan _default_ untuk `PodTopologySpread`. |
| 267 | +{{< /note >}} |
| 268 | + |
| 269 | +## Perbandingan dengan PodAffinity/PodAntiAffinity |
| 270 | + |
| 271 | +Di Kubernetes, arahan yang terkait dengan "Afinitas" mengontrol bagaimana Pod dijadwalkan - |
| 272 | +lebih terkumpul atau lebih tersebar. |
| 273 | + |
| 274 | +- Untuk `PodAffinity`, kamu dapat mencoba mengumpulkan beberapa Pod ke dalam suatu |
| 275 | +domain topologi yang memenuhi syarat. |
| 276 | +- Untuk `PodAntiAffinity`, hanya satu Pod yang dalam dijadwalkan pada sebuah domain topologi. |
| 277 | + |
| 278 | +Fitur "EvenPodsSpread" memberikan opsi fleksibilas untuk mendistribusikan Pod secara merata |
| 279 | +pada domain topologi yang berbeda, untuk meraih ketersediaan yang tinggi atau menghemat biaya. |
| 280 | +Ini juga dapat membantu saat perbaruan bergilir dan menaikan jumlah replika dengan lancar. |
| 281 | +Silakan baca [motivasi](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20190221-even-pods-spreading.md#motivation) untuk lebih detail. |
| 282 | + |
| 283 | +## Limitasi yang diketahui |
| 284 | + |
| 285 | +Pada versi 1.18, dimana fitur ini masih Beta, beberapa limitasi yang sudah diketahui: |
| 286 | + |
| 287 | +- Pengurangan jumlah Deployment akan membuat ketidakseimbangan pada persebaran Pod. |
| 288 | +- Pod yang cocok pada _tainted_ Node akan dihargai. Lihat [Issue 80921](https://github.com/kubernetes/kubernetes/issues/80921) |
| 289 | + |
| 290 | +{{% /capture %}} |
0 commit comments