Skip to content

Commit 045e81d

Browse files
committed
ID translation for pod topology spread constraints
1 parent f85277d commit 045e81d

File tree

4 files changed

+356
-0
lines changed

4 files changed

+356
-0
lines changed
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
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 %}}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
kind: Pod
2+
apiVersion: v1
3+
metadata:
4+
name: mypod
5+
labels:
6+
foo: bar
7+
spec:
8+
topologySpreadConstraints:
9+
- maxSkew: 1
10+
topologyKey: zone
11+
whenUnsatisfiable: DoNotSchedule
12+
labelSelector:
13+
matchLabels:
14+
foo: bar
15+
affinity:
16+
nodeAffinity:
17+
requiredDuringSchedulingIgnoredDuringExecution:
18+
nodeSelectorTerms:
19+
- matchExpressions:
20+
- key: zone
21+
operator: NotIn
22+
values:
23+
- zoneC
24+
containers:
25+
- name: pause
26+
image: k8s.gcr.io/pause:3.1
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
kind: Pod
2+
apiVersion: v1
3+
metadata:
4+
name: mypod
5+
labels:
6+
foo: bar
7+
spec:
8+
topologySpreadConstraints:
9+
- maxSkew: 1
10+
topologyKey: zone
11+
whenUnsatisfiable: DoNotSchedule
12+
labelSelector:
13+
matchLabels:
14+
foo: bar
15+
containers:
16+
- name: pause
17+
image: k8s.gcr.io/pause:3.1
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
kind: Pod
2+
apiVersion: v1
3+
metadata:
4+
name: mypod
5+
labels:
6+
foo: bar
7+
spec:
8+
topologySpreadConstraints:
9+
- maxSkew: 1
10+
topologyKey: zone
11+
whenUnsatisfiable: DoNotSchedule
12+
labelSelector:
13+
matchLabels:
14+
foo: bar
15+
- maxSkew: 1
16+
topologyKey: node
17+
whenUnsatisfiable: DoNotSchedule
18+
labelSelector:
19+
matchLabels:
20+
foo: bar
21+
containers:
22+
- name: pause
23+
image: k8s.gcr.io/pause:3.1

0 commit comments

Comments
 (0)