Dasar-dasar StatefulSet

Tutorial ini memberikan pengantar untuk manajemen aplikasi dengan StatefulSet. Di sini dicontohkan bagaimana cara untuk membuat, menghapus, melakukan penyekalaan, dan memperbarui Pod dari StatefulSet.

Sebelum kamu memulai

Sebelum memulai tutorial ini, kamu harus mengakrabkan dirimu dengan konsep-konsep Kubernetes sebagai berikut:

Tujuan

StatefulSet ditujukan untuk digunakan dengan aplikasi-aplikasi stateful dan sistem terdistribusi. Akan tetapi, tata kelola aplikasi-aplikasi stateful dan sistem terdistribusi pada Kubernetes merupakan topik yang luas dan kompleks. Untuk menunjukkan fitur-fitur dasar dari StatefulSet dan tidak mencampuradukkan topik sebelum dan terakhir, kamu akan menggelar sebuah aplikasi web sederhana menggunakan StatefulSet.

Setelah tutorial ini, kamu akan akrab hal-hal berikut:

  • Bagaimana cara membuat sebuah StatefulSet
  • Bagaimana suatu StatefulSet mengelola Pod
  • Bagaimana cara menghapus StatefulSet
  • Bagaimana cara melakukan penyekalaan terhadap suatu StatefulSet
  • Bagaimana cara memperbarui Pod dari StatefulSet

Membuat Sebuah StatefulSet

Mulailah dengan membuat sebuah Statefulset dengan menggunakan contoh di bawah ini. Hal ini mirip dengan contoh yang ditunjukkan di dalam konsep StatefulSet. Contoh ini menciptakan sebuah Service headless, nginx, untuk mempublikasikan alamat IP Pod di dalam StatefulSet, web.

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

Unduh contoh di atas, dan simpan ke dalam berkas dengan nama web.yaml.

Kamu perlu menggunakan dua jendela terminal. Pada terminal yang pertama, gunakan perintah kubectl get untuk mengamati pembuatan Pod dari StatefulSet.

kubectl get pods -w -l app=nginx

Pada terminal yang kedua, gunakan kubectl apply untuk membuat Service headless dan StatefulSet yang didefinisikan di dalam web.yaml.

kubectl apply -f web.yaml
service/nginx created
statefulset.apps/web created

Perintah di atas menciptakan dua Pod, masing-masing menjalankan server web NGINX. Dapatkan Service nginx...

kubectl get service nginx
NAME      TYPE         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx     ClusterIP    None         <none>        80/TCP    12s

...kemudian dapatkan StatefulSet web, untuk memastikan keduanya berhasil dibuat:

kubectl get statefulset web
NAME      DESIRED   CURRENT   AGE
web       2         1         20s

Pembuatan Pod Berurutan

Untuk StatefulSet dengan n replika, ketika Pod sedang digelar, kesemuanya akan dibuat secara berurutan, terurut dari {0..n-1}. Periksa keluaran dari perintah kubectl get pada terminal pertama. Pada akhirnya, keluaran yang dihasilkan akan seperti contoh di bawah ini.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     0/1       Pending   0          0s
web-0     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         19s
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         18s

Perhatikan Pod web-1 tidak dijalankan hingga web-0 berganti status menjadi Running (lihat Fase Pod) dan Ready (lihat type di Kondisi Pod).

Pod pada StatefulSet

Pod pada StatefulSet memiliki satu indeks urutan unik dan satu identitas jaringan yang tetap.

Memeriksa Indeks Urutan Pod

Dapatkan Pod dari StatefulSet:

kubectl get pods -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          1m
web-1     1/1       Running   0          1m

Sebagaimana telah disebutkan di dalam konsep StatefulSet, Pod pada StatefulSet memiliki suatu identitas yang melekat (sticky) dan unik. Identitas ini didasarkan pada sebuah indeks urutan yang unik yang di tetapkan ke masing-masing Pod oleh pengontrol StatefulSet. Nama Pod memiliki format <nama statefulset>-<indeks urutan>. Karena StatefulSet web memiliki dua replika, maka ada dua Pod yang tercipta, web-0 dan web-1.

Menggunakan Identitas Jaringan yang Tetap

Setiap Pod memiliki nama hos yang tetep berdasarkan indeks urutannya. Gunakan perintah kubectl exec untuk menjalankan perintah hostname di tiap Pod:

for i in 0 1; do kubectl exec "web-$i" -- sh -c 'hostname'; done
web-0
web-1

Gunakan perintah kubectl run untuk menjalankan sebuah Container yang menyediakan perintah nslookup dari paket dnsutils. Dengan menjalankan perintah nslookup dengan nama hos dari Pod, kamu dapat memeriksa alamat DNS mereka di dalam klaster:

kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm

perintah itu akan memulai sebuah shell baru. Pada shell tersebut, jalankan:

# Jalankan ini di dalam shell Container dns-test
nslookup web-0.nginx

Keluarannya akan seperti:

Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.1.6

nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.2.6

(dan selanjutnya keluarlah dari shell Container dengan menjalankan: exit)

CNAME dari headless service mengarah ke SRV record (satu untuk tiap Pod yang Running dan Ready). SRC record mengarah ke entri A record yang memuat alamat IP Pod.

Pada salah satu terminal, amati Pod dari StatefulSet:

kubectl get pod -w -l app=nginx

Pada terminal yang lain, gunakan perintah kubectl delete untuk menghapus semua Pod pada StatefulSet:

kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

Tunggu sampai StatefulSet menjalankan mereka kembali, dan untuk keduanya menjadi Running dan Ready:

kubectl get pod -w -l app=nginx
NAME      READY     STATUS              RESTARTS   AGE
web-0     0/1       ContainerCreating   0          0s
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          2s
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         34s

Gunakan perintah kubectl exec dan kubectl run untuk menampilkan nama hos Pod dan entri DNS mereka dalam klaster. Pertama-tama, tampilkan nama hos Pod:

for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1

selanjutnya, jalankan:

kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh

perintah itu akan menjalankan shell baru. Di dalam shell yang baru jalankan:

# Jalankan ini di dalam shell Container dns-test
nslookup web-0.nginx

Keluarannya akan seperti:

Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.1.7

nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.2.8

(dan selanjutnya keluarlah dari shell Container dengan menjalankan: exit)

Urutan, nama hos, SRV record, dan nama A record dari Pod tidak berubah, akan tetapi alamat IP yang terkait dengan Pod bisa jadi mengalami perubahan. Pada klaster yang digunakan dalam tutorial ini terjadi perubahan. Karena itulah mengapa sangat penting untuk menghindari pengaturan terhadap aplikasi lain yang terhubung ke Pod di dalam StatefulSet menggunakan alamat IP.

Jika kamu ingin mencari dan terhubung dengan anggota aktif dari StatefulSet, kamu perlu melakukan kueri CNAME dari Service headless (nginx.default.svc.cluster.local). SRV record yang terkait dengan CNAME hanya akan memuat Pod dari StatefulSet yang Running dan Ready.

Jika aplikasimu telah menerapkan logika koneksi yang menguji keaktifan (liveness) dan kesiapan (readiness), kamu dapat menggunakan SRV record dari Pod ( web-0.nginx.default.svc.cluster.local, web-1.nginx.default.svc.cluster.local), karena mereka tidak akan berubah, dan aplikasimu akan bisa menemukan alamat-alamat Pod ketika mereka mengalami peralihan ke Running dan Ready.

Dapatkan PersistentVolumeClaim untuk web-0 dan web-1:

kubectl get pvc -l app=nginx

Keluarannya akan seperti:

NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           48s
www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           48s

Pengontrol StatefulSet membuat dua PersistentVolumeClaim yang terikat ke dua PersistentVolume.

Karena klaster yang digunakan dalam tutorial ini dikonfigurasi untuk melakukan penyediaan PersistentVolume secara dinamis, maka PersistentVolume dibuat dan terikat secara otomatis.

Server web NGINX, secara bawaan, menyajikan berkas indeks dari /usr/share/nginx/html/index.html. Field volumeMounts pada spec StatefulSet memastikan direktori /usr/share/nginx/html didukung oleh sebuah PersistentVolume.

Tulis nama hos Pod ke dalam berkas index.html mereka masing-masing dan periksa apakah server web NGINX menyajikan nama hos tersebut:

for i in 0 1; do kubectl exec "web-$i" -- sh -c 'echo "$(hostname)" > /usr/share/nginx/html/index.html'; done

for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1

Di salah satu terminal, amati Pod dari StatefulSet:

kubectl get pod -w -l app=nginx

Di terminal yang lain, hapus semua Pod dari StatefulSet:

kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

Periksa keluaran dari perintah kubectl get pada terminal yang pertama dan tunggu semua Pod berubah menjadi Running dan Ready.

kubectl get pod -w -l app=nginx
NAME      READY     STATUS              RESTARTS   AGE
web-0     0/1       ContainerCreating   0          0s
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          2s
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         34s

Periksa apakah server web masih terus menyajikan nama hosnya:

for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1

Walaupun web-0 dan web-1 telah dijadwalkan ulang, mereka masih menyajikan nama hos masing-masing karena PersistentVolume yang terkait dengan PersistentVolumeClaim-nya dipasang kembali (remounted) ke setiap volumeMounts. Di Node manapun web-0 dan web-1 dijadwalkan, PersistentVolume-nya akan dipasangkan ke titik pasang (mount point) yang sesuai.

Penyekalaan StatefulSet

Melakukan penyekalaan pada StatefulSet berarti meningkatkan atau mengurangi jumlah replika. Hal ini dicapai dengan memperbarui field replicas. Kamu dapat menggunakan kubectl scale atau kubectl patch untuk melakukan penyekalaan terhadap StatefulSet.

Penyekalaan Naik

Pada salah satu jendela terminal, amati Pod pada StatefulSet:

kubectl get pods -w -l app=nginx

Di jendela terminal yang lain gunakan perintah kubectl scale untuk melakukan penyekalaan jumlah replika menjadi 5:

kubectl scale sts web --replicas=5
statefulset.apps/web scaled

Periksa keluaran dari perintah kubectl get pada terminal pertama dan tunggu tambahan tiga Pod yang baru berubah menjadi Running dan Ready.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          2h
web-1     1/1       Running   0          2h
NAME      READY     STATUS    RESTARTS   AGE
web-2     0/1       Pending   0          0s
web-2     0/1       Pending   0         0s
web-2     0/1       ContainerCreating   0         0s
web-2     1/1       Running   0         19s
web-3     0/1       Pending   0         0s
web-3     0/1       Pending   0         0s
web-3     0/1       ContainerCreating   0         0s
web-3     1/1       Running   0         18s
web-4     0/1       Pending   0         0s
web-4     0/1       Pending   0         0s
web-4     0/1       ContainerCreating   0         0s
web-4     1/1       Running   0         19s

Pengontrol StatefulSet telah melakukan penyekalaan terhadap jumlah replika. Sama seperti pembuatan StatefulSet, pengontrol StatefulSet membuat tiap Pod berurutan sesuai dengan indeks urutan masing-masing dan menunggu setiap Pod yang dibuat sebelumnya menjadi Running dan Ready sebelum menjalankan Pod berikutnya.

Penyekalaan Turun

Di salah satu terminal, amati Pod pada StatefulSet:

kubectl get pods -w -l app=nginx

Di terminal yang lain, gunakan perintah kubectl patch untuk melakukan penyekalaan StatefulSet turun menjadi tiga replika:

kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched

Tunggu hingga web-4 dan web-3 berubah menjadi Terminating.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          3h
web-1     1/1       Running             0          3h
web-2     1/1       Running             0          55s
web-3     1/1       Running             0          36s
web-4     0/1       ContainerCreating   0          18s
NAME      READY     STATUS    RESTARTS   AGE
web-4     1/1       Running   0          19s
web-4     1/1       Terminating   0         24s
web-4     1/1       Terminating   0         24s
web-3     1/1       Terminating   0         42s
web-3     1/1       Terminating   0         42s

Penghentian Pod Berurutan

Pengontrol menghapus satu Pod dalam satu waktu, dengan urutan terbalik dari indeks urutannya, dan setiap Pod akan ditunggu sampai benar-benar mati terlebih dahulu sebelum menghapus Pod berikutnya.

Dapatkan PersistentVolumeClaim dari StatefulSet:

kubectl get pvc -l app=nginx
NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-2   Bound     pvc-e1125b27-b508-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-3   Bound     pvc-e1176df6-b508-11e6-932f-42010a800002   1Gi        RWO           13h
www-web-4   Bound     pvc-e11bb5f8-b508-11e6-932f-42010a800002   1Gi        RWO           13h

Di sana masih ada lima PersistentVolumeClaim dan lima PersistentVolume. Ketika mengeksplorasi penyimpanan tetap pada Pod, kita dapat melihat bahwa PersistentVolume yang terpasang pada Pod dari suatu StatefulSet tidak terhapus ketika Pod-nya dihapus. Hal ini tetap berlaku ketika penghapusan Pod terjadi karena penyekalaan turun pada suatu StatefulSet.

Memperbarui StatefulSet

Di Kubernetes 1.7 dan yang lebih baru, pengontrol StatefulSet mendukung pembaruan otomatis. Strategi yang digunakan ditentukan oleh field spec.updateStrategy dari objek API StatefulSet. Fitur ini dapat digunakan untuk memperbarui image Container, permintaan sumber daya dan/atau pembatasan, label, dan anotasi Pod dalam suatu StatefulSet. Ada dua strategi pembaruan yang berlaku, RollingUpdate dan OnDelete.

Pembaruan dengan RollingUpdate adalah strategi bawaan untuk StatefulSet.

Pembaruan Bertahap (RollingUpdate)

Pembaruan dengan strategi RollingUpdate akan memperbarui semua Pod di dalam StatefulSet dalam urutan indeks terbalik, dengan tetap memperhatikan jaminan dari StatefulSet.

Lakukan patch pada StatefulSet web dengan menerapkan RollingUpdate:

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched

Pada salah satu jendela terminal, patch StatefulSet web untuk mengubah image Container lagi:

kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]'
statefulset.apps/web patched

Pada terminal yang lain, amati Pod pada StatefulSet:

kubectl get pod -l app=nginx -w

Keluarannya akan seperti:

NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          7m
web-1     1/1       Running   0          7m
web-2     1/1       Running   0          8m
web-2     1/1       Terminating   0         8m
web-2     1/1       Terminating   0         8m
web-2     0/1       Terminating   0         8m
web-2     0/1       Terminating   0         8m
web-2     0/1       Terminating   0         8m
web-2     0/1       Terminating   0         8m
web-2     0/1       Pending   0         0s
web-2     0/1       Pending   0         0s
web-2     0/1       ContainerCreating   0         0s
web-2     1/1       Running   0         19s
web-1     1/1       Terminating   0         8m
web-1     0/1       Terminating   0         8m
web-1     0/1       Terminating   0         8m
web-1     0/1       Terminating   0         8m
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         6s
web-0     1/1       Terminating   0         7m
web-0     1/1       Terminating   0         7m
web-0     0/1       Terminating   0         7m
web-0     0/1       Terminating   0         7m
web-0     0/1       Terminating   0         7m
web-0     0/1       Terminating   0         7m
web-0     0/1       Pending   0         0s
web-0     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         10s

Pod dalam StatefulSet diperbarui dengan urutan indeks terbalik. Pengontrol StatefulSet mengakhiri setiap Pod, dan menunggunya beralih menjadi Running dan Ready sebelum melakukan pembaruan ke Pod berikutnya. Sebagai catatan, walaupun pengontrol StatefulSet tidak akan melanjutkan pembaruan terhadap Pod berikutnya hingga penggantinya Running dan Ready, pengontrol akan memulihkan Pod apa pun yang mengalami kegagalan selama proses pembaruan berlangsung.

Pod yang telah menerima pembaruan akan dipulihkan ke versi yang diperbarui, sedangkan Pod yang belum menerima pembaruan akan dipulihkan ke versi sebelumnya. Dengan cara inilah pengontrol mencoba untuk terus mempertahankan kesehatan aplikasi dan pembaruan tetap konsisten ditengah adanya kemungkinan kegagalan intermiten.

Dapatkan Pod untuk melihat image Container-nya:

for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
k8s.gcr.io/nginx-slim:0.8
k8s.gcr.io/nginx-slim:0.8
k8s.gcr.io/nginx-slim:0.8

Semua Pod pada StatefulSet saat ini sedang menjalankan image Container sebelumnya.

Pembaruan dengan Staging

Kamu dapat melakukan staging terhadap suatu pembaruan StatefulSet dengan menggunakan parameter partition dari strategi pembaruan RollingUpdate. Suatu pembaruan yang di-staging akan akan mempertahankan semua Pod dalam StatefulSet tersebut pada versi yang digunakan saat ini sembari mengizinkan terjadinya perubahan pada .spec.template dari StatefulSet.

Lakukan patch terhadap StatefulSet web untuk menambahkan partisi pada field updateStrategy:

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset.apps/web patched

Lakukan patch terhadap StatefulSet lagi, untuk mengubah image Container:

kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
statefulset.apps/web patched

Hapus sebuah Pod dari StatefulSet:

kubectl delete pod web-2
pod "web-2" deleted

Tunggu hingga Pod menjadi Running dan Ready.

kubectl get pod -l app=nginx -w
NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          4m
web-1     1/1       Running             0          4m
web-2     0/1       ContainerCreating   0          11s
web-2     1/1       Running   0         18s

Dapatkan image Container Pod:

kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
k8s.gcr.io/nginx-slim:0.8

Perhatikan, walaupun strategi pembaruan yang digunakan adalah RollingUpdate, StatefulSet mengembalikan Pod dengan Container-nya yang semula. Hal ini karena urutan Pod kurang dari nilai partition yang ditetapkan pada updateStrategy.

Meluncurkan Canary

Kamu dapat meluncurkan canary untuk mencoba suatu perubahan dengan mengurangi partition yang kamu tentukan sebelumnya di atas.

Lakukan patch terhadap StatefulSet untuk mengurangi jumlah partisi:

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
statefulset.apps/web patched

Tunggu hingga web-2 menjadi Running dan Ready.

kubectl get pod -l app=nginx -w
NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          4m
web-1     1/1       Running             0          4m
web-2     0/1       ContainerCreating   0          11s
web-2     1/1       Running   0         18s

Dapatkan image Container Pod:

kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
k8s.gcr.io/nginx-slim:0.7

Ketika kamu mengubah partition, pengontrol StatefulSet secara otomatis memperbarui Pod web-2 karena urutan dari Pod tersebut lebih besar dari atau sama dengan nilai partition.

Hapus Pod web-1:

kubectl delete pod web-1
pod "web-1" deleted

Tunggu sampai Pod web-1 menjadi Running dan Ready.

kubectl get pod -l app=nginx -w

Keluarannya akan seperti:

NAME      READY     STATUS        RESTARTS   AGE
web-0     1/1       Running       0          6m
web-1     0/1       Terminating   0          6m
web-2     1/1       Running       0          2m
web-1     0/1       Terminating   0         6m
web-1     0/1       Terminating   0         6m
web-1     0/1       Terminating   0         6m
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       ContainerCreating   0         0s
web-1     1/1       Running   0         18s

Dapatkan image Container dari Pod web-1:

kubectl get pod web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
k8s.gcr.io/nginx-slim:0.8

web-1 dikembalikan ke konfigurasinya yang semula karena urutan Pod lebih kecil dari partisi. Ketika partisi ditentukan, semua Pod dengan urutan yang lebih besar dari atau sama dengan jumlah partisi akan diperbarui ketika .spec.template dari StatefulSet diubah. Jika suatu Pod yang memiliki urutan lebih kecil dari partisi dihapus atau diakhiri, Pod tersebut akan dikembalikan ke konfigurasinya yang semula.

Peluncuran Bertahap

Kamu dapat melakukan peluncuran bertahap (misalkan peluncuran: linier, geometris, atau eksponensial) dengan menggunakan pembaruan bertahap yang terpartisi dengan cara yang serupa ketika kamu meluncurkan canary. Untuk melakukan peluncuran bertahap, atur partition ke urutan di mana kamu menginginkan pengontrol untuk melakukan pause terhadap pembaruan.

Saat ini partisi sedang di atur menjadi 2. Ganti partisi menjadi 0:

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
statefulset.apps/web patched

Tunggu semua Pod pada StatefulSet menjadi Running dan Ready.

kubectl get pod -l app=nginx -w

Keluarannya akan seperti:

NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          3m
web-1     0/1       ContainerCreating   0          11s
web-2     1/1       Running             0          2m
web-1     1/1       Running   0         18s
web-0     1/1       Terminating   0         3m
web-0     1/1       Terminating   0         3m
web-0     0/1       Terminating   0         3m
web-0     0/1       Terminating   0         3m
web-0     0/1       Terminating   0         3m
web-0     0/1       Terminating   0         3m
web-0     0/1       Pending   0         0s
web-0     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         3s

Dapatkan detail image Container dari Pod pada StatefulSet:

for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
k8s.gcr.io/nginx-slim:0.7
k8s.gcr.io/nginx-slim:0.7
k8s.gcr.io/nginx-slim:0.7

Dengan mengubah nilai partition menjadi 0, kamu mengizinkan StatefulSet untuk melanjutkan proses pembaruan.

Pembaruan OnDelete

Strategi pembaruan OnDelete menerapkan mekanisme lama (versi 1.6 dan sebelumnya). Ketika kamu memilih strategi pembaruan ini, pengontrol StatefulSet tidak akan secara otomatis melakukan pembaruan terhadap Pod ketika suatu perubahan terjadi pada field .spec.template pada StatefulSet. Strategi ini dapat dipilih dengan mengatur .spec.template.updateStrategy.type menjadi OnDelete.

Menghapus StatefulSet

StatefulSet mendukung penghapusan tidak berjenjang (non-cascading) dan berjenjang (cascading). Dalam penghapusan tidak berjenjang (non-cascading delete), Pod pada StatefulSet tidak dihapus ketika StatefulSet terhapus. Pada penghapusan berjenjang (Cascading Delete), StatefulSet bersama Pod-nya dihapus semua.

Penghapusan Tidak Berjenjang (Non-Cascading)

Pada salah satu jendela terminal, amati Pod pada StatefulSet.

kubectl get pods -w -l app=nginx

Gunakan perintah kubectl delete untuk menghapus StatefulSet. Pastikan kamu menambahkan parameter --cascade=orphan ke perintah tersebut. Parameter ini memberitahukan Kubernetes untuk hanya menghapus StatefulSet dan agar tidak menghapus Pod yang ada padanya.

kubectl delete statefulset web --cascade=orphan
statefulset.apps "web" deleted

Dapatkan Pod untuk melihat statusnya masing-masing:

kubectl get pods -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          6m
web-1     1/1       Running   0          7m
web-2     1/1       Running   0          5m

Walaupun web telah dihapus, semua Pod masih Running dan Ready. Hapus web-0:

kubectl delete pod web-0
pod "web-0" deleted

Dapatkan Pod dari StatefulSet:

kubectl get pods -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-1     1/1       Running   0          10m
web-2     1/1       Running   0          7m

Karena StatefulSet web telah dihapus, maka web-0 tidak dijalankan lagi.

Di salah satu terminal, amati Pod pada StatefulSet.

kubectl get pods -w -l app=nginx

Pada terminal yang lain, buat kembali StatefulSet. Perhatikan, terkecuali jika kamu telah menghapus Service ngingx (yang seharusnya belum kamu lakukan), kamu akan melihat sebuah galat yang mengindikasikan bahwa Service tersebut sudah ada.

kubectl apply -f web.yaml
statefulset.apps/web created
service/nginx unchanged

Abaikan galat yang terjadi. Hal itu hanya menunjukkan bahwa suatu upaya telah dilakukan untuk membuat Service headless nginx walaupun Service tersebut sebenarnya sudah ada.

Perhatikan keluaran dari perintah kubectl get yang dijalankan pada terminal yang pertama.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-1     1/1       Running   0          16m
web-2     1/1       Running   0          2m
NAME      READY     STATUS    RESTARTS   AGE
web-0     0/1       Pending   0          0s
web-0     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         18s
web-2     1/1       Terminating   0         3m
web-2     0/1       Terminating   0         3m
web-2     0/1       Terminating   0         3m
web-2     0/1       Terminating   0         3m

Ketika StatefulSet web dibuat ulang, yang dijalankan pertama kali adalah web-0. Karena web-1 telah menjadi Running dan Ready, ketika web-0 berubah menjadi Running dan Ready, web-0 mengadopsi Pod tersebut. Karena kamu membuat ulang StatefulSet dengan replicas sama dengan 2, ketika web-0 selesai dibuat ulang, dan ketika web-1 telah ditetapkan menjadi Running dan Ready, maka web-2 diakhiri.

Mari kita lihat kembali konten dari berkas index.html yang disajikan oleh server web Pod:

for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1

Walaupun kamu sebelumnya pernah menghapus StatefulSet dan Pod web-0, server web masih terus menyajikan nama hos sebelumnya yang dimasukkan ke dalam berkas index.html. Hal ini terjadi karena StatefulSet tidak menghapus PersistentVolume yang terkait dengan Pod. Ketika kamu membuat ulang StatefulSet dan menjalankan kembali web-0, PersistentVolume yang digunakan sebelumnya akan dipasang kembali.

Penghapusan Berjenjang (Cascading)

Pada salah satu jendela terminal, amati Pod pada StatefulSet.

kubectl get pods -w -l app=nginx

Pada terminal yang lain, hapus StatefulSet lagi. Kali ini, hilangkan parameter --cascade=orphan.

kubectl delete statefulset web
statefulset.apps "web" deleted

Perhatikan keluaran dari perintah kubectl get yang dijalankan di terminal yang pertama, dan tunggu semua status Pod berubah menjadi Terminating.

kubectl get pods -w -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          11m
web-1     1/1       Running   0          27m
NAME      READY     STATUS        RESTARTS   AGE
web-0     1/1       Terminating   0          12m
web-1     1/1       Terminating   0         29m
web-0     0/1       Terminating   0         12m
web-0     0/1       Terminating   0         12m
web-0     0/1       Terminating   0         12m
web-1     0/1       Terminating   0         29m
web-1     0/1       Terminating   0         29m
web-1     0/1       Terminating   0         29m

Seperti yang telah kamu saksikan pada bagian Penyekalaan Turun, Pod diakhiri satu demi satu dengan urutan terbalik dari indeks urutan mereka. Sebelum mengakhiri suatu Pod, pengontrol StatefulSet menunggu Pod pengganti hingga benar-benar berakhir.

kubectl delete service nginx
service "nginx" deleted

Buat ulang StatefulSet dan Service headless sekali lagi:

kubectl apply -f web.yaml
service/nginx created
statefulset.apps/web created

Saat semua Pod StatefulSet mengalami transisi ke Running dan Ready, dapatkan konten dari berkas index.html masing-masing:

for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1

Walaupun kamu telah menghapus StatefulSet dan semua Pod di dalamnya, Pod dibuat lagi dengan PersistentVolume yang sama terpasang, dan web-0 dan web-1 masih menyajikan nama hos masing-masing.

Akhirnya, hapus Service nginx...

kubectl delete service nginx
service "nginx" deleted

...dan StatefulSet web:

kubectl delete statefulset web
statefulset "web" deleted

Kebijakan Manajemen Pod

Untuk beberapa sistem terdistribusi, jaminan pengurutan StatefulSet tidak penting dan/atau tidak diharapkan. Sistem-sistem tersebut hanya membutuhkan keunikan dan identitas. Untuk mengatasi ini, pada Kubernetes 1.7, kami memperkenalkan .spec.podManagementPolicy pada objek API StatefulSet.

Manajemen Pod OrderedReady

Manajemen Pod OrderedReady adalah bawaan dari StatefulSet. Manajemen dengan cara ini memberitahukan pengontrol StatefulSet untuk menghormati jaminan pengurutan yang sudah ditunjukkan sebelumnya.

Manajemen Pod Parallel

Manajemen Pod Parallel memberitahukan pengontrol StatefulSet untuk menjalankan atau mengakhiri semua Pod secara bersamaan (paralel), dan tidak menunggu suatu Pod menjadi Running dan Ready atau benar-benar berakhir sebelum menjalankan atau mengakhiri Pod yang lain.

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  podManagementPolicy: "Parallel"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

Unduh contoh di atas, dan simpan ke sebuah berkas dengan nama web-parallel.yaml.

Manifes ini serupa dengan yang telah kamu unduh sebelumnya kecuali .spec.podManagementPolicy dari StatefulSet web diatur ke Parallel.

Di salah satu terminal, amati Pod pada StatefulSet.

kubectl get pod -l app=nginx -w

Pada terminal yang lain, buat StatefulSet dan Service dari manifes tadi:

kubectl apply -f web-parallel.yaml
service/nginx created
statefulset.apps/web created

Perhatikan keluaran dari perintah kubectl get yang kamu jalankan pada terminal yang pertama.

kubectl get pod -l app=nginx -w
NAME      READY     STATUS    RESTARTS   AGE
web-0     0/1       Pending   0          0s
web-0     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-1     0/1       Pending   0         0s
web-0     0/1       ContainerCreating   0         0s
web-1     0/1       ContainerCreating   0         0s
web-0     1/1       Running   0         10s
web-1     1/1       Running   0         10s

Pengontrol StatefulSet menjalankan web-0 dan web- berbarengan.

Biarkan terminal kedua tetap terbuka, kemudian, di jendela terminal yang lain lakukan penyekalaan terhadap StatefulSet:

kubectl scale statefulset/web --replicas=4
statefulset.apps/web scaled

Perhatikan keluaran terminal di mana perintah kubectl get dijalankan.

web-3     0/1       Pending   0         0s
web-3     0/1       Pending   0         0s
web-3     0/1       Pending   0         7s
web-3     0/1       ContainerCreating   0         7s
web-2     1/1       Running   0         10s
web-3     1/1       Running   0         26s

StatefulSet menjalankan dua Pod baru dan tidak menunggu Pod pertama menjadi Running dan Ready terlebih dahulu sebelum menjalankan Pod yang kedua.

Bersihkan

Kamu harus membuka dua terminal yang siap untuk menjalankan perintah kubectl sebagai bagian dari pembersihan.

kubectl delete sts web
# sts adalah singkatan dari statefulset

Kamu dapat mengamati kubectl get untuk melihat semua Pod yang sedang dihapus.

kubectl get pod -l app=nginx -w
web-3     1/1       Terminating   0         9m
web-2     1/1       Terminating   0         9m
web-3     1/1       Terminating   0         9m
web-2     1/1       Terminating   0         9m
web-1     1/1       Terminating   0         44m
web-0     1/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-3     0/1       Terminating   0         9m
web-2     0/1       Terminating   0         9m
web-1     0/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-2     0/1       Terminating   0         9m
web-2     0/1       Terminating   0         9m
web-2     0/1       Terminating   0         9m
web-1     0/1       Terminating   0         44m
web-1     0/1       Terminating   0         44m
web-1     0/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-0     0/1       Terminating   0         44m
web-3     0/1       Terminating   0         9m
web-3     0/1       Terminating   0         9m
web-3     0/1       Terminating   0         9m

Selama penghapusan, StatefulSet menghapus semua Pod secara serentak; tidak menghentikan Pod berdasarkan urutan indeksnya terlebih dahulu sebelum menghapus Pod tersebut.

Tutup terminal di mana perintah kubectl get dijalankan dan hapus Service nginx:

kubectl delete svc nginx
Last modified August 30, 2021 at 12:39 AM PST: [id] Updating --cascade=false to --cascade=orphan (570dce0dde)