ID translation for pod topology spread constraints

pull/21565/head
Gede Wahyu 2020-04-08 00:40:47 +07:00
parent f85277d6d4
commit 045e81dd8c
4 changed files with 356 additions and 0 deletions

View File

@ -0,0 +1,290 @@
---
title: Batasan Persebaran Topologi Pod
content_template: templates/concept
weight: 50
---
{{% capture overview %}}
{{< feature-state for_k8s_version="v1.18" state="beta" >}}
Kamu dapat menggunakan batasan perseberan topologi (_topology spread constraints_)
untuk mengatur bagaimana {{< glossary_tooltip text="Pod" term_id="Pod" >}} akan disebarkan
pada klaster yang ditetapkan sebagai _failure-domains_, seperti wilayah, zona, Node dan domain
topologi yang ditentukan oleh pengguna. Ini akan membantu untuk mencapai ketersediaan yang tinggi
dan juga penggunaan sumber daya yang efisien.
{{% /capture %}}
{{% capture body %}}
## Persyaratan
### Mengaktifkan Gerbang Fitur
[Gerbang fitur (_feature gate_)](/docs/reference/command-line-tools-reference/feature-gates/)
`EvenPodsSpread` harus diaktifkan untuk
{{< glossary_tooltip text="API Server" term_id="kube-apiserver" >}} **dan**
{{< glossary_tooltip text="penjadwal (_scheduler_)" term_id="kube-scheduler" >}}.
### Label Node
Batasan persebaran topologi bergantung dengan label pada Node untuk menentukan
domain topologi yang memenuhi untuk semua Node. Misalnya saja, sebuah Node bisa memiliki
label sebagai berikut: `node=node1,zone=us-east-1a,region=us-east-1`
Misalkan kamu memiliki klaster dengan 4 Node dengan label sebagai berikut:
```
NAME STATUS ROLES AGE VERSION LABELS
node1 Ready <none> 4m26s v1.16.0 node=node1,zone=zoneA
node2 Ready <none> 3m58s v1.16.0 node=node2,zone=zoneA
node3 Ready <none> 3m17s v1.16.0 node=node3,zone=zoneB
node4 Ready <none> 2m43s v1.16.0 node=node4,zone=zoneB
```
Maka klaster tersebut secara logika akan dilihat sebagai berikut:
```
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
```
Tanpa harus memberi label secara manual, kamu dapat menggunakan [label ternama]
(/docs/reference/kubernetes-api/labels-annotations-taints/) yang terbuat dan terkumpulkan
secara otomatis pada kebanyakan klaster.
## Batasan Persebaran untuk Pod
### API
_Field_ `pod.spec.topologySpreadConstraints` diperkenalkan pada versi 1.16 sebagai berikut:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
topologySpreadConstraints:
- maxSkew: <integer>
topologyKey: <string>
whenUnsatisfiable: <string>
labelSelector: <object>
```
Kamu dapat mendefinisikan satu atau lebih `topologySpreadConstraint` untuk menginstruksikan
kube-scheduler mengenai cara peletakan tiap Pod baru dengan menggunakan kondisi Pod yang
sudah ada dalam klaster kamu. _Field_ yang ada adalah:
- **maxSkew** menentukan batasan yang menandakan Pod tidak tersebar secara merata.
Ini merupakan nilai maksimal dari selisih jumlah Pod yang sama untuk setiap 2 domain topologi
yang sama. Nilai ini harus lebih dari 0.
- **topologyKey** adalah kunci dari label Node. Jika terdapat dua Node memiliki label dengan
kunci ini dan memiliki nilai yang identik untuk label tersebut, maka penjadwal akan menganggap
kedua Noode dalam topologi yang sama. Penjadwal akan mencoba untuk menyeimbangkan jumlah Pod
dalam setiap domain topologi.
- **whenUnsatisfiable** mengindikasikan cara menangani Pod yang tidak memenuhi batasan persebaran:
- `DoNotSchedule` (_default_) memberitahukan penjadwal untuk tidak menjadwalkan Pod tersebut.
- `ScheduleAnyway` memberitahukan penjadwal untuk tetap menjadwalkan Pod namun tetap menjaga ketidakseimbangan Node sekecil mungkin.
- **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.
Kamu juga bisa membaca lebih detail mengenai _field_ ini dengan menjalankan perintah
`kubectl explain Pod.spec.topologySpreadConstraints`.
### Contoh: Satu TopologySpreadConstraint
Misalkan kamu memiliki klaster dengan 4 Node dimana 3 Pod berlabel `foo:bar` terdapat pada node1,
node2 dan node3 (`P` merepresentasikan Pod):
```
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
| P | P | P | |
+-------+-------+-------+-------+
```
Jika kita ingin Pod baru akan disebar secara merata berdasarkan Pod yang telah ada pada semua zona,
maka _spec_ bernilai sebagai berikut:
{{< codenew file="pods/topology-spread-constraints/one-constraint.yaml" >}}
`topologyKey: zone` berarti persebaran merata hanya akan digunakan pada Node dengan pasangan label
"zone: <nilai apapun>". `whenUnsatisfiable: DoNotSchedule` memberitahukan penjadwal untuk membiarkan
tetap ditunda jika Pod yang baru tidak memenuhi batasan yang diterapkan.
Jika penjadwal menempatkan Pod baru pada "zoneA", persebaran Pod akan menjadi [3, 1], menjadikan
ketidakseimbangan menjadi bernilai 2 (3 - 1), yang mana akan melanggar batasan `maxSkew: 1`.
Dalam contoh ini, Pod baru hanya dapat ditempatkan pada "zoneB":
```
+---------------+---------------+ +---------------+---------------+
| zoneA | zoneB | | zoneA | zoneB |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
| node1 | node2 | node3 | node4 | OR | node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
| P | P | P | P | | P | P | P P | |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
```
Kamu dapat mengatur spesifikasi Pod untuk memenuhi beberapa persyaratan berikut:
- Ubah nilai `maxSkew` menjadi lebih besar, misal "2", sehingga Pod baru dapat ditempatkan pada "zoneA".
- 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".
- Ubah nilai `whenUnsatisfiable: DoNotSchedule` menjadi `whenUnsatisfiable: ScheduleAnyway` untuk
menjamin agar semua Pod baru akan tetap dijadwalkan (misalkan saja API penjadwalan lain tetap
terpenuhi). Namun, ini lebih suka ditempatkan pada domain topologi yang memiliki lebih sedikit
Pod yang sesuai. (Harap diperhatikan bahwa preferensi ini digabungkan bersama dengan prioritas
penjadwalan internal yang lain, seperti rasio penggunaan sumber daya, dan lain sebagainya.)
### Contoh: Beberapa TopologySpreadConstraint
Ini dibuat berdasarkan contoh sebelumnya. Misalkan kamu memiliki klaster dengan 4 Node dengan
3 Pod berlabel `foo:bar` yang ditempatkan pada node1, node2 dan node3. (`P` merepresentasikan Pod):
```
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
| P | P | P | |
+-------+-------+-------+-------+
```
Kamu dapat menggunakan 2 TopologySpreadConstraint untuk mengatur persebaran Pod pada zona dan Node:
{{< codenew file="pods/topology-spread-constraints/two-constraints.yaml" >}}
Dalam contoh ini, untuk memenuhi batasan pertama, Pod yang baru hanya akan ditempatkan pada "zoneB",
sedangkan untuk batasan kedua, Pod yang baru hanya akan ditempatkan pada "node4". Maka hasil dari
2 batasan ini akan digunakan (_AND_), sehingga opsi untuk menempatkan Pod hanya pada "node4".
Beberapa batasan dapat berujung pada konflik. Misalnya saja kamu memiliki klaster dengan 3 Node
pada 2 zona berbeda:
```
+---------------+-------+
| zoneA | zoneB |
+-------+-------+-------+
| node1 | node2 | node3 |
+-------+-------+-------+
| P P | P | P P |
+-------+-------+-------+
```
Jika kamu menerapkan "two-constraints.yaml" pada klaster ini, kamu akan mendapatkan "mypod" tetap
dalam kondisi `Pending`. Ini dikarenakan oleh: untuk memenuhi batasan pertama, "mypod" hanya dapat
ditempatkan pada "zoneB", sedangkan untuk batasan kedua, "mypod" hanya dapat ditempatkan pada
"node2". Tidak ada hasil penggabungan dari "zoneB" dan "node2".
Untuk mengatasi situasi ini, kamu bisa menambahkan nilai `maxSkew` atau mengubah salah satu dari
batasan untuk menggunakan `whenUnsatisfiable: ScheduleAnyway`.
### Konvensi
Ada beberapa konvensi implisit yang perlu diperhatikan di sini:
- Hanya Pod dengan Namespace yang sama dengan Pod baru yang bisa menjadi kandidat yang cocok.
- Node tanpa memiliki `topologySpreadConstraints[*].topologyKey` akan dilewatkan. Ini berarti:
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".
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".
- Harap diperhatikan mengenai hal yang terjadi jika nilai `topologySpreadConstraints[*].labelSelector` pada Pod yang baru tidak sesuai dengan labelnya.
Pada contoh di atas, jika kita menghapus label pada Pod yang baru, maka Pod akan tetap ditempatkan
pada "zoneB" karena batasan yang ada masih terpenuhi. Namun, setelah ditempatkan, nilai
ketidakseimbangan pada klaster masih tetap tidak berubah, zoneA tetap memiliki 2 Pod dengan label
{foo:bar} dan zoneB memiliki 1 Pod dengan label {foo:bar}. Jadi jika ini tidak yang kamu harapkan,
kami menyarankan nilai dari `topologySpreadConstraints[*].labelSelector` disamakan dengan labelnya.
- Jika Pod yang baru memiliki `spec.nodeSelector` atau `spec.affinity.nodeAffinity`, Node yang tidak
sesuai dengan nilai tersebut akan dilewatkan.
Misalkan kamu memiliki klaster dengan 5 Node dari zoneA sampai zoneC:
```
+---------------+---------------+-------+
| zoneA | zoneB | zoneC |
+-------+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 | node5 |
+-------+-------+-------+-------+-------+
| P | P | P | | |
+-------+-------+-------+-------+-------+
```
dan kamu mengetahui bahwa "zoneC" harus tidak diperhitungkan. Dalam kasus ini, kamu dapat membuat
berkas yaml seperti di bawah, jadi "mypod" akan ditempatkan pada "zoneB", bukan "zoneC".
Demikian juga `spec.nodeSelector` akan digunakan.
{{< codenew file="pods/topology-spread-constraints/one-constraint-with-nodeaffinity.yaml" >}}
### Batasan _default_ pada tingkat klaster
{{< feature-state for_k8s_version="v1.18" state="alpha" >}}
Ini memungkinkan untuk mengatur batasan persebaran topologi bawaan untuk klaster.
Batasan persebaran topologi bawaan akan digunakan pada Pod jika dan hanya jika:
- Hal ini tidak mendefinisikan batasan apapun pada `.spec.topologySpreadConstraints`.
- Hal ini milik sebuah Service, ReplicationController, ReplicaSet atau StatefulSet.
Batasan bawaan akan diatur sebagai bagian dari argumen pada _plugin_ `PodTopologySpread`
di dalam sebuah [profil penjadwalan](/docs/reference/scheduling/profiles).
Batasan dispesifikasikan dengan [API yang sama dengan di atas](#api), kecuali bagian `labelSelector`
harus kosong. _selector_ akan dihitung dari Service, ReplicationController, ReplicaSet atau
StatefulSet yang dimiliki oleh Pod tersebut.
Sebuah contoh konfigurasi sebagai berikut:
```yaml
apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
profiles:
pluginConfig:
- name: PodTopologySpread
args:
defaultConstraints:
- maxSkew: 1
topologyKey: failure-domain.beta.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
```
{{< note >}}
Nilai yang dihasilkan oleh batasan penjadwalan bawaan mungkin akan konflik dengan
nilai yang dihasilkan oleh
[`DefaultPodTopologySpread` plugin](/docs/reference/scheduling/profiles/#scheduling-plugins).
Direkomendasikan untuk kamu menonaktifkan _plugin_ ini dalam profil penjadwalan ketika
menggunakan batasan _default_ untuk `PodTopologySpread`.
{{< /note >}}
## Perbandingan dengan PodAffinity/PodAntiAffinity
Di Kubernetes, arahan yang terkait dengan "Afinitas" mengontrol bagaimana Pod dijadwalkan -
lebih terkumpul atau lebih tersebar.
- Untuk `PodAffinity`, kamu dapat mencoba mengumpulkan beberapa Pod ke dalam suatu
domain topologi yang memenuhi syarat.
- Untuk `PodAntiAffinity`, hanya satu Pod yang dalam dijadwalkan pada sebuah domain topologi.
Fitur "EvenPodsSpread" memberikan opsi fleksibilas untuk mendistribusikan Pod secara merata
pada domain topologi yang berbeda, untuk meraih ketersediaan yang tinggi atau menghemat biaya.
Ini juga dapat membantu saat perbaruan bergilir dan menaikan jumlah replika dengan lancar.
Silakan baca [motivasi](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20190221-even-pods-spreading.md#motivation) untuk lebih detail.
## Limitasi yang diketahui
Pada versi 1.18, dimana fitur ini masih Beta, beberapa limitasi yang sudah diketahui:
- Pengurangan jumlah Deployment akan membuat ketidakseimbangan pada persebaran Pod.
- Pod yang cocok pada _tainted_ Node akan dihargai. Lihat [Issue 80921](https://github.com/kubernetes/kubernetes/issues/80921)
{{% /capture %}}

View File

@ -0,0 +1,26 @@
kind: Pod
apiVersion: v1
metadata:
name: mypod
labels:
foo: bar
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: NotIn
values:
- zoneC
containers:
- name: pause
image: k8s.gcr.io/pause:3.1

View File

@ -0,0 +1,17 @@
kind: Pod
apiVersion: v1
metadata:
name: mypod
labels:
foo: bar
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
containers:
- name: pause
image: k8s.gcr.io/pause:3.1

View File

@ -0,0 +1,23 @@
kind: Pod
apiVersion: v1
metadata:
name: mypod
labels:
foo: bar
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
- maxSkew: 1
topologyKey: node
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
containers:
- name: pause
image: k8s.gcr.io/pause:3.1