Mengatur Probe Liveness, Readiness dan Startup

Laman ini memperlihatkan bagaimana cara untuk mengatur probe liveness, readiness, dan startup untuk Container.

Probe liveness digunakan oleh kubelet untuk mengetahui kapan perlu mengulang kembali (restart) sebuah Container. Sebagai contoh, probe liveness dapat mendeteksi deadlock, ketika aplikasi sedang berjalan tapi tidak dapat berfungsi dengan baik. Mengulang Container dengan state tersebut dapat membantu ketersediaan aplikasi yang lebih baik walaupun ada kekutu (bug).

Probe readiness digunakan oleh kubelet untuk mengetahui kapan sebuah Container telah siap untuk menerima lalu lintas jaringan (traffic). Suatu Pod dianggap siap saat semua Container di dalamnya telah siap. Sinyal ini berguna untuk mengontrol Pod-Pod mana yang digunakan sebagai backend dari Service. Ketika Pod dalam kondisi tidak siap, Pod tersebut dihapus dari Service load balancer.

Probe startup digunakan oleh kubelet untuk mengetahui kapan sebuah aplikasi Container telah mulai berjalan. Jika probe tersebut dinyalakan, probe akan menonaktifkan pemeriksaan liveness dan readiness sampai berhasil, kamu harus memastikan probe tersebut tidak mengganggu startup dari aplikasi. Mekanisme ini dapat digunakan untuk mengadopsi pemeriksaan liveness pada saat memulai Container yang lambat, untuk menghindari Container dimatikan oleh kubelet sebelum Container mulai dan berjalan.

Sebelum kamu memulai

Kamu harus memiliki klaster Kubernetes, dan perangkat baris perintah kubectl juga harus dikonfigurasikan untuk berkomunikasi dengan klastermu. Jika kamu belum memiliki klaster, kamu dapat membuatnya dengan menggunakan minikube, atau kamu juga dapat menggunakan salah satu dari tempat mencoba Kubernetes berikut ini:

Untuk melihat versi, tekan kubectl version.

Mendefinisikan perintah liveness

Kebanyakan aplikasi yang telah berjalan dalam waktu lama pada akhirnya akan bertransisi ke state yang rusak (broken), dan tidak dapat pulih kecuali diulang kembali. Kubernetes menyediakan probe liveness untuk mendeteksi dan memperbaiki situasi tersebut.

Pada latihan ini, kamu akan membuat Pod yang menjalankan Container dari image registry.k8s.io/busybox. Berikut ini adalah berkas konfigurasi untuk Pod tersebut:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

Pada berkas konfigurasi di atas, kamu dapat melihat bahwa Pod memiliki satu Container. Field periodSeconds menentukan bahwa kubelet harus melakukan probe liveness setiap 5 detik. Field initialDelaySeconds memberitahu kubelet untuk menunggu 5 detik sebelum mengerjakan probe yang pertama. Untuk mengerjakan probe, kubelet menjalankan perintah cat /tmp/healthy pada Container tujuan. Jika perintah berhasil, kode 0 akan dikembalikan, dan kubelet menganggap Container sedang dalam kondisi hidup (alive) dan sehat (healthy). Jika perintah mengembalikan kode selain 0, maka kubelet akan mematikan Container dan mengulangnya kembali.

Saat dimulai, Container akan menjalankan perintah berikut:

/bin/sh -c "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"

Container memiliki berkas /tmp/healthy pada saat 30 detik pertama setelah dijalankan. Kemudian, perintah cat /tmp/healthy mengembalikan kode sukses. Namun setelah 30 detik, cat /tmp/healthy mengembalikan kode gagal.

Buatlah sebuah Pod:

kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml

Dalam 30 detik pertama, lihatlah event dari Pod:

kubectl describe pod liveness-exec

Keluaran dari perintah tersebut memperlihatkan bahwa belum ada probe liveness yang gagal:

FirstSeen    LastSeen    Count   From            SubobjectPath           Type        Reason      Message
--------- --------    -----   ----            -------------           --------    ------      -------
24s       24s     1   {default-scheduler }                    Normal      Scheduled   Successfully assigned liveness-exec to worker0
23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulling     pulling image "registry.k8s.io/busybox"
23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulled      Successfully pulled image "registry.k8s.io/busybox"
23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Created     Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
23s       23s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Started     Started container with docker id 86849c15382e

Setelah 35 detik, lihatlah lagi event Pod tersebut:

kubectl describe pod liveness-exec

Baris terakhir dari keluaran tersebut memperlihatkan pesan bahwa probe liveness mengalami kegagalan, dan Container telah dimatikan dan dibuat ulang.

FirstSeen LastSeen    Count   From            SubobjectPath           Type        Reason      Message
--------- --------    -----   ----            -------------           --------    ------      -------
37s       37s     1   {default-scheduler }                    Normal      Scheduled   Successfully assigned liveness-exec to worker0
36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulling     pulling image "registry.k8s.io/busybox"
36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Pulled      Successfully pulled image "registry.k8s.io/busybox"
36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Created     Created container with docker id 86849c15382e; Security:[seccomp=unconfined]
36s       36s     1   {kubelet worker0}   spec.containers{liveness}   Normal      Started     Started container with docker id 86849c15382e
2s        2s      1   {kubelet worker0}   spec.containers{liveness}   Warning     Unhealthy   Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory

Tunggu 30 detik lagi, dan verifikasi bahwa Container telah diulang kembali:

kubectl get pod liveness-exec

Keluaran perintah tersebut memperlihatkan bahwa jumlah RESTARTS telah meningkat:

NAME            READY     STATUS    RESTARTS   AGE
liveness-exec   1/1       Running   1          1m

Mendefinisikan probe liveness dengan permintaan HTTP

Jenis kedua dari probe liveness menggunakan sebuah permintaan GET HTTP. Berikut ini berkas konfigurasi untuk Pod yang menjalankan Container dari image registry.k8s.io/liveness.

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/liveness
    args:
    - /server
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3

Pada berkas konfigurasi tersebut, kamu dapat melihat Pod memiliki sebuah Container. Field periodSeconds menentukan bahwa kubelet harus mengerjakan probe liveness setiap 3 detik. Field initialDelaySeconds memberitahu kubelet untuk menunggu 3 detik sebelum mengerjakan probe yang pertama. Untuk mengerjakan probe tersebut, kubelet mengirimkan sebuah permintaan GET HTTP ke server yang sedang berjalan di dalam Container dan mendengarkan (listen) pada porta 8080. Jika handler path /healthz yang dimiliki server mengembalikan kode sukses, kubelet menganggap Container sedang dalam kondisi hidup dan sehat. Jika handler mengembalikan kode gagal, kubelet mematikan Container dan mengulangnya kembali.

Kode yang lebih besar atau sama dengan 200 dan kurang dari 400 mengindikasikan kesuksesan. Kode selain ini mengindikasikan kegagalan.

Kamu dapat melihat kode program untuk server ini pada server.go.

Untuk 10 detik pertama setelah Container hidup (alive), handler /healthz mengembalikan status 200. Setelah itu, handler mengembalikan status 500.

http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    duration := time.Now().Sub(started)
    if duration.Seconds() > 10 {
        w.WriteHeader(500)
        w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
    } else {
        w.WriteHeader(200)
        w.Write([]byte("ok"))
    }
})

Pemeriksaan kesehatan (health check) dilakukan kubelet 3 detik setelah Container dimulai, sehingga beberapa pemeriksaaan pertama akan berhasil. Namun setelah 10 detik, pemeriksaan akan gagal, dan kubelet akan mematikan dan mengulang Container kembali.

Untuk mencoba pemeriksaan liveness HTTP, marilah membuat sebuah Pod:

kubectl apply -f https://k8s.io/examples/pods/probe/http-liveness.yaml

Setelah 10 detik, lihatlah event Pod untuk memverifikasi bahwa probe liveness telah gagal dan Container telah diulang kembali:

kubectl describe pod liveness-http

Untuk rilis sebelum v1.13 (termasuk v1.13), jika variabel lingkungan http_proxy (atau HTTP_PROXY) telah diatur pada Node dimana Pod berjalan, probe liveness HTTP akan menggunakan proksi tersebut. Untuk rilis setelah v1.13, pengaturan variabel lingkungan pada proksi HTTP lokal tidak mempengaruhi probe liveness HTTP.

Mendefinisikan probe liveness TCP

Jenis ketiga dari probe liveness menggunakaan sebuah soket TCP. Dengan konfigurasi ini, kubelet akan mencoba untuk membuka soket pada Container kamu dengan porta tertentu. Jika koneksi dapat terbentuk dengan sukses, maka Container dianggap dalam kondisi sehat. Namun jika tidak berhasil terbentuk, maka Container dianggap gagal.

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: registry.k8s.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

Seperti yang terlihat, konfigurasi untuk pemeriksaan TCP cukup mirip dengan pemeriksaan HTTP. Contoh ini menggunakan probe readiness dan liveness. Probe readiness yang pertama akan dikirimkan oleh kubelet, 5 detik setelah Container mulai dijalankan. Container akan coba dihubungkan oleh kubelet dengan goproxy pada porta 8080. Jika probe berhasil, maka Pod akan ditandai menjadi ready. Pemeriksaan ini akan dilanjutkan oleh kubelet setiap 10 detik.

Selain probe readiness, probe liveness juga termasuk di dalam konfigurasi. Probe liveness yang pertama akan dijalankan oleh kubelet, 15 detik setelah Container mulai dijalankan. Sama seperti probe readiness, kubelet akan mencoba untuk terhubung dengan Container goproxy pada porta 8080. Jika probe liveness gagal, maka Container akan diulang kembali.

Untuk mencoba pemeriksaan liveness TCP, marilah membuat sebuah Pod:

kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml

Setelah 15 detik, lihatlah event Pod untuk memverifikasi probe liveness tersebut:

kubectl describe pod goproxy

Menggunakan sebuah porta dengan nama

Kamu dapat menggunakan ContainerPort dengan nama untuk melakukan pemeriksaan liveness HTTP atau TCP:

ports:
- name: liveness-port
  containerPort: 8080

livenessProbe:
  httpGet:
    path: /healthz
    port: liveness-port

Melindungi Container yang lambat untuk dimulai dengan probe startup

Terkadang kamu harus berurusan dengan aplikasi peninggalan (legacy) yang memerlukan waktu tambahan untuk mulai berjalan pada saat pertama kali diinisialisasi. Pada kasus ini, cukup rumit untuk mengatur parameter probe liveness tanpa mengkompromikan respons yang cepat terhadap deadlock yang memotivasi digunakannya probe_ tersebut. Triknya adalah mengatur probe startup dengan perintah yang sama, baik pemeriksaan HTTP ataupun TCP, dengan failureThreshold * periodSeconds yang mencukupi untuk kemungkinan waktu memulai yang terburuk.

Sehingga, contoh sebelumnya menjadi:

ports:
- name: liveness-port
  containerPort: 8080

livenessProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 1
  periodSeconds: 10

startupProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 30
  periodSeconds: 10

Berkat probe startup, aplikasi akan memiliki paling lambat 5 menit (30 * 10 = 300 detik) untuk selesai memulai. Ketika probe startup telah berhasil satu kali, maka probe liveness akan mengambil alih untuk menyediakan respons cepat terhadap deadlock Container. Jika probe startup tidak pernah berhasil, maka Container akan dimatikan setelah 300 detik dan perilakunya akan bergantung pada restartPolicy yang dimiliki Pod.

Mendefinisikan probe readiness

Terkadang aplikasi tidak dapat melayani lalu lintas jaringan sementara. Contohnya, aplikasi mungkin perlu untuk memuat data besar atau berkas konfigurasi saat dimulai, atau aplikasi bergantung pada layanan eksternal setelah dimulai. Pada kasus-kasus ini, kamu tidak ingin mematikan aplikasi, tetapi kamu tidak ingin juga mengirimkan permintaan ke aplikasi tersebut. Kubernetes menyediakan probe readiness sebagai solusinya. Sebuah Pod dengan Container yang melaporkan dirinya tidak siap, tidak akan menerima lalu lintas jaringan dari Kubernetes Service.

Probe readiness memiliki pengaturan yang mirip dengan probe liveness. Perbedaan satu-satunya adalah kamu menggunakan field readinessProbe, bukan field livenessProbe.

readinessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5

Pengaturan untuk probe readiness untuk HTTP dan TCP juga sama persis dengan pengaturan untuk probe liveness.

Probe readiness dan liveness dapat digunakan secara bersamaan untuk Container yang sama. Apabila keduanya digunakan sekaligus, lalu lintas jaringan tidak akan sampai ke Container yang belum siap, dan Container akan diulang kembali (restart) saat mengalami kegagalan.

Mengatur Probe

Probe memiliki beberapa field yang dapat digunakan untuk mengendalikan pemeriksaan liveness dan readiness secara presisi.

  • initialDelaySeconds: Durasi dalam detik setelah Container dimulai, sebelum probe liveness atau readiness diinisiasi. Nilai bawaannya adalah 0 detik. Nilai minimalnya adalah 0.
  • periodSeconds: Seberapa sering (dalam detik) probe dijalankan. Nilai bawaannya adalah 10 detik. Nilai minimalnya adalah 0.
  • timeoutSeconds: Durasi dalam detik setelah probe mengalami timeout. Nilai bawaannya adalah 1 detik. Nilai minimalnya adalah 0.
  • successThreshold: Jumlah minimal sukses yang berurutan untuk probe dianggap berhasil setelah mengalami kegagalan. Nilai bawaannya adalah 1. Nilanya harus 1 untuk liveness. Nilai minimalnya adalah 1.
  • failureThreshold: Ketika sebuah Pod dimulai dan probe mengalami kegagalan, Kubernetes akan mencoba beberapa kali sesuai nilai failureThreshold sebelum menyerah. Menyerah dalam kasus probe liveness berarti Container akan diulang kembali. Untuk probe readiness, menyerah akan menandai Pod menjadi "tidak siap" (Unready). Nilai bawaannya adalah 3. Nilai minimalnya adalah 1.

Probe HTTP memiliki field-field tambahan yang bisa diatur melalui httpGet:

  • host: Nama dari host yang akan terhubung, nilai bawaannya adalah IP dari Pod. Kamu mungkin juga ingin mengatur "Host" pada httpHeaders.
  • scheme: Skema yang digunakan untuk terhubung pada host (HTTP atau HTTPS). Nilai bawaannya adalah HTTP.
  • path: Path untuk mengakses server HTTP.
  • httpHeaders: Header khusus yang diatur dalam permintaan HTTP. HTTP memperbolehkan header yang berulang.
  • port: Nama atau angka dari porta untuk mengakses Container. Angkanya harus ada di antara 1 sampai 65535.

Untuk sebuah probe HTTP, kubelet mengirimkan permintaan HTTP untuk path yang ditentukan dan porta untuk mengerjakan pemeriksaan. Probe dikirimkan oleh kubelet untuk alamat IP Pod, kecuali saat alamat digantikan oleh field opsional pada httpGet. Jika field scheme diatur menjadi HTTPS, maka kubelet mengirimkan permintaan HTTPS dan melewati langkah verifikasi sertifikat. Pada skenario kebanyakan, kamu tidak menginginkan field host. Berikut satu skenario yang memerlukan host. Misalkan Container mendengarkan permintaan melalui 127.0.0.1 dan field hostNetwork pada Pod bernilai true. Kemudian host, melalui httpGet, harus diatur menjadi 127.0.0.1. Jika Pod kamu bergantung pada host virtual, dimana untuk kasus-kasus umum, kamu tidak perlu menggunakan host, tetapi perlu mengatur header Host pada httpHeaders.

Untuk probe TCP, kubelet membuat koneksi probe pada Node, tidak pada Pod, yang berarti bahwa kamu tidak menggunakan nama Service di dalam parameter host karena kubelet tidak bisa me-resolve-nya.

Selanjutnya

Kamu juga dapat membaca rujukan API untuk: