1 - Menetapkan Sumber Daya Memori untuk Container dan Pod

Laman ini menunjukkan bagaimana menetapkan permintaan dan batasan memori untuk Container. Container dijamin memiliki memori sebanyak yang diminta, tetapi tidak diperbolehkan untuk menggunakan memori melebihi batas.

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.

Setiap Node pada klaster kamu harus memiliki memori setidaknya 300 MiB.

Beberapa langkah pada laman ini mengharuskan kamu menjalankan Service metrics-server pada klaster kamu. Jika kamu memiliki metrics-server yang sudah berjalan, kamu dapat melewati langkah-langkah berikut ini.

Jika kamu menjalankan Minikube, jalankan perintah berikut untuk mengaktifkan metrics-server:

minikube addons enable metrics-server

Untuk melihat apakah metrics-server sudah berjalan, atau penyedia lain dari API metrik sumber daya (metrics.k8s.io), jalankan perintah berikut ini:

kubectl get apiservices

Jika API metrik sumber daya telah tersedia, keluarannya meliputi seperti acuan pada metrics.k8s.io.

NAME
v1beta1.metrics.k8s.io

Membuat Namespace

Buat Namespace sehingga sumber daya yang kamu buat dalam latihan ini terisolasi dari klaster kamu yang lain.

kubectl create namespace mem-example

Menentukan permintaan memori dan batasan memori

Untuk menentukan permintaan memori untuk Container, sertakan field resources:requests pada manifes sumber daya dari Container. Untuk menentukan batasan memori, sertakan resources:limits.

Dalam latihan ini, kamu akan membuat Pod yang memiliki satu Container. Container memiliki permintaan memori sebesar 100 MiB dan batasan memori sebesar 200 MiB. Berikut berkas konfigurasi untuk Pod:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

Bagian args dalam berkas konfigurasi memberikan argumen untuk Container pada saat dimulai. Argumen"--vm-bytes", "150M" memberi tahu Container agar mencoba mengalokasikan memori sebesar 150 MiB.

Buatlah Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example

Verifikasi apakah Container dalam Pod sudah berjalan:

kubectl get pod memory-demo --namespace=mem-example

Lihat informasi mendetil tentang Pod:

kubectl get pod memory-demo --output=yaml --namespace=mem-example

Keluarannya menunjukkan bahwa satu Container dalam Pod memiliki permintaan memori sebesar 100 MiB dan batasan memori sebesar 200 MiB.

...
resources:
  limits:
    memory: 200Mi
  requests:
    memory: 100Mi
...

Jalankan kubectl top untuk mengambil metrik dari Pod:

kubectl top pod memory-demo --namespace=mem-example

Keluarannya menunjukkan bahwa Pod menggunakan memori sekitar 162.900.000 byte, dimana sekitar 150 MiB. Ini lebih besar dari permintaannya sebesar 100 MiB Pod, tetapi masih di dalam batasan Pod sebesar 200 MiB.

NAME                        CPU(cores)   MEMORY(bytes)
memory-demo                 <something>  162856960

Hapuslah Pod:

kubectl delete pod memory-demo --namespace=mem-example

Melebihi batasan memori dari Container

Container dapat melebihi permintaan memorinya jika Node memiliki memori yang tersedia. Tapi sebuah Container tidak diperbolehkan untuk menggunakan lebih dari batasan memorinya. Jika Container mengalokasikan lebih banyak memori daripada batasannya, Container menjadi kandidat untuk dihentikan. Jika Container terus berlanjut mengkonsumsi memori melebihi batasnya, maka Container akan diakhiri. Jika Container dihentikan dan bisa di mulai ulang, kubelet akan memulai ulang, sama seperti jenis kegagalan runtime yang lainnya.

Dalam latihan ini, kamu membuat Pod yang mencoba mengalokasikan lebih banyak memori dari batasannya. Berikut adalah berkas konfigurasi untuk Pod yang memiliki satu Container dengan berkas permintaan memori sebesar 50 MiB dan batasan memori sebesar 100 MiB:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-2
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-2-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "50Mi"
      limits:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

Dalam bagian args dari berkas konfigurasi, kamu dapat melihat bahwa Container tersebut akan mencoba mengalokasikan memori sebesar 250 MiB, yang jauh di atas batas yaitu 100 MiB.

Buatlah Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example

Lihat informasi mendetail tentang Pod:

kubectl get pod memory-demo-2 --namespace=mem-example

Sampai sini, Container mungkin sedang berjalan atau dimatikan. Ulangi perintah sebelumnya hingga Container dimatikan:

NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          24s

Dapatkan tampilan yang lebih mendetail tentang status Container:

kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example

Keluarannya menunjukkan bahwa Container dimatikan karena kehabisan memori (OOM):

lastState:
   terminated:
     containerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
     exitCode: 137
     finishedAt: 2017-06-20T20:52:19Z
     reason: OOMKilled
     startedAt: null

Container dalam latihan ini dapat dimulai ulang, sehingga kubelet akan memulai ulangnya. Ulangi perintah ini beberapa kali untuk melihat bahwa Container berulang kali dimatikan dan dimulai ulang:

kubectl get pod memory-demo-2 --namespace=mem-example

Keluarannya menunjukkan bahwa Container dimatikan, dimulai ulang, dimatikan lagi, dimulai ulang lagi, dan seterusnya:

kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          37s

kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-2   1/1       Running   2          40s

Lihat informasi mendetail tentang riwayat Pod:

kubectl describe pod memory-demo-2 --namespace=mem-example

Keluarannya menunjukkan bahwa Container dimulai dan gagal berulang kali:

... Normal  Created   Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff   Back-off restarting failed container

Lihat informasi mendetail tentang Node klaster Anda:

kubectl describe nodes

Keluarannya mencakup rekaman Container yang dimatikan karena kondisi kehabisan memori:

Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child

Hapus Pod kamu:

kubectl delete pod memory-demo-2 --namespace=mem-example

Menentukan permintaan memori yang terlalu besar untuk Node kamu

Permintaan dan batasan memori yang dikaitkan dengan Container, berguna untuk berpikir apakah sebuah Pod yang memiliki permintaan dan batasan memori. Permintaan memori untuk Pod tersebut adalah jumlah permintaan memori untuk semua Container dalam Pod. Begitu juga dengan batasan memori untuk Pod adalah jumlah batasan memori dari semua Container di dalam Pod.

Penjadwalan Pod didasarkan pada permintaan. Sebuah Pod dijadwalkan untuk berjalan di sebuah Node hanya jika sebuah Node memiliki cukup memori yang tersedia untuk memenuhi permintaan memori dari Pod tersebut.

Dalam latihan ini, kamu membuat Pod yang memiliki permintaan memori yang sangat besar sehingga melebihi kapasitas dari Node mana pun dalam klaster kamu. Berikut adalah berkas konfigurasi untuk Pod yang memiliki Container dengan permintaan memori 1000 GiB, yang kemungkinan besar melebihi kapasitas dari setiap Node dalam klaster kamu.

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-3
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-3-ctr
    image: polinux/stress
    resources:
      limits:
        memory: "1000Gi"
      requests:
        memory: "1000Gi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

Buatlah Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example

Lihat status Pod:

kubectl get pod memory-demo-3 --namespace=mem-example

Keluarannya menunjukkan bahwa status Pod adalah PENDING. Artinya, Pod tidak dijadwalkan untuk berjalan di Node mana pun, dan Pod akan tetap dalam status PENDING tanpa batas waktu:

kubectl get pod memory-demo-3 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-3   0/1       Pending   0          25s

Lihat informasi mendetail tentang Pod, termasuk event:

kubectl describe pod memory-demo-3 --namespace=mem-example

Keluarannya menunjukkan bahwa Container tidak dapat dijadwalkan karena memori yang tidak cukup pada Node:

Events:
  ...  Reason            Message
       ------            -------
  ...  FailedScheduling  No nodes are available that match all of the following predicates:: Insufficient memory (3).

Satuan Memori

Sumber daya memori diukur dalam satuan byte. Kamu dapat mengekspresikan memori sebagai bilangan bulat biasa atau bilangan bulan fixed-point dengan salah satu akhiran ini: E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki. Contoh berikut ini mewakili nilai yang kira-kira sama:

128974848, 129e6, 129M , 123Mi

Hapuslah Pod kamu:

kubectl delete pod memory-demo-3 --namespace=mem-example

Jika kamu tidak menentukan batasan memori

Jika kamu tidak menentukan batasan memori untuk sebuah Container, salah satu dari situasi berikut ini berlaku:

  • Container tidak memiliki batasan maksimum jumlah memori yang digunakannya. Container dapat menggunakan semua memori yang tersedia dalam Node dimana Container itu berjalan yang pada gilirannya dapat memanggil penyetop OOM (out-of-memory). Lebih lanjut, dalam kasus menghentikan OOM, Container tanpa batas sumber daya akan memiliki peluang lebih besar untuk dihentikan.

  • Container berjalan pada Namespace yang memiliki batasan bawaan memori, dan Container secara otomatis menetapkan batasan bawaan. Administrator klaster dapat menggunakan LimitRange untuk menentukan batasan memori secara bawaan.

Motivasi untuk permintaan dan batasan memori

Dengan mengonfigurasi permintaan dan batasan memori untuk Container yang berjalan pada berkas klaster, kamu dapat menggunakan sumber daya memori yang tersedia pada Node klaster kamu secara efisien. Dengan menjaga permintaan memori pada Pod tetap rendah, kamu memberikan kesempatan yang baik untuk Pod tersebut dijadwalkan. Dengan memiliki batas memori yang lebih besar dari permintaan memori, Anda mencapai dua hal:

  • Pod dapat memiliki aktivitas yang bersifat burst dengan memanfaatkan memori yang kebetulan tersedia.
  • Jumlah memori yang dapat digunakan Pod selama keadaan burst dibatasi pada jumlah yang wajar.

Membersihkan

Hapus Namespace kamu. Ini akan menghapus semua Pod yang kamu buat untuk tugas ini:

kubectl delete namespace mem-example

Selanjutnya

Untuk pengembang aplikasi

Untuk administrator klaster

2 - Konfigurasi Quality of Service untuk Pod

Laman ini menunjukkan bagaimana mengonfigurasi Pod agar ditempatkan pada kelas Quality of Service (QoS) tertentu. Kubernetes menggunakan kelas QoS untuk membuat keputusan tentang penjadwalan dan pengeluaran Pod.

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.

Kelas QoS

Saat membuat Pod, Kubernetes menempatkan salah satu kelas QoS berikut untuknya:

  • Guaranteed
  • Burstable
  • BestEffort

Membuat sebuah Namespace

Buat sebuah Namespace sehingga sumber daya yang kamu buat dalam latihan ini terisolasi dari klaster kamu yang lain.

kubectl create namespace qos-example

Membuat sebuah Pod yang mendapatkan penempatan kelas QoS Guaranteed

Agar sebuah Pod memiliki kelas QoS Guaranteed:

  • Setiap Container, termasuk Container pemulai, di dalam Pod harus memiliki batasan memori dan permintaan memori dengan nilai yang sama.
  • Setiap Container, termasuk Container pemulai, di dalam Pod harus memiliki batasan CPU dan permintaan CPU dengan nilai yang sama.

Berikut adalah berkas konfigurasi untuk sebuah Pod dengan satu Container. Container tersebut memiliki sebuah batasan memori dan sebuah permintaan memori, keduanya sama dengan 200MiB. Container itu juga mempunyai batasan CPU dan permintaan CPU yang sama sebesar 700 milliCPU:

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "700m"
      requests:
        memory: "200Mi"
        cpu: "700m"

Buatlah Pod:

kubectl create -f https://k8s.io/examples/pods/qos/qos-pod.yaml --namespace=qos-example

Tampilkan informasi detail Pod yang telah dibuat:

kubectl get pod qos-demo --namespace=qos-example --output=yaml

Keluaran dari perintah di atas menunjukkan Kubernetes memberikan kelas QoS Guaranteed pada Pod. Keluaran tersebut juga membuktikan bahwa Container pada Pod memiliki permintaan memori yang sesuai dengan batasan memori dan permintaan CPU yang juga sesuai dengan batasan CPU yang dispesifikasikan.

spec:
  containers:
    ...
    resources:
      limits:
        cpu: 700m
        memory: 200Mi
      requests:
        cpu: 700m
        memory: 200Mi
  ...
status:
  qosClass: Guaranteed

Hapuslah Pod:

kubectl delete pod qos-demo --namespace=qos-example

Membuat sebuah Pod yang mendapatkan penempatan kelas Qos Burstable

Sebuah Pod akan mendapatkan kelas QoS Burstable apabila:

  • Pod tidak memenuhi kriteria untuk kelas QoS Guaranteed.
  • Setidaknya ada satu Container di dalam Pod dengan permintaan memori atau CPU.

Berikut adalah berkas konfigurasi untuk Pod dengan satu Container. Container yang dimaksud memiliki batasan memori sebesar 200MiB dan permintaan memori sebesar 100MiB.

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-2
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-2-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

Buatlah Pod:

kubectl create -f https://k8s.io/examples/pods/qos/qos-pod-2.yaml --namespace=qos-example

Tampilkan informasi detail Pod yang telah dibuat:

kubectl get pod qos-demo-2 --namespace=qos-example --output=yaml

Keluaran dari perintah di atas menunjukkan Kubernetes memberikan kelas QoS Burstable pada Pod.

spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: qos-demo-2-ctr
    resources:
      limits:
        memory: 200Mi
      requests:
        memory: 100Mi
  ...
status:
  qosClass: Burstable

Hapuslah Pod:

kubectl delete pod qos-demo-2 --namespace=qos-example

Membuat sebuah Pod yang mendapatkan penempatan kelas QoS BestEffort

Agar Pod mendapatkan kelas QoS BestEffort, Container dalam pod tidak boleh memiliki batasan atau permintaan memori atau CPU.

Berikut adalah berkas konfigurasi untuk Pod dengan satu Container. Container yang dimaksud tidak memiliki batasan atau permintaan memori atau CPU apapun.

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-3
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-3-ctr
    image: nginx

Buatlah Pod:

kubectl create -f https://k8s.io/examples/pods/qos/qos-pod-3.yaml --namespace=qos-example

Tampilkan informasi detail Pod yang telah dibuat:

kubectl get pod qos-demo-3 --namespace=qos-example --output=yaml

Keluaran dari perintah di atas menunjukkan Kubernetes memberikan kelas QoS BestEffort pada Pod.

spec:
  containers:
    ...
    resources: {}
  ...
status:
  qosClass: BestEffort

Hapuslah Pod:

kubectl delete pod qos-demo-3 --namespace=qos-example

Membuat sebuah Pod yang memiliki dua Container

Berikut adalah konfigurasi berkas untuk Pod yang memiliki dua Container. Satu Container menentukan permintaan memori sebesar 200MiB. Container yang lain tidak menentukan permintaan atau batasan apapun.

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-4
  namespace: qos-example
spec:
  containers:

  - name: qos-demo-4-ctr-1
    image: nginx
    resources:
      requests:
        memory: "200Mi"

  - name: qos-demo-4-ctr-2
    image: redis

Perhatikan bahwa Pod ini memenuhi kriteria untuk kelas QoS Burstable. Maksudnya, Container tersebut tidak memenuhi kriteria untuk kelas QoS Guaranteed, dan satu dari Container tersebut memiliki permintaan memori.

Buatlah Pod:

kubectl create -f https://k8s.io/examples/pods/qos/qos-pod-4.yaml --namespace=qos-example

Tampilkan informasi detail Pod yang telah dibuat:

kubectl get pod qos-demo-4 --namespace=qos-example --output=yaml

Keluaran dari perintah di atas menunjukkan Kubernetes memberikan kelas QoS Burstable pada Pod.

spec:
  containers:
    ...
    name: qos-demo-4-ctr-1
    resources:
      requests:
        memory: 200Mi
    ...
    name: qos-demo-4-ctr-2
    resources: {}
    ...
status:
  qosClass: Burstable

Hapuslah Pod:

kubectl delete pod qos-demo-4 --namespace=qos-example

Membersihkan

Hapuslah Namespace:

kubectl delete namespace qos-example

Selanjutnya

Untuk pengembang aplikasi

Untuk administrator klaster

3 - Mengatur Pod untuk Menggunakan Volume sebagai Tempat Penyimpanan

Laman ini menjelaskan bagaimana cara mengatur sebuah Pod untuk menggunakan Volume sebagai tempat penyimpanan.

Filesystem dari sebuah Container hanya hidup selama Container itu juga hidup. Saat Container berakhir dan dimulai ulang, perubahan pada filesystem akan hilang. Untuk penyimpanan konsisten yang independen dari Container, kamu dapat menggunakan Volume. Hal ini penting terutama untuk aplikasi stateful, seperti key-value stores (contohnya Redis) dan database.

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.

Mengatur volume untuk Pod

Pada latihan ini, kamu membuat sebuah Pod yang menjalankan sebuah Container. Pod ini memiliki sebuah Volume dengan tipe emptyDir yang tetap bertahan, meski Container berakhir dan dimulai ulang. Berikut berkas konfigurasi untuk Pod:

apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: redis
    volumeMounts:
    - name: redis-storage
      mountPath: /data/redis
  volumes:
  - name: redis-storage
    emptyDir: {}
  1. Membuat Pod:

    kubectl apply -f https://k8s.io/examples/pods/storage/redis.yaml
    
  2. Verifikasi apakah Container dari Pod berjalan sukses, lalu mengamati perubahan terhadap Pod:

    kubectl get pod redis --watch
    

    Hasil keluaran seperti ini:

    NAME      READY     STATUS    RESTARTS   AGE
    redis     1/1       Running   0          13s
    
  3. Pada terminal lain, buka shell untuk masuk ke Container yang sedang berjalan:

    kubectl exec -it redis -- /bin/bash
    
  4. Di dalam shell, pergi ke /data/redis, kemudian buat sebuah berkas:

    root@redis:/data# cd /data/redis/
    root@redis:/data/redis# echo Hello > test-file
    
  5. Di dalam shell, munculkan daftar proses-proses yang sedang berjalan:

    root@redis:/data/redis# apt-get update
    root@redis:/data/redis# apt-get install procps
    root@redis:/data/redis# ps aux
    

    Keluarannya mirip seperti ini:

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    redis        1  0.1  0.1  33308  3828 ?        Ssl  00:46   0:00 redis-server *:6379
    root        12  0.0  0.0  20228  3020 ?        Ss   00:47   0:00 /bin/bash
    root        15  0.0  0.0  17500  2072 ?        R+   00:48   0:00 ps aux
    
  6. Di dalam shell, matikan proses Redis:

    root@redis:/data/redis# kill <pid>
    

    dengan <pid> adalah ID proses Redis (PID).

  7. Di dalam terminal awal, amati perubahan terhadap Pod Redis. Sampai akhirnya kamu akan melihat hal seperti ini:

    NAME      READY     STATUS     RESTARTS   AGE
    redis     1/1       Running    0          13s
    redis     0/1       Completed  0         6m
    redis     1/1       Running    1         6m
    

Sampai di sini, Container telah berakhir dan dimuat ulang. Hal ini karena Pod Redis memiliki restartPolicy dengan nilai Always.

  1. Gunakan shell untuk masuk ke dalam Container yang telah dimuat ulang:

    kubectl exec -it redis -- /bin/bash
    
  2. Di dalam shell, pergi ke /data/redis, dan verifikasi apakah test-file masih ada.

    root@redis:/data/redis# cd /data/redis/
    root@redis:/data/redis# ls
    test-file
    
  3. Hapus Pod yang kamu buat untuk latihan ini:

    kubectl delete pod redis
    

Selanjutnya

  • Lihat Volume.

  • Lihat Pod.

  • Selain penyimpanan pada disk lokal yang di sediakan oleh emptyDir, Kubernetes juga mendukung solusi penyimpanan network-attached, termasuk PD pada GCE dan EBS dari EC2, yang cenderung lebih disukai untuk data sangat penting dan akan menangani urusan detil seperti mounting dan unmounting perangkat pada Node. Lihat Volume untuk informasi detil.

4 - Mengatur Pod untuk Penyimpanan dengan PersistentVolume

Laman ini akan menjelaskan bagaimana kamu dapat mengatur sebuah Pod dengan menggunakan PersistentVolumeClaim untuk penyimpanan. Berikut ringkasan prosesnya:

  1. Kamu, sebagai seorang administrator klaster, membuat sebuah PersistentVolume yang didukung oleh penyimpanan fisik. Kamu tidak mengaitkan volume dengan Pod apapun.

  2. Kamu, sekarang mengambil peran sebagai seorang developer / pengguna klaster, membuat sebuah PersistentVolumeClaim yang secara otomatis terikat dengan PersistentVolume yang sesuai.

  3. Kamu membuat sebuah Pod yang menggunakan PersistentVolumeClaim di atas untuk penyimpanan.

Sebelum kamu memulai

  • Kamu membutuhkan sebuah klaster Kubernetes yang hanya memiliki satu Node, dan kubectl alat baris perintah yang sudah diatur untuk berkomunikasi dengan klaster kamu. Jika kamu tidak memiliki sebuah klaster dengan Node tunggal, kamu dapat membuatnya dengan Minikube.

  • Familiar dengan materi di Persistent Volumes.

Membuat sebuah berkas index.html di dalam Node kamu

Buka sebuah shell ke Node tunggal di klaster kamu. Bagaimana kamu membuka sebuah shell tergantung dengan bagaimana kamu mengatur klaster kamu. Contoh, jika kamu menggunakan Minikube, kamu dapat membuka sebuah shell ke Node kamu dengan memasukkan minikube ssh.

Di dalam shell kamu pada Node itu, buat sebuah direktori dengan nama /mnt/data:

# Asumsikan Node kamu menggunakan "sudo" untuk menjalankan perintah
# sebagai superuser
sudo mkdir /mnt/data

Di dalam direktori /mnt/data, buat sebuah berkas dengan nama index.html:

# Disini kembali asumsikan bahwa Node kamu menggunakan "sudo" untuk menjalankan perintah
# sebagai superuser
sudo sh -c "echo 'Hello from Kubernetes storage' > /mnt/data/index.html"

Menguji bahwa berkas index.html ada:

cat /mnt/data/index.html

Keluaran akan seperti ini:

Hello from Kubernetes storage

Sekarang kamu dapat menutup shell di Node kamu.

Membuat sebuah PersistentVolume

Pada latihan ini, kamu akan membuat sebuah hostPath PersistentVolume. Kubernetes mendukung hostPath untuk pengembangan dan pengujian di dalam klaster Node tunggal. Sebuah hostPath PersistentVolume menggunakan berkas atau direktori di dalam Node untuk meniru penyimpanan terhubung jaringan (NAS, network-attached storage).

Di dalam klaster production, kamu tidak dapat menggunakan hostPath. Sebagai gantinya sebuah administrator klaster akan menyediakan sumberdaya jaringan seperti Google Compute Engine persistent disk, NFS share, atau sebuah Amazon Elastic Block Store volume. Administrator klaster juga dapat menggunakan StorageClass untuk mengatur provisioning secara dinamis.

Berikut berkas konfigurasi untuk hostPath PersistentVolume:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: task-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

Berkas konfigurasi tersebut menentukan bahwa volume berada di /mnt/data pada klaster Node. Konfigurasi tersebut juga menentukan ukuran dari 10 gibibytes dan mode akses ReadWriteOnce, yang berarti volume dapat di pasang sebagai read-write oleh Node tunggal. Konfigurasi ini menggunakan nama dari StorageClass manual untuk PersistentVolume, yang akan digunakan untuk mengikat permintaan PeristentVolumeClaim ke PersistentVolume ini.

Membuat sebuah PersistentVolume:

kubectl apply -f https://k8s.io/examples/pods/storage/pv-volume.yaml

Melihat informasi tentang PersistentVolume:

kubectl get pv task-pv-volume

Keluaran menunjuk PersistentVolume memliki sebuah STATUS dari Available. Ini berarti PersistentVolume belum terikat ke PersistentVolumeClaim.

NAME             CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
task-pv-volume   10Gi       RWO           Retain          Available             manual                   4s

Membuat sebuah PersistentVolumeClaim

Langkah selanjutnya adalah membuat sebuah PersistentVolumeClaim. Pod menggunakan PersistentVolumeClaim untuk meminta penyimpanan fisik. Pada latihan ini, kamu akan membuat sebuah PersistentVolumeClaim yang meminta sebuah volume minimal tiga gibibytes dengan mode akses read-write setidaknya untuk satu Node.

Berikut berkas konfigurasi untuk PersistentVolumeClaim:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

Membuat sebuah PersistentVolumeClaim:

kubectl apply -f https://k8s.io/examples/pods/storage/pv-claim.yaml

Setelah membuat sebuah PersistentVolumeClaim, Kubernetes control plane terlihat untuk sebuah PersistentVolumeClaim yang memenuhi persyaratan claim's. Jika control plane menemukan PersistentVolume yang cocok dengan StorageClass, maka akan mengikat claim ke dalam volume tersebut.

Lihat kembali PersistentVolume:

kubectl get pv task-pv-volume

Sekarang keluaran menunjukan sebuah STATUS dari Bound.

NAME             CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS    CLAIM                   STORAGECLASS   REASON    AGE
task-pv-volume   10Gi       RWO           Retain          Bound     default/task-pv-claim   manual                   2m

Lihat PersistentVolumeClaim:

kubectl get pvc task-pv-claim

Keluaran menunjukan PersistentVolumeClaim terlah terikat dengan PersistentVolume, task-pv-volume.

NAME            STATUS    VOLUME           CAPACITY   ACCESSMODES   STORAGECLASS   AGE
task-pv-claim   Bound     task-pv-volume   10Gi       RWO           manual         30s

Membuat sebuah Pod

Langkah selanjutnya adalah membuat sebuah Pod yang akan menggunakan PersistentVolumeClaim sebagai volume.

Berikut berkas konfigurasi untuk Pod:

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage

Perhatikan bahwa berkas konfigurasi Pod menentukan sebuah PersistentVolumeClaim, tetapi tidak menentukan PeristentVolume. Dari sudut pandang Pod, claim adalah volume.

Membuat Pod:

kubectl apply -f https://k8s.io/examples/pods/storage/pv-pod.yaml

Pastikan bahwa Container di dalam Pod berjalan:

kubectl get pod task-pv-pod

Mendapatkan sebuah shell ke Container yang sedang berjalan di Pod kamu:

kubectl exec -it task-pv-pod -- /bin/bash

Di dalam shell, pastikan bahwa nginx menyajikan berkas index.html dari dalam hostPath volume:

# Pastikan kamu menjalankan 3 perintah ini di dalam shell root yang berasal dari
# "kubectl exec" dari langkah sebelumnya
apt update
apt install curl
curl http://localhost/

Keluaran akan menunjukan sebuah teks yang telah kamu tulis di berkas index.html di dalam hostPath volume:

Hello from Kubernetes storage

Jika kamu melihat pesan tersebut, kamu telah berhasil mengatur sebuah Pod untuk menggunakan penyimpanan dari PersistentVolumeClaim.

Membersihkan

Hapus Pod, PersistentVolumeClaim dan PersistentVolume:

kubectl delete pod task-pv-pod
kubectl delete pvc task-pv-claim
kubectl delete pv task-pv-volume

Jika kamu belum memiliki shell yang telah dibuka ke Node di klaster kamu, buka shell baru dengan cara yang sama yang telah kamu lakukan sebelumnya.

Di dalam shell Node kamu, hapus berkas dan direktori yang telah kamu buat:

# Asumsikan Node kamu menggunakan "sudo" untuk menjalankan perintah
# sebagai superuser
sudo rm /mnt/data/index.html
sudo rmdir /mnt/data

Sekarang kamu dapat menutup shell Node kamu.

Kontrol akses

Penyimpanan yang telah terkonfigurasi dengan group ID (GID) memungkinkan akses menulis hanya dari Pod yang menggunakan GID yang sama. GID yang tidak cocok atau hilang akan menyebabkan kesalahan izin ditolak. Untuk mengurangi kebutuhan koordinasi dengan pengguna, administrator dapat membuat anotasi sebuah PersistentVolume dengan GID. Kemudian GID akan otomatis ditambahkan ke Pod yang menggunakan PersistentVolume.

Gunakan anotasi pv.beta.kubernetes.io/gid sebagai berikut:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
  annotations:
    pv.beta.kubernetes.io/gid: "1234"

Ketika sebuah Pod mengkonsumsi PersistentVolume yang memiliki anotasi GID, anotasi GID tersebut akan diterapkan ke semua container di dalam Pod dengan cara yang sama yang ditentukan di dalam GID Pod security context. Settiap GID, baik berasal dari anotasi PersistentVolume atau Pod, diterapkan pada proses pertama yang dijalankan di setiap container.

Selanjutnya

Referensi

5 - Mengonfigurasi Konteks Keamanan untuk Pod atau Container

Konteks keamanan (security context) menentukan wewenang (privilege) dan aturan kontrol akses untuk sebuah Pod atau Container. Aturan konteks keamanan meliputi hal-hal berikut ini namun tidak terbatas pada hal-hal tersebut:

  • Kontrol akses bersifat diskresi: Izin untuk mengakses objek, seperti sebuah berkas, yang didasarkan pada ID pengguna atau user ID (UID) dan ID grup atau group ID (GID).

  • Security Enhanced Linux (SELinux): Di mana objek diberi label keamanan.

  • Menjalankan dengan wewenang (privileged) atau tanpa wewenang (unprivileged).

  • Kapabilitas Linux (Linux Capabilities): Memberi sebuah proses beberapa wewenang, namun tidak semua wewenang dari pengguna root.

  • AppArmor: Menggunakan profil program untuk membatasi kemampuan dari masing-masing program.

  • Seccomp: Menyaring panggilan sistem (system calls) dari suatu proses.

  • AllowPrivilegeEscalation: Mengontrol apakah suatu proses dapat memperoleh lebih banyak wewenang daripada proses induknya. Pilihan ini mengontrol secara langsung apakah opsi no_new_privs diaktifkan pada proses dalam Container. AllowPrivilegeEscalation selalu aktif (true) ketika Container: 1) berjalan dengan wewenang ATAU 2) memiliki CAP_SYS_ADMIN.

  • readOnlyRootFilesystem: Menambatkan (mount) sistem berkas (file system) root dari sebuah Container hanya sebatas untuk dibaca saja (read-only).

Poin-poin di atas bukanlah sekumpulan lengkap dari aturan konteks keamanan - silakan lihat SecurityContext untuk daftar lengkapnya.

Untuk informasi lebih lanjut tentang mekanisme keamanan pada Linux, silahkan lihat ikhtisar fitur keamanan pada Kernel Linux

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.

Mengatur konteks keamanan untuk Pod

Untuk menentukan aturan keamanan pada Pod, masukkan bagian securityContext dalam spesifikasi Pod. Bagian securityContext adalah sebuah objek PodSecurityContext. Aturan keamanan yang kamu tetapkan untuk Pod akan berlaku untuk semua Container dalam Pod tersebut. Berikut sebuah berkas konfigurasi untuk Pod yang memiliki volume securityContext dan emptyDir:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false

Dalam berkas konfigurasi ini, bagian runAsUser menentukan bahwa dalam setiap Container pada Pod, semua proses dijalankan oleh ID pengguna 1000. Bagian runAsGroup menentukan grup utama dengan ID 3000 untuk semua proses dalam setiap Container pada Pod. Jika bagian ini diabaikan, maka ID grup utama dari Container akan berubah menjadi root(0). Berkas apa pun yang dibuat juga akan dimiliki oleh pengguna dengan ID 1000 dan grup dengan ID 3000 ketika runAsGroup ditentukan. Karena fsGroup ditentukan, semua proses milik Container juga merupakan bagian dari grup tambahan dengan ID 2000. Pemilik volume /data/demo dan berkas apa pun yang dibuat dalam volume tersebut adalah grup dengan ID 2000.

Buatlah Pod tersebut:

kubectl apply -f https://k8s.io/examples/pods/security/security-context.yaml

Periksa apakah Container dari Pod sedang berjalan:

kubectl get pod security-context-demo

Masuk ke shell dari Container yang sedang berjalan tersebut:

kubectl exec -it security-context-demo -- sh

Pada shell kamu, lihat daftar proses yang berjalan:

ps

Keluarannya menunjukkan bahwa proses dijalankan oleh pengguna dengan ID 1000, yang merupakan nilai dari bagian runAsUser:

PID   USER     TIME  COMMAND
    1 1000      0:00 sleep 1h
    6 1000      0:00 sh
...

Pada shell kamu, pindah ke direktori /data, dan lihat isinya:

cd /data
ls -l

Keluarannya menunjukkan bahwa direktori /data/demo memiliki grup dengan ID 2000, yang merupakan nilai dari bagian fsGroup.

drwxrwsrwx 2 root 2000 4096 Jun  6 20:08 demo

Pada shell kamu, pindah ke direktori /data/demo, dan buatlah sebuah berkas didalamnya:

cd demo
echo hello > testfile

Lihatlah daftar berkas dalam direktori /data/demo:

ls -l

Keluarannya menunjukkan bahwa testfile memiliki grup dengan ID 2000, dimana merupakan nilai dari bagian fsGroup.

-rw-r--r-- 1 1000 2000 6 Jun  6 20:08 testfile

Jalankan perintah berikut ini:

$ id
uid=1000 gid=3000 groups=2000

Kamu akan melihat bahwa nilai gid adalah 3000, sama dengan bagian runAsGroup. Jika runAsGroup diabaikan maka nilai gid akan tetap bernilai 0(root) dan proses akan dapat berinteraksi dengan berkas-berkas yang dimiliki oleh grup root(0) dan yang memiliki izin grup untuk grup root(0).

Keluarlah dari shell kamu:

exit

Melakukan konfigurasi izin volume dan kebijakan perubahan kepemilikan untuk Pod

FEATURE STATE: Kubernetes v1.18 [alpha]

Secara bawaan, Kubernetes mengubah kepemilikan dan izin secara rekursif untuk konten masing-masing volume untuk mencocokkan fsGroup yang ditentukan dalam securityContext dari Pod pada saat volume itu ditambatkan (mounted). Untuk volume yang besar, memeriksa dan mengubah kepemilikan dan izin dapat memerlukan waktu yang sangat lama, sehingga memperlambat proses menjalankan Pod. Kamu dapat menggunakan bagian fsGroupChangePolicy dalam sebuah securityContext untuk mengontrol cara Kubernetes memeriksa dan mengelola kepemilikan dan izin untuk sebuah volume.

fsGroupChangePolicy - fsGroupChangePolicy mendefinisikan perilaku untuk mengubah kepemilikan dan izin volume sebelum diekspos di dalam sebuah Pod. Bagian ini hanya berlaku untuk tipe volume yang mendukung fsGroup untuk mengontrol kepemilikan dan izin. Bagian ini memiliki dua nilai yang dapat dimasukkan:

  • OnRootMismatch: Hanya mengubah izin dan kepemilikan jika izin dan kepemilikan dari direktori root tidak sesuai dengan izin volume yang diharapkan. Hal ini dapat membantu mempersingkat waktu yang diperlukan untuk mengubah kepemilikan dan izin sebuah volume.
  • Always: Selalu mengubah izin dan kepemilikan volume ketika volume sudah ditambatkan.

Sebagai contoh:

securityContext:
  runAsUser: 1000
  runAsGroup: 3000
  fsGroup: 2000
  fsGroupChangePolicy: "OnRootMismatch"

Ini adalah fitur alpha. Untuk menggunakannya, silahkan aktifkan gerbang fitur ConfigurableFSGroupPolicy untuk kube-api-server, kube-controller-manager, dan kubelet.

Mengatur konteks keamanan untuk Container

Untuk menentukan aturan keamanan untuk suatu Container, sertakan bagian securityContext dalam manifes Container. Bagian securityContext adalah sebuah objek SecurityContext. Aturan keamanan yang kamu tentukan untuk Container hanya berlaku untuk Container secara individu, dan aturan tersebut menimpa aturan yang dibuat pada tingkat Pod apabila ada aturan yang tumpang tindih. Aturan pada Container mempengaruhi volume pada Pod.

Berikut berkas konfigurasi untuk Pod yang hanya memiliki satu Container. Keduanya, baik Pod dan Container memiliki bagian securityContext sebagai berikut:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-2
spec:
  securityContext:
    runAsUser: 1000
  containers:
  - name: sec-ctx-demo-2
    image: gcr.io/google-samples/node-hello:1.0
    securityContext:
      runAsUser: 2000
      allowPrivilegeEscalation: false

Buatlah Pod tersebut:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-2.yaml

Periksa jika Container dalam Pod sedang berjalan:

kubectl get pod security-context-demo-2

Masuk ke dalam shell Container yang sedang berjalan tersebut:

kubectl exec -it security-context-demo-2 -- sh

Pada shell kamu, lihat daftar proses yang sedang berjalan:

ps aux

Keluarannya menunjukkan bahwa proses dijalankan oleh user dengan ID 2000, yang merupakan nilai dari runAsUser seperti yang telah ditentukan untuk Container tersebut. Nilai tersebut menimpa nilai ID 1000 yang ditentukan untuk Pod-nya.

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
2000         1  0.0  0.0   4336   764 ?        Ss   20:36   0:00 /bin/sh -c node server.js
2000         8  0.1  0.5 772124 22604 ?        Sl   20:36   0:00 node server.js
...

Keluar dari shell anda:

exit

Mengatur Kapabilitas untuk Container

Dengan menggunakan Kapabilitas Linux (Linux Capabilities), kamu dapat memberikan wewenang tertentu kepada suatu proses tanpa memberikan semua wewenang dari pengguna root. Untuk menambah atau menghapus Kapabilitas Linux pada suatu Container, masukkan bagian capabilities pada securityContext di manifes Container-nya.

Pertama-tama, mari melihat apa yang terjadi ketika kamu tidak menyertakan bagian capabilities. Berikut ini adalah berkas konfigurasi yang tidak menambah atau mengurangi kemampuan apa pun dari Container:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-3
spec:
  containers:
  - name: sec-ctx-3
    image: gcr.io/google-samples/node-hello:1.0

Buatlah Pod tersebut:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-3.yaml

Periksa apakah Container dari Pod tersebut sedang berjalan:

kubectl get pod security-context-demo-3

Masuk ke dalam shell dari Container yang berjalan:

kubectl exec -it security-context-demo-3 -- sh

Dalam shell tersebut, lihatlah daftar proses yang berjalan:

ps aux

Keluarannya menunjukkan ID dari proses atau process IDs (PIDs) untuk Container tersebut:

USER  PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
root    1  0.0  0.0   4336   796 ?     Ss   18:17   0:00 /bin/sh -c node server.js
root    5  0.1  0.5 772124 22700 ?     Sl   18:17   0:00 node server.js

Dalam shell kamu, lihat status dari proses dengan ID 1:

cd /proc/1
cat status

Keluarannya menunjukkan bitmap dari kapabilitas untuk proses tersebut:

...
CapPrm:	00000000a80425fb
CapEff:	00000000a80425fb
...

Buatlah catatan untuk bitmap dari kapabilitas tersebut, dan keluarlah dari shell kamu:

exit

Berikutnya, jalankan Container yang sama seperti dengan Container sebelumnya, namun Container ini memiliki kapabilitas tambahan yang sudah ditentukan.

Berikut ini adalah berkas konfigurasi untuk Pod yang hanya menjalankan satu Container. Konfigurasi ini menambahkan kapabilitas CAP_NET_ADMIN dan CAP_SYS_TIME:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-4
spec:
  containers:
  - name: sec-ctx-4
    image: gcr.io/google-samples/node-hello:1.0
    securityContext:
      capabilities:
        add: ["NET_ADMIN", "SYS_TIME"]

Buatlah Pod tersebut:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-4.yaml

Masuk ke dalam shell dari Container yang berjalan:

kubectl exec -it security-context-demo-4 -- sh

Di dalam shell kamu, lihatlah kapabilitas dari proses dengan ID 1:

cd /proc/1
cat status

Keluarannya menunjukkan bitmap kapabilitas untuk proses tersebut:

...
CapPrm:	00000000aa0435fb
CapEff:	00000000aa0435fb
...

Bandingkan kemampuan dari kedua Containers tersebut:

00000000a80425fb
00000000aa0435fb

Dalam bitmap kapabilitas pada Container pertama, bit-12 dan ke-25 tidak diatur. Sedangkan dalam Container kedua, bit ke-12 dan ke-25 diatur. Bit ke-12 adalah kapabilitas CAP_NET_ADMIN, dan bit-25 adalah kapabilitas CAP_SYS_TIME. Lihatlah capability.h untuk nilai dari konstanta kapabilitas-kapabilitas yang lainnya.

Memberikan label SELinux pada sebuah Container

Untuk memberikan label SELinux pada sebuah Container, masukkan bagian seLinuxOptions pada bagian securityContext dari manifes Pod atau Container kamu. Bagian seLinuxOptions adalah sebuah objek SELinuxOptions. Berikut ini adalah contoh yang menerapkan sebuah level dari SELinux:

...
securityContext:
  seLinuxOptions:
    level: "s0:c123,c456"

Diskusi

Konteks keamanan untuk sebuah Pod berlaku juga untuk Container yang berada dalam Pod tersebut dan juga untuk volume dari Pod tersebut jika ada. Terkhusus untuk fsGroup dan seLinuxOptions akan diterapkan pada volume seperti berikut:

  • fsGroup: Volume yang mendukung manajemen kepemilikan (ownership) akan dimodifikasi agar dapat dimiliki dan ditulis oleh ID group (GID) yang disebutkan dalam fsGroup. Lihatlah Dokumen Desain untuk Manajemen Kepemilikan untuk lebih lanjut.

  • seLinuxOptions: Volume yang mendukung pelabelan SELinux akan dilabel ulang agar dapat diakses oleh label yang ditentukan pada seLinuxOptions. Biasanya kamu hanya perlu mengatur bagian level. Dimana ini akan menetapkan label Keamanan multi-kategori (Multi-Category Security) (MCS) yang diberikan kepada semua Container dalam Pod serta Volume yang ada didalamnya.

Bersih-bersih (Clean Up)

Hapus Pod-Pod tersebut:

kubectl delete pod security-context-demo
kubectl delete pod security-context-demo-2
kubectl delete pod security-context-demo-3
kubectl delete pod security-context-demo-4

Selanjutnya

6 - Mengatur ServiceAccount untuk Pod

ServiceAccount menyediakan identitas untuk proses yang sedang berjalan dalam sebuah Pod.

Ketika kamu mengakses klaster (contohnya menggunakan kubectl), kamu terautentikasi oleh apiserver sebagai sebuah akun pengguna (untuk sekarang umumnya sebagai admin, kecuali jika administrator klustermu telah melakukan pengubahan). Berbagai proses yang ada di dalam kontainer dalam Pod juga dapat mengontak apiserver. Ketika itu terjadi, mereka akan diautentikasi sebagai sebuah ServiceAccount (contohnya sebagai default).

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.

Menggunakan Default ServiceAccount untuk Mengakses API server.

Ketika kamu membuat sebuah Pod, jika kamu tidak menentukan sebuah ServiceAccount, maka ia akan otomatis ditetapkan sebagai ServiceAccountdefault di Namespace yang sama. Jika kamu mendapatkan json atau yaml mentah untuk sebuah Pod yang telah kamu buat (contohnya menggunakan kubectl get pods/<podname> -o yaml), kamu akan melihat field spec.serviceAccountName yang telah secara otomatis ditentukan.

Kamu dapat mengakses API dari dalam Pod menggunakan kredensial ServiceAccount yang ditambahkan secara otomatis seperti yang dijelaskan dalam Mengakses Klaster. Hak akses API dari ServiceAccount menyesuaikan dengan kebijakan dan plugin otorisasi yang sedang digunakan.

Di versi 1.6+, kamu dapat tidak memilih automounting kredensial API dari sebuah ServiceAccount dengan mengatur automountServiceAccountToken: false pada ServiceAccount:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
automountServiceAccountToken: false
...

Di versi 1.6+, kamu juga dapat tidak memilih automounting kredensial API dari suatu Pod tertentu:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  serviceAccountName: build-robot
  automountServiceAccountToken: false
  ...

Pengaturan dari spesifikasi Pod didahulukan dibanding ServiceAccount jika keduanya menentukan nilai dari automountServiceAccountToken.

Menggunakan Beberapa ServiceAccount.

Setiap Namespace memiliki sumber daya ServiceAccount standar default. Kamu dapat melihatnya dan sumber daya serviceAccount lainnya di Namespace tersebut dengan perintah:

kubectl get serviceaccounts

Keluarannya akan serupa dengan:

NAME      SECRETS    AGE
default   1          1d

Kamu dapat membuat objek ServiceAccount tambahan seperti ini:

kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
EOF

Nama dari objek ServiceAccount haruslah sebuah nama subdomain DNS yang valid.

Jika kamu mendapatkan objek ServiceAccount secara komplit, seperti ini:

kubectl get serviceaccounts/build-robot -o yaml

Keluarannya akan serupa dengan:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2015-06-16T00:12:59Z
  name: build-robot
  namespace: default
  resourceVersion: "272500"
  uid: 721ab723-13bc-11e5-aec2-42010af0021e
secrets:
- name: build-robot-token-bvbk5

maka kamu dapat melihat bahwa token telah dibuat secara otomatis dan dirujuk oleh ServiceAccount.

Kamu dapat menggunakan plugin otorisasi untuk mengatur hak akses dari ServiceAccount.

Untuk menggunakan ServiceAccount selain nilai standar, atur field spec.serviceAccountName dari Pod menjadi nama dari ServiceAccount yang hendak kamu gunakan.

Service account harus ada ketika Pod dibuat, jika tidak maka akan ditolak.

Kamu tidak dapat memperbarui ServiceAccount dari Pod yang telah dibuat.

Kamu dapat menghapus ServiceAccount dari contoh seperti ini:

kubectl delete serviceaccount/build-robot

Membuat token API ServiceAccount secara manual.

Asumsikan kita memiliki ServiceAccount dengan nama "build-robot" seperti yang disebukan di atas, dan kita membuat Secret secara manual.

kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: build-robot-secret
  annotations:
    kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
EOF

Sekarang kamu dapat mengonfirmasi bahwa Secret yang baru saja dibuat diisi dengan token API dari ServiceAccount "build-robot".

Setiap token dari ServiceAccount yang tidak ada akan dihapus oleh token controller.

kubectl describe secrets/build-robot-secret

Keluarannya akan serupa dengan:

Name:           build-robot-secret
Namespace:      default
Labels:         <none>
Annotations:    kubernetes.io/service-account.name: build-robot
                kubernetes.io/service-account.uid: da68f9c6-9d26-11e7-b84e-002dc52800da

Type:   kubernetes.io/service-account-token

Data
====
ca.crt:         1338 bytes
namespace:      7 bytes
token:          ...

Menambahkan ImagePullSecret ke ServiceAccount.

Membuat imagePullSecret

  • Membuat sebuah imagePullSecret, seperti yang dijelaskan pada Menentukan ImagePullSecret pada Pod.

    kubectl create secret docker-registry myregistrykey --docker-server=<registry name> \
            --docker-username=DUMMY_USERNAME --docker-password=DUMMY_DOCKER_PASSWORD \
            --docker-email=DUMMY_DOCKER_EMAIL
    
  • Memastikan bahwa Secret telah terbuat.

    kubectl get secrets myregistrykey
    

    Keluarannya akan serupa dengan:

    NAME             TYPE                              DATA    AGE
    myregistrykey    kubernetes.io/.dockerconfigjson   1       1d
    

Menambahkan imagePullSecret ke ServiceAccount

Selanjutnya, modifikasi ServiceAccount standar dari Namespace untuk menggunakan Secret ini sebagai imagePullSecret.

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'

Sebagai gantinya kamu dapat menggunakan kubectl edit, atau melakukan pengubahan secara manual manifes YAML seperti di bawah ini:

kubectl get serviceaccounts default -o yaml > ./sa.yaml

Keluaran dari berkas sa.yaml akan serupa dengan:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2015-08-07T22:02:39Z
  name: default
  namespace: default
  resourceVersion: "243024"
  uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets:
- name: default-token-uudge

Menggunakan editor pilihanmu (misalnya vi), buka berkas sa.yaml, hapus baris dengan key resourceVersion, tambahkan baris dengan imagePullSecrets: dan simpan.

Keluaran dari berkas sa.yaml akan serupa dengan:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2015-08-07T22:02:39Z
  name: default
  namespace: default
  uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets:
- name: default-token-uudge
imagePullSecrets:
- name: myregistrykey

Terakhir ganti serviceaccount dengan berkas sa.yaml yang telah diperbarui.

kubectl replace serviceaccount default -f ./sa.yaml

Memverifikasi imagePullSecrets sudah ditambahkan ke spesifikasi Pod

Ketika Pod baru dibuat dalam Namespace yang sedang aktif dan menggunakan ServiceAccount, Pod baru akan memiliki field spec.imagePullSecrets yang ditentukan secara otomatis:

kubectl run nginx --image=<registry name>/nginx --restart=Never
kubectl get pod nginx -o=jsonpath='{.spec.imagePullSecrets[0].name}{"\n"}'

Keluarannya adalah:

myregistrykey

ServiceAccountTokenVolumeProjection

FEATURE STATE: Kubernetes v1.12 [beta]

Kubelet juga dapat memproyeksikan token ServiceAccount ke Pod. Kamu dapat menentukan properti yang diinginkan dari token seperti target pengguna dan durasi validitas. Properti tersebut tidak dapat diubah pada token ServiceAccount standar. Token ServiceAccount juga akan menjadi tidak valid terhadap API ketika Pod atau ServiceAccount dihapus.

Perilaku ini diatur pada PodSpec menggunakan tipe ProjectedVolume yaitu ServiceAccountToken. Untuk memungkinkan Pod dengan token dengan pengguna bertipe "vault" dan durasi validitas selama dua jam, kamu harus mengubah bagian ini pada PodSpec:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /var/run/secrets/tokens
      name: vault-token
  serviceAccountName: build-robot
  volumes:
  - name: vault-token
    projected:
      sources:
      - serviceAccountToken:
          path: vault-token
          expirationSeconds: 7200
          audience: vault

Buat Pod:

kubectl create -f https://k8s.io/examples/pods/pod-projected-svc-token.yaml

Token yang mewakili Pod akan diminta dan disimpan kubelet, lalu kubelet akan membuat token yang dapat diakses oleh Pod pada file path yang ditentukan, dan melakukan refresh token ketika telah mendekati waktu berakhir. Token akan diganti oleh kubelet jika token telah melewati 80% dari total TTL, atau jika token telah melebihi waktu 24 jam.

Aplikasi bertanggung jawab untuk memuat ulang token ketika terjadi penggantian. Pemuatan ulang teratur (misalnya sekali setiap 5 menit) cukup untuk mencakup kebanyakan kasus.

ServiceAccountIssuerDiscovery

FEATURE STATE: Kubernetes v1.18 [alpha]

Fitur ServiceAccountIssuerDiscovery diaktifkan dengan mengaktifkan gerbang fitur ServiceAccountIssuerDiscovery dan mengaktifkan fitur Service Account Token Volume Projection seperti yang telah dijelaskan di atas.

Fitur Service Account Issuer Discovery memungkinkan federasi dari berbagai token ServiceAccount Kubernetes yang dibuat oleh sebuah klaster (penyedia identitas) dan sistem eksternal.

Ketika diaktifkan, server API Kubernetes menyediakan dokumen OpenID Provider Configuration pada /.well-known/openid-configuration dan JSON Web Key Set (JWKS) terkait pada /openid/v1/jwks. OpenID Provider Configuration terkadang disebut juga dengan sebutan discovery document.

Ketika diaktifkan, klaster juga dikonfigurasi dengan RBAC ClusterRole standar yaitu system:service-account-issuer-discovery. Role binding tidak disediakan secara default. Administrator dimungkinkan untuk, sebagai contoh, menentukan apakah peran akan disematkan ke system:authenticated atau system:unauthenticated tergantung terhadap kebutuhan keamanan dan sistem eksternal yang direncakanan untuk diintegrasikan.

Respons JWKS memuat kunci publik yang dapat digunakan oleh sistem eksternal untuk melakukan validasi token ServiceAccount Kubernetes. Awalnya sistem eksternal akan mengkueri OpenID Provider Configuration, dan selanjutnya dapat menggunakan field jwks_uri pada respons kueri untuk mendapatkan JWKS.

Pada banyak kasus, server API Kubernetes tidak tersedia di internet publik, namun endpoint publik yang menyediakan respons hasil cache dari server API dapat dibuat menjadi tersedia oleh pengguna atau penyedia servis. Pada kasus ini, dimungkinkan untuk mengganti jwks_uri pada OpenID Provider Configuration untuk diarahkan ke endpoint publik sebagai ganti alamat server API dengan memberikan flag --service-account-jwks-uri ke API server. serupa dengan URL issuer, URI JWKS diharuskan untuk menggunakan skema https.

Selanjutnya

Lihat juga:

7 - Menarik Image dari Register Pribadi

Laman ini menunjukkan cara membuat Pod dengan menggunakan Secret untuk menarik image dari sebuah register atau repositori pribadi untuk Docker.

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.

  • Untuk melakukan latihan ini, kamu memerlukan sebuah nama pengguna (ID) Docker dan kata sandi (password).

Masuk (login) ke Docker

Pada laptop kamu, kamu harus melakukan autentikasi dengan register untuk menarik image pribadi:

docker login

Ketika diminta, masukkan nama pengguna dan kata sandi Docker kamu.

Proses login membuat atau memperbarui berkas config.json yang menyimpan sebuah token otorisasi.

Lihatlah berkas config.json:

cat ~/.docker/config.json

Keluaran berisi bagian yang serupa dengan ini:

{
    "auths": {
        "https://index.docker.io/v1/": {
            "auth": "c3R...zE2"
        }
    }
}

Membuat Secret berdasarkan kredensial Docker yang sudah ada

Klaster Kubernetes menggunakan Secret dari tipe docker-registry untuk melakukan autentikasi dengan register Container untuk menarik image pribadi.

Jika kamu sudah menjalankan docker login, kamu dapat menyalin kredensial itu ke Kubernetes:

kubectl create secret generic regcred \
    --from-file=.dockerconfigjson=<path/to/.docker/config.json> \
    --type=kubernetes.io/dockerconfigjson

Jika kamu memerlukan lebih banyak kontrol (misalnya, untuk mengatur Namespace atau label baru pada Secret) maka kamu dapat menyesuaikan Secret tersebut sebelum menyimpannya. Pastikan untuk:

  • Mengatur nama dari pokok (item) data menjadi .dockerconfigjson
  • Melakukan enkode secara base64 dari Dockerfile (berkas Docker) dan memindahkan urutan huruf (string) tersebut, secara tidak terputus sebagai nilai untuk bidang data[".dockerconfigjson"]
  • Mengatur type menjadi kubernetes.io/dockerconfigjson

Sebagai contoh:

apiVersion: v1
kind: Secret
metadata:
  name: myregistrykey
  namespace: awesomeapps
data:
  .dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
type: kubernetes.io/dockerconfigjson

Jika kamu mendapat pesan kesalahan error: no objects passed to create, ini berarti pengkodean base64 dari urutan huruf tersebut tidak valid. Jika kamu mendapat pesan kesalahan seperti Secret "myregistrykey" is invalid: data[.dockerconfigjson]: invalid value ..., ini berarti enkode base64 dari urutan huruf dalam data tersebut sukses didekodekan, tetapi tidak bisa diuraikan menjadi berkas .docker/config.json.

Membuat Secret dengan memberikan kredensial pada baris perintah

Buatlah Secret ini, dan berilah nama regcred:

kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>

dimana:

  • <your-registry-server> merupakan FQDN dari register privat Docker kamu. (https://index.docker.io/v1/ untuk DockerHub)
  • <your-name> adalah nama pengguna Docker kamu.
  • <your-pword> adalah kata sandi Docker kamu.
  • <your-email> adalah alamat email Docker kamu.

Kamu telah berhasil mengatur kredensial untuk Docker kamu pada klaster sebagai sebuah Secret yang dipanggil dengan nama regcred.

Menginspeksi Secret regcred

Untuk memahami isi Secret regcred yang baru saja kamu buat, mulailah dengan melihat Secret dalam format YAML:

kubectl get secret regcred --output=yaml

Keluarannya akan seperti ini:

apiVersion: v1
kind: Secret
metadata:
  ...
  name: regcred
  ...
data:
  .dockerconfigjson: eyJodHRwczovL2luZGV4L ... J0QUl6RTIifX0=
type: kubernetes.io/dockerconfigjson

Nilai dari bidang .dockerconfigjson merupakan representasi dalam base64 dari kredensial Docker kamu.

Untuk memahami apa yang ada dalam bidang .dockerconfigjson, ubahlah data Secret menjadi format yang bisa terbaca:

kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode

Keluarannya akan seperti ini:

{"auths":{"your.private.registry.example.com":{"username":"janedoe","password":"xxxxxxxxxxx","email":"jdoe@example.com","auth":"c3R...zE2"}}}

Untuk memahami apa yang ada dalam bidang auth, ubahlah data Secret menjadi format yang bisa terbaca:

echo "c3R...zE2" | base64 --decode

Keluarannya, nama pengguna dan kata sandi yang digabungkan dengan tanda :, seperti dibawah ini:

janedoe:xxxxxxxxxxx

Perhatikan bahwa data Secret berisi token otorisasi yang serupa dengan berkas ~/.docker/config.json lokal kamu.

Kamu telah berhasil menetapkan kredensial Docker kamu sebagai sebuah Secret yang dipanggil dengan regcred pada klaster.

Membuat Pod yang menggunakan Secret kamu

Berikut ini adalah berkas konfigurasi untuk Pod yang memerlukan akses ke kredensial Docker kamu pada regcred:

apiVersion: v1
kind: Pod
metadata:
  name: private-reg
spec:
  containers:
  - name: private-reg-container
    image: <image-pribadi-kamu>
  imagePullSecrets:
  - name: regcred

Unduh berkas diatas:

wget -O my-private-reg-pod.yaml https://k8s.io/examples/pods/private-reg-pod.yaml

Dalam berkas my-private-reg-pod.yaml, ubah <your-private-image> dengan tautan ke image dalam register pribadi seperti ini:

your.private.registry.example.com/janedoe/jdoe-private:v1

Untuk menarik image dari register pribadi, Kubernetes memerlukan kredensial. Bidang imagePullSecrets dalam berkas konfigurasi menentukan bahwa Kubernetes harus mendapatkan kredensial dari Secret yang bernama regcred.

Buatlah Pod yang menggunakan Secret kamu, dan verifikasi bahwa Pod tersebut berjalan:

kubectl apply -f my-private-reg-pod.yaml
kubectl get pod private-reg

Selanjutnya

8 - 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/e2e-test-images/agnhost.

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/e2e-test-images/agnhost:2.40
    args:
    - liveness
    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:

9 - Menempatkan Pod pada Node Menggunakan Afinitas Pod

Dokumen ini menunjukkan cara menempatkan Pod Kubernetes pada sebuah Node menggunakan Afinitas Node di dalam klaster Kubernetes.

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:

Kubernetes servermu harus dalam versi yang sama atau lebih baru dari v1.10. Untuk melihat versi, tekan kubectl version.

Menambahkan sebuah Label pada sebuah Node

  1. Jabarkan Node-Node yang ada pada klaster kamu, bersamaan dengan label yang ada:

    kubectl get nodes --show-labels
    

    Keluaran dari perintah tersebut akan berupa:

    NAME      STATUS    ROLES    AGE     VERSION        LABELS
    worker0   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker0
    worker1   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker1
    worker2   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker2
    
  2. Pilihkan salah satu dari Node yang ada dan tambahkan label pada Node tersebut.

    kubectl label nodes <nama-node-kamu> disktype=ssd
    

    dimana <nama-node-kamu> merupakan nama dari Node yang kamu pilih.

  3. Keluaran dari Node yang kamu pilih dan sudah memiliki label disktype=ssd:

    kubectl get nodes --show-labels
    

    Keluaran dari perintah tersebut akan berupa:

    NAME      STATUS    ROLES    AGE     VERSION        LABELS
    worker0   Ready     <none>   1d      v1.13.0        ...,disktype=ssd,kubernetes.io/hostname=worker0
    worker1   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker1
    worker2   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker2
    

    Pada keluaran dari perintah di atas, kamu dapat melihat bahwa Node worker0 memiliki label disktype=ssd.

Menjadwalkan Pod menggunakan Afinitas Node

Konfigurasi ini menunjukkan sebuah Pod yang memiliki afinitas node requiredDuringSchedulingIgnoredDuringExecution, disktype: ssd. Dengan kata lain, Pod hanya akan dijadwalkan hanya pada Node yang memiliki label disktype=ssd.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd            
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

  1. Terapkan konfigurasi berikut untuk membuat sebuah Pod yang akan dijadwalkan pada Node yang kamu pilih:

    kubectl apply -f https://k8s.io/examples/pods/pod-nginx-required-affinity.yaml
    
  2. Verifikasi apakah Pod yang kamu pilih sudah dijalankan pada Node yang kamu pilih:

    kubectl get pods --output=wide
    

    Keluaran dari perintah tersebut akan berupa:

    NAME     READY     STATUS    RESTARTS   AGE    IP           NODE
    nginx    1/1       Running   0          13s    10.200.0.4   worker0
    

Jadwalkan Pod menggunakan Afinitas Node yang Dipilih

Konfigurasi ini memberikan deskripsi sebuah Pod yang memiliki afinitas Node preferredDuringSchedulingIgnoredDuringExecution,disktype: ssd. Artinya Pod akan diutamakan dijalankan pada Node yang memiliki label disktype=ssd.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd          
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

  1. Terapkan konfigurasi berikut untuk membuat sebuah Pod yang akan dijadwalkan pada Node yang kamu pilih:

    kubectl apply -f https://k8s.io/examples/pods/pod-nginx-preferred-affinity.yaml
    
  2. Verifikasi apakah Pod yang kamu pilih sudah dijalankan pada Node yang kamu pilih:

    kubectl get pods --output=wide
    

    Keluaran dari perintah tersebut akan berupa:

    NAME     READY     STATUS    RESTARTS   AGE    IP           NODE
    nginx    1/1       Running   0          13s    10.200.0.4   worker0
    

Selanjutnya

Pelajari lebih lanjut mengenai Afinitas Node.

10 - Mengatur Pod untuk Menggunakan ConfigMap

ConfigMap mengizinkan kamu untuk memisahkan artifak-artifak konfigurasi dari konten image untuk menjaga aplikasi yang dikontainerisasi tetap portabel. Artikel ini menyediakan sekumpulan contoh penerapan yang mendemonstrasikan bagaimana cara membuat ConfigMap dan mengatur Pod menggunakan data yang disimpan di dalam ConfigMap.

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.

Membuat ConfigMap

Kamu dapat menggunakan kubectl create configmap ataupun generator ConfigMap pada kustomization.yaml untuk membuat sebuah ConfigMap. Perlu diingat bahwa kubectl mulai mendukung kustomization.yaml sejak versi 1.14.

Membuat ConfigMap Menggunakan kubectl create configmap

Gunakan perintah kubectl create configmap untuk membuat ConfigMap dari direktori, berkas, ataupun nilai-nilai yang harfiah (literal values):

kubectl create configmap <map-name> <data-source>

di mana <map-name> merupakan nama yang ingin kamu berikan pada ConfigMap tersebut dan <data-source> adalah direktori, berkas, atau nilai harfiah yang digunakan sebagai sumber data. Nama dari sebuah objek ConfigMap haruslah berupa nama subdomain DNS yang sah.

Ketika kamu membuat ConfigMap dari sebuah berkas, secara bawaan, basename dari berkas tersebut akan menjadi kunci pada <data-source>, dan isi dari berkas tersebut akan menjadi nilai dari kunci tersebut.

Kamu dapat menggunakan kubectl describe atau kubectl get untuk mengambil informasi mengenai sebuah ConfigMap.

Membuat ConfigMap dari direktori

Kamu dapat menggunakan kubectl create configmap untuk membuat sebuah ConfigMap dari banyak berkas dalam sebuah direktori yang sama. Ketika kamu membuat sebuah ConfigMap dari sebuah direktori, kubectl akan mengidentifikasi berkas-berkas yang memiliki basename yang merupakan sebuah kunci yang sah pada direktori dan mengemas tiap berkas tersebut ke dalam sebuah ConfigMap baru. Seluruh entri direktori kecuali berkas reguler akan diabaikan (subdirektori, symlink, device, pipe, dsb).

Sebagai contoh:

# Membuat direktori lokal
mkdir -p configure-pod-container/configmap/

# Mengunduh berkas-berkas sampel ke dalam direktori `configure-pod-container/configmap/`
wget https://kubernetes.io/examples/configmap/game.properties -O configure-pod-cont1ainer/configmap/game.properties
wget https://kubernetes.io/examples/configmap/ui.properties -O configure-pod-container/configmap/ui.properties

# Membuat configmap
kubectl create configmap game-config --from-file=configure-pod-container/configmap/

Perintah di atas mengemas tiap berkas, dalam kasus ini, game.properties dan ui.properties dalam direktori configure-pod-container/configmap/ ke dalam ConfigMap dengan nama game-config. Kamu dapat menampilkan detail dari ConfigMap menggunakan perintah berikut:

kubectl describe configmaps game-config

Keluaran akan tampil seperti berikut:

Name:         game-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice

Berkas-berkas game.properties dan ui.properties pada direktori configure-pod-container/configmap/ direpresentasikan oleh bagian data pada ConfigMap.

kubectl get configmaps game-config -o yaml

Keluaran akan tampil seperti berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2016-02-18T18:52:05Z
  name: game-config
  namespace: default
  resourceVersion: "516"
  uid: b4952dc3-d670-11e5-8cd0-68f728db1985
data:
  game.properties: |
    enemies=aliens
    lives=3
    enemies.cheat=true
    enemies.cheat.level=noGoodRotten
    secret.code.passphrase=UUDDLRLRBABAS
    secret.code.allowed=true
    secret.code.lives=30    
  ui.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true
    how.nice.to.look=fairlyNice    

Membuat ConfigMap dari berkas

Kamu dapat menggunakan kubectl create configmap untuk membuat sebuah ConfigMap dari berkas individual, atau dari banyak berkas.

Sebagai contoh,

kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties

akan menghasilkan ConfigMap berikut:

kubectl describe configmaps game-config-2

dengan keluaran seperti berikut:

Name:         game-config-2
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30

Kamu dapat memasukkan argumen --from-file beberapa kali untuk membuat sebuah ConfigMap dari banyak sumber data.

kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties --from-file=configure-pod-container/configmap/ui.properties

Kamu dapat menampilkan detail dari ConfigMap game-config-2 menggunakan perintah berikut:

kubectl describe configmaps game-config-2

Keluaran akan tampil seperti berikut:

Name:         game-config-2
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice

Gunakan opsi --from-env-file untuk membuat sebuah ConfigMap dari sebuah env-file, sebagai contoh:

# Env-file berisi sebuah daftar variabel _environment_.
# Ada aturan-aturan sintaks yang berlaku:
#   Tiap baris pada sebuah env file harus memiliki format VAR=VAL.
#   Baris yang diawali # (komentar) akan diabaikan.
#   Baris-baris kosong akan diabaikan.
#   Tidak ada penanganan spesial untuk tanda kutip (tanda kutip akan menjadi bagian dari nilai pada ConfigMap).

# Mengunduh berkas-berkas sampel berikut ke dalam direktori `configure-pod-container/configmap/`
wget https://kubernetes.io/examples/configmap/game-env-file.properties -O configure-pod-container/configmap/game-env-file.properties

# Berkas env-file `game-env-file.properties` berisi sebagai berikut:
cat configure-pod-container/configmap/game-env-file.properties
enemies=aliens
lives=3
allowed="true"

# Komentar ini dan baris kosong di atasnya akan diabaikan.
kubectl create configmap game-config-env-file \
       --from-env-file=configure-pod-container/configmap/game-env-file.properties

akan menghasilkan ConfigMap sebagai berikut:

kubectl get configmap game-config-env-file -o yaml

dengan keluaran seperti berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2017-12-27T18:36:28Z
  name: game-config-env-file
  namespace: default
  resourceVersion: "809965"
  uid: d9d1ca5b-eb34-11e7-887b-42010a8002b8
data:
  allowed: '"true"'
  enemies: aliens
  lives: "3"

Contoh perilaku memasukkan --from-env-file beberapa kali didemonstrasikan dengan:

# Mengunduh berkas-berkas sampel berikut ke dalam direktori `configure-pod-container/configmap/` 
wget https://kubernetes.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties

# Membuat configmap
kubectl create configmap config-multi-env-files \
        --from-env-file=configure-pod-container/configmap/game-env-file.properties \
        --from-env-file=configure-pod-container/configmap/ui-env-file.properties

akan menghasilkan ConfigMap sebagai berikut:

kubectl get configmap config-multi-env-files -o yaml

dengan keluaran seperti berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2017-12-27T18:38:34Z
  name: config-multi-env-files
  namespace: default
  resourceVersion: "810136"
  uid: 252c4572-eb35-11e7-887b-42010a8002b8
data:
  color: purple
  how: fairlyNice
  textmode: "true"

Menentukan kunci yang akan digunakan ketika membuat ConfigMap dari sebuah berkas

Kamu dapat menentukan kunci selain dari nama berkas untuk digunakan pada bagian data pada ConfigMap yang kamu buat menggunakan argumen --from-file:

kubectl create configmap game-config-3 --from-file=<my-key-name>=<path-to-file>

di mana <my-key-name> merupakan kunci yang ingin kamu gunakan pada ConfigMap dan <path-to-file> merupakan lokasi dari berkas sumber data yang akan menjadi nilai dari kunci tersebut.

Sebagai contoh:

kubectl create configmap game-config-3 --from-file=game-special-key=configure-pod-container/configmap/game.properties

akan menghasilkan ConfigMap sebagai berikut:

kubectl get configmaps game-config-3 -o yaml

dengan keluaran seperti berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2016-02-18T18:54:22Z
  name: game-config-3
  namespace: default
  resourceVersion: "530"
  uid: 05f8da22-d671-11e5-8cd0-68f728db1985
data:
  game-special-key: |
    enemies=aliens
    lives=3
    enemies.cheat=true
    enemies.cheat.level=noGoodRotten
    secret.code.passphrase=UUDDLRLRBABAS
    secret.code.allowed=true
    secret.code.lives=30    

Membuat ConfigMap dari nilai harfiah

Kamu dapat menggunakan kubectl create configmap dengan argumen --from-literal untuk menentukan nilai harfiah dari baris perintah:

kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm

Kamu dapat memasukkan beberapa pasang kunci-nilai. Tiap pasang yang dimasukkan pada command line direpresentasikan sebagai sebuah entri terpisah pada bagian data dari ConfigMap.

kubectl get configmaps special-config -o yaml

Keluaran akan tampil seperti berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2016-02-18T19:14:38Z
  name: special-config
  namespace: default
  resourceVersion: "651"
  uid: dadce046-d673-11e5-8cd0-68f728db1985
data:
  special.how: very
  special.type: charm

Membuat ConfigMap dari generator

kubectl mendukung kustomization.yaml sejak versi 1.14. Kamu juga dapat membuat ConfigMap dari generator lalu menggunakannya untuk membuat objek tersebut pada peladen API. Generator harus dituliskan pada kustomization.yaml dalam sebuah direktori.

Menghasilkan ConfigMap dari berkas

Sebagai contoh, untuk menghasilkan ConfigMap dari berkas configure-pod-container/configmap/game.properties

# Membuat berkas kustomization.yaml dengan ConfigMapGenerator
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-4
  files:
  - configure-pod-container/configmap/game.properties
EOF

Gunakan direktori kustomization untuk membuat objek ConfigMap.

kubectl apply -k .
configmap/game-config-4-m9dm2f92bt created

Kamu dapat melihat ConfigMap yang dihasilkan seperti berikut:

kubectl get configmap
NAME                       DATA   AGE
game-config-4-m9dm2f92bt   1      37s


kubectl describe configmaps/game-config-4-m9dm2f92bt
Name:         game-config-4-m9dm2f92bt
Namespace:    default
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","data":{"game.properties":"enemies=aliens\nlives=3\nenemies.cheat=true\nenemies.cheat.level=noGoodRotten\nsecret.code.p...

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
Events:  <none>

Perlu diingat baha nama dari ConfigMap yang dihasilkan memiliki sufiks yang ditambahkan dengan melakukan hashing terhadap konten dari ConfigMap tersebut. Hal ini memastikan bahwa sebuah ConfigMap baru akan dihasilkan setiap kali konten dimodifikasi.

Menentukan kunci yang akan digunakan ketika generating ConfigMap dari sebuah berkas

Kamu dapat menentukan kunci selain nama berkas untuk digunakan pada generator ConfigMap. Sebagai contoh, untuk menghasilkan sebuah ConfigMap dari berkas configure-pod-container/configmap/game.properties dengan kunci game-special-key

# Membuat berkas kustomization.yaml dengan ConfigMapGenerator
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-5
  files:
  - game-special-key=configure-pod-container/configmap/game.properties
EOF

Gunakan direktori kustomization untuk membuat objek ConfigMap.

kubectl apply -k .
configmap/game-config-5-m67dt67794 created

Menghasilkan ConfigMap dari Nilai-nilai Harfiah

Untuk menghasilkan ConfigMap dari nilai-nilai harfiah special.type=charm dan special.how=very, kamu dapat menentukan generator ConfigMap pada kustomization.yaml sebagai berikut

# Membuat berkas kustomization.yaml dengan ConfigMapGenerator
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: special-config-2
  literals:
  - special.how=very
  - special.type=charm
EOF

Gunakan direktori kustomization untuk membuat objek ConfigMap.

kubectl apply -k .
configmap/special-config-2-c92b5mmcf2 created

Menentukan variabel environment kontainer menggunakan data ConfigMap

Menentukan variabel environment kontainer dengan data dari sebuah ConfigMap

  1. Menentukan sebuah variabel environment sebagai sepasang kunci-nilai pada ConfigMap:

    kubectl create configmap special-config --from-literal=special.how=very
    
  2. Memberikan nilai special.how yang sudah terdapat pada ConfigMap pada variabel environment SPECIAL_LEVEL_KEY di spesifikasi Pod.

apiVersion: v1
   kind: Pod
   metadata:
     name: dapi-test-pod
   spec:
     containers:
       - name: test-container
         image: registry.k8s.io/busybox
         command: [ "/bin/sh", "-c", "env" ]
         env:
           # Tentukan variabel environment
           - name: SPECIAL_LEVEL_KEY
             valueFrom:
               configMapKeyRef:
                 # ConfigMap berisi nilai yang ingin kamu berikan pada SPECIAL_LEVEL_KEY
                 name: special-config
                 # Tentukan kunci yang diasosiasikan dengan nilainya
                 key: special.how
     restartPolicy: Never
   

Buat Pod:

kubectl create -f https://kubernetes.io/id/examples/pods/pod-single-configmap-env-variable.yaml

Sekarang, keluaran dari Pod meliputi variabel environment SPECIAL_LEVEL_KEY=very.

Menentukan variabel environment kontainer dengan data dari beberapa ConfigMap

  • Seperti pada contoh sebelumnya, buat ConfigMap terlebih dahulu.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: special-config
      namespace: default
    data:
      special.how: very
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: env-config
      namespace: default
    data:
      log_level: INFO
    

    Buat ConfigMap:

kubectl create -f https://kubernetes.io/examples/configmap/configmaps.yaml
  • Tentukan variabel environment pada spesifikasi Pod.

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-test-pod
    spec:
      containers:
        - name: test-container
          image: registry.k8s.io/busybox
          command: [ "/bin/sh", "-c", "env" ]
          env:
            - name: SPECIAL_LEVEL_KEY
              valueFrom:
                configMapKeyRef:
                  name: special-config
                  key: special.how
            - name: LOG_LEVEL
              valueFrom:
                configMapKeyRef:
                  name: env-config
                  key: log_level
      restartPolicy: Never
    

    Buat Pod:

kubectl create -f https://kubernetes.io/id/examples/pods/pod-multiple-configmap-env-variable.yaml

Sekarang, keluaran Pod meliputi variabel environment SPECIAL_LEVEL_KEY=very dan LOG_LEVEL=INFO.

Mengatur semua pasangan kunci-nilai pada ConfigMap sebagai variabel environment kontainer

  • Buat ConfigMap yang berisi beberapa pasangan kunci-nilai.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: special-config
      namespace: default
    data:
      SPECIAL_LEVEL: very
      SPECIAL_TYPE: charm
    

    Buat ConfigMap:

kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml
  • Gunakan envFrom untuk menentukan seluruh data pada ConfigMap sebagai variabel environment kontainer. Kunci dari ConfigMap akan menjadi nama variabel environment di dalam Pod.
apiVersion: v1
 kind: Pod
 metadata:
   name: dapi-test-pod
 spec:
   containers:
     - name: test-container
       image: registry.k8s.io/busybox
       command: [ "/bin/sh", "-c", "env" ]
       envFrom:
       - configMapRef:
           name: special-config
   restartPolicy: Never
 

Buat Pod:

kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-envFrom.yaml

Sekarang, Pod keluaran pod meliputi variabel environment SPECIAL_LEVEL=very dan SPECIAL_TYPE=charm.

Menggunakan variabel environment yang ditentukan ConfigMap pada perintah Pod

Kamu dapat menggunakan variabel environment yang ditentukan ConfigMap pada bagian command dari spesifikasi Pod menggunakan sintaks substitusi Kubernetes $(VAR_NAME).

Sebagai contoh, spesifikasi Pod berikut

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
      env:
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: SPECIAL_LEVEL
        - name: SPECIAL_TYPE_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: SPECIAL_TYPE
  restartPolicy: Never

dibuat dengan menjalankan

kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-env-var-valueFrom.yaml

menghasilkan keluaran pada kontainer test-container seperti berikut:

kubectl logs dapi-test-pod
very charm

Menambahkan data ConfigMap pada Volume

Seperti yang sudah dijelaskan pada Membuat ConfigMap dari berkas, ketika kamu membuat ConfigMap menggunakan --from-file, nama dari berkas tersebut akan menjadi kunci yang disimpan pada bagian data dari ConfigMap. Isi berkas tersebut akan menjadi nilai dari kunci tersebut.

Contoh pada bagian ini merujuk pada ConfigMap bernama special-config, Seperti berikut.

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  SPECIAL_LEVEL: very
  SPECIAL_TYPE: charm

Buat ConfigMap:

kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml

Mengisi Volume dengan data yang disimpan Pada ConfigMap

Tambahkan nama ConfigMap di bawah bagian volumes pada spesifikasi Pod. Hal ini akan menambahkan data ConfigMap pada direktori yang ditentukan oleh volumeMounts.mountPath (pada kasus ini, /etc/config). Bagian command berisi daftar berkas pada direktori dengan nama-nama yang sesuai dengan kunci-kunci pada ConfigMap.

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh", "-c", "ls /etc/config/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        # Berikan nama dari ConfigMap yang berisi berkas-berkas yang ingin kamu
        # tambahkan ke kontainer
        name: special-config
  restartPolicy: Never

Buat Pod:

kubectl create -f https://kubernetes.io/i/examples/pods/pod-configmap-volume.yaml

Ketika Pod berjalan, perintah ls /etc/config/ akan menghasilkan keluaran di bawah:

SPECIAL_LEVEL
SPECIAL_TYPE

Menambahkan data ConfigMap pada jalur tertentu pada Volume

Gunakan kolom path untuk menentukan jalur berkas yang diinginkan untuk butir tertentu pada ConfigMap (butir ConfigMap tertentu). Pada kasus ini, butir SPECIAL_LEVEL akan akan dipasangkan sebagai config-volume pada /etc/config/keys.

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh","-c","cat /etc/config/keys" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
        items:
        - key: SPECIAL_LEVEL
          path: keys
  restartPolicy: Never

Buat Pod:

kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume-specific-key.yaml

Ketika Pod berjalan, perintah cat /etc/config/keys akan menghasilkan keluaran di bawah:

very

Memproyeksikan kunci ke jalur dan perizinan berkas tertentu

Kamu dapat memproyeksikan kunci ke jalur dan perizinan tertentu pada setiap berkas. Panduan pengguna Secret menjelaskan mengenai sintaks-sintaksnya.

ConfigMap yang dipasang akan diperbarui secara otomatis

Ketika sebuah ConfigMap yang sudah dipasang pada sebuah volume diperbarui, kunci-kunci yang diproyeksikan akan turut diperbarui. Kubelet akan memeriksa apakah ConfigMap yang dipasang merupakan yang terbaru pada sinkronisasi berkala. Namun, ConfigMap menggunakan cache lokal berbasis ttl (time-to-live) miliknya untuk mendapatkan nilai dari ConfigMap saat ini. Hasilnya, keseluruhan penundaan dari saat ketika ConfigMap diperbarui sampai saat ketika kunci-kunci baru diproyeksikan ke pada Pod bisa selama periode sinkronisasi kubelet (secara bawaan selama 1 menit) + ttl dari cache ConfigMap (secara bawaan selama 1 menit) pada kubelet. Kamu dapat memicu pembaruan langsung dengan memperbarui salah satu dari anotasi Pod.

Memahami ConfigMap dan Pod

Sumber daya API ConfigMap menyimpan data konfigurasi sebagai pasangan kunci-nilai. Data tersebut dapat dikonsumsi oleh Pod atau sebagai penyedia konfigurasi untuk komponen-komponen sistem seperti kontroler. ConfigMap mirip dengan Secret, tetapi ConfigMap dimaksudkan untuk mengolah tulisan yang tidak memiliki informasi yang sensitif. Baik pengguna maupun komponen sistem dapat menyimpan data konfigurasi pada ConfigMap.

Kolom data pada ConfigMap berisi data konfigurasi. Seperti pada contoh di bawah, hal ini bisa berupa sesuatu yang sederhana -- seperti properti individual yang ditentukan menggunakan --from-literal -- atau sesuatu yang kompleks -- seperti berkas konfigurasi atau blob JSON yang ditentukan dengan --from-file.

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2016-02-18T19:14:38Z
  name: example-config
  namespace: default
data:
  # contoh properti yang sederhana yang ditentukan menggunakan --from-literal
  example.property.1: hello
  example.property.2: world
  # contoh properti yang kompleks yang ditentukan menggunakan --from-file
  example.property.file: |-
    property.1=value-1
    property.2=value-2
    property.3=value-3    

Batasan

  • Kamu harus membuat ConfigMap sebelum merujuknya pada spesifikasi Pod (kecuali kamu menandai ConfigMap sebagai "optional"). Jika kamu merujuk sebuah ConfigMap yang tidak ada, Pod tersebut tidak akan berjalan. Sama halnya, mereferensikan kunci yang tidak ada pada ConfigMap akan mencegah Pod untuk berjalan.

  • Jika kamu menggunakan envFrom untuk menentukan variabel environment dari ConfigMap, kunci-kunci yang dianggap tidak sah akan dilewat. Pod akan diizinkan untuk berjalan, tetapi nama-nama yang tidak sah akan direkam pada event log (InvalidVariableNames). Pesan log tersebut mencantumkan tiap kunci yang dilewat. Sebagai contoh:

    kubectl get events
    

    Keluaran akan tampil seperti berikut:

    LASTSEEN FIRSTSEEN COUNT NAME          KIND  SUBOBJECT  TYPE      REASON                            SOURCE                MESSAGE
    0s       0s        1     dapi-test-pod Pod              Warning   InvalidEnvironmentVariableNames   {kubelet, 127.0.0.1}  Keys [1badkey, 2alsobad] from the EnvFrom configMap default/myconfig were skipped since they are considered invalid environment variable names.
    
  • ConfigMap berada pada Namespace tertentu. ConfigMap hanya dapat dirujuk oleh Pod yang berada pada Namespace yang sama.

  • Kamu tidak dapat menggunakan ConfigMap untuk Pod statis, karena Kubelet tidak mendukung hal ini.

Selanjutnya

11 - Pembagian Namespace Proses antar Container pada sebuah Pod

FEATURE STATE: Kubernetes v1.17 [stable]

Dokumen ini akan menjelaskan menkanisme konfigurasi pembagian namespace process dalam sebuah Pod. Ketika pembagian namespace proses diaktifkan untuk sebuah Pod, proses yang ada di dalam Container akan bersifat transparan pada semua Container yang terdapat di dalam Pod tersebut.

Kamu dapat mengaktifkan fitur ini untuk melakukan konfigurasi kontainer yang saling terhubung, misalnya saja kontainer sidecar yang bertugas dalam urusan log, atau untuk melakukan proses pemecahan masalah (troubleshoot) image kontainer yang tidak memiliki utilitas debugging seperti shell.

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:

Kubernetes servermu harus dalam versi yang sama atau lebih baru dari v1.10. Untuk melihat versi, tekan kubectl version.

Mengatur sebuah Pod

Pembagian namespace proses (Process Namespace Sharing) diaktifkan menggunakan field shareProcessNamespace v1.PodSpec. Sebagai contoh:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  shareProcessNamespace: true
  containers:
  - name: nginx
    image: nginx
  - name: shell
    image: busybox
    securityContext:
      capabilities:
        add:
        - SYS_PTRACE
    stdin: true
    tty: true
  1. Buatlah sebuah Pod nginx di dalam klaster kamu:

    kubectl apply -f https://k8s.io/examples/pods/share-process-namespace.yaml
    
  2. Tempelkan kontainer shell dan jalankan perintah ps:

    kubectl exec -it nginx -c shell -- /bin/sh
    

    Jika kamu tidak melihat prompt perintah, kamu dapat menekan tombol enter:

    / # ps ax
    PID   USER     TIME  COMMAND
        1 root      0:00 /pause
        8 root      0:00 nginx: master process nginx -g daemon off;
       14 101       0:00 nginx: worker process
       15 root      0:00 sh
       21 root      0:00 ps ax
    

Kamu dapat memberikan sinyal pada kontainer lain. Misalnya saja, mengirim sinyal SIGHUP pada nginx untuk menjalankan ulang proses worker. Hal ini membutuhkan kapabilitas SYS_PTRACE.

/ # kill -HUP 8
/ # ps ax
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    8 root      0:00 nginx: master process nginx -g daemon off;
   15 root      0:00 sh
   22 101       0:00 nginx: worker process
   23 root      0:00 ps ax

Hal ini juga merupakan alasan mengapa kita dapat mengakses kontainer lain menggunakan tautan (link) /proc/$pid/root.

/ # head /proc/8/root/etc/nginx/nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;

Memahami Pembagian Namespace Process

Pod berbagi banyak sumber daya yang ada sehingga memungkinkan adanya pembagian namespace proses. Beberapa image kontainer bisa jadi terisolasi dari kontainer lainnya, meskipun begitu, memahami beberapa perbedaan berikut juga merupakan hal yang penting untuk diketahui:

  1. Proses kontainer tidak lagi memiliki PID 1. Beberapa image kontainer akan menolak untuk dijalankan (contohnya, kontainer yang menggunakan systemd) atau menjalankan perintah seperti kill -HUP 1 untuk memberikan sinyal pada proses kontainer. Di dalam Pod dengan sebuah namespace process terbagi, sinyal kill -HUP 1 akan diberikan pada sandbox Pod. (/pause pada contoh di atas.)

  2. Proses-proses yang ada akan transparan pada kontainer lain di dalam Pod. Hal ini termasuk informasi pada /proc, seperti kata sandi yang diberikan sebagai argumen atau environment variable. Hal ini hanya dilindungi oleh perizinan reguler Unix.

  3. Berkas sistem (filesystem) kontainer bersifat transparan pada kontainer lain di dalam Pod melalui link /proc/$pid/root. Hal ini memungkinkan proses debugging menjadi lebih mudah, meskipun begitu hal ini juga berarti kata kunci (secret) yang ada di dalam filesystem juga hanya dilindungi oleh perizinan filesystem saja.

12 - Membuat Pod Statis

Pod statis dikelola langsung oleh daemon kubelet pada suatu Node spesifik, tanpa API server mengobservasi mereka. Tidak seperti Pod yang dikelola oleh control plane (contohnya, Deployment); kubelet akan memantau setiap Pod statis (dan menjalankan ulang jika Pod mengalami kegagalan).

Pod statis selalu terikat pada satu Kubelet di dalam Node spesifik.

Kubelet secara otomatis akan mengulang untuk membuat sebuah Pod mirror pada server API Kubernetes untuk setiap Pod statis. Ini berarti Pod yang berjalan pada Node akan terlihat oleh API server, namun tidak dapat mengontrol dari sana.

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.

Laman ini mengasumsikan kamu menggunakan CRI-O untuk menjalankan Pod, dan Node kamu berjalan menggunakan sistem operasi Fedora. Instruksi untuk distribusi lain atau instalasi Kubernetes mungkin berbeda.

Membuat sebuah Pod statis

Kamu dapat mengatur Pod statis dengan menggunakan sebuah berkas konfigurasi pada file system atau sebuah berkas konfigurasi ditempatkan pada web.

Manifes Pod statis pada berkas sistem (file system)

Manifes adalah standar definisi Pod dalam format JSON atau YAML pada suatu direktori. Gunakan field staticPodPath: <direktori> pada berkas konfigurasi kubelet, yang akan membaca direktori secara berkala dan membuat atau menghapus Pod statis sesuai dengan berkas YAML/JSON yang bertambah atau berkurang disana.

Catatan bahwa kubelet akan mengabaikan berkas yang diawali dengan titik (dot) ketika memindai suatu direktori.

Sebagai contoh, ini cara untuk memulai server web sederhana sebagai Pod statis:

  1. Pilih Node yang kamu pilih untuk menjalankan Pod statis. Dalam contoh ini adalah my-node1.

    ssh my-node1
    
  2. Pilih sebuah direktori, katakan /etc/kubelet.d dan letakkan berkas definisi Pod untuk web server disana, contohnya /etc/kubelet.d/static-web.yaml:

    # Jalankan perintah ini pada Node tempat kubelet sedang berjalan
    mkdir /etc/kubelet.d/
    cat <<EOF >/etc/kubelet.d/static-web.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: static-web
      labels:
        role: myrole
    spec:
      containers:
        - name: web
          image: nginx
          ports:
            - name: web
              containerPort: 80
              protocol: TCP
    EOF
    
  3. Atur kubelet pada Node untuk menggunakan direktori ini dengan menjalankannya menggunakan argumen --pod-manifest-path=/etc/kubelet.d/. Pada Fedora, ubah berkas /etc/kubernetes/kubelet dengan menambahkan baris berikut:

    KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --pod-manifest-path=/etc/kubelet.d/"
    

    atau tambahkan field staticPodPath: <direktori> pada berkas konfigurasi kubelet.

  4. Jalankan ulang kubelet. Pada Fedora, kamu dapat menjalankan:

    # Jalankan perintah berikut pada Node tempat kubelet berjalan
    systemctl restart kubelet
    

Manifes Pod statis pada Web

Berkas yang ditentukan pada argumen --manifest-url=<URL> akan diunduh oleh kubelet secara berkala dan kubelet akan menginterpretasinya sebagai sebuah berkas JSON/YAML yang berisikan definisi Pod. Mirip dengan cara kerja manifes pada filesystem, kubelet akan mengambil manifes berdasarkan jadwal. Jika ada perubahan pada daftar Pod statis, maka kubelet akan menerapkannya.

Untuk menggunakan cara ini:

  1. Buat sebuah berkas YAML dan simpan pada suatu web server sehingga kamu pada memberikan URL tersebut pada kubelet.

    apiVersion: v1
    kind: Pod
    metadata:
      name: static-web
      labels:
        role: myrole
    spec:
      containers:
        - name: web
          image: nginx
          ports:
            - name: web
              containerPort: 80
              protocol: TCP
    
  2. Atur kubelet pada suatu Node untuk menggunakan manifes pada web ini dengan menjalankan menggunakan argumen --manifest-url=<url-manifes>. Pada Fedora, ubah pada /etc/kubernetes/kubelet untuk menambahkan baris ini:

    KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --manifest-url=<url-manifes>"
    
  3. Jalankan ulang kubelet. Pada Fedora, kamu dapat menjalankan:

    # Jalankan perintah ini pada Node tempat kubelet berjalan
    systemctl restart kubelet
    

Mengobservasi perilaku Pod statis

Ketika kubelet berjalan, secara otomatis akan menjalankan semua Pod statis yang terdefinisi. Ketika kamu mendefinisikan Pod statis dan menjalankan ulang kubelet, Pod statis yang baru akan dijalankan.

Kamu dapat melihat Container yang berjalan (termasuk Pod statis) dengan menjalankan (pada Node):

# Jalankan perintah ini pada Node tempat kubelet berjalan
crictl ps

Keluarannya kira-kira seperti berikut:

CONTAINER ID IMAGE         COMMAND  CREATED        STATUS         PORTS     NAMES
f6d05272b57e nginx:latest  "nginx"  8 minutes ago  Up 8 minutes             k8s_web.6f802af4_static-web-fk-node1_default_67e24ed9466ba55986d120c867395f3c_378e5f3c

Kamu dapat melihat Pod mirror tersebut pada API server:

kubectl get pods
NAME         READY   STATUS    RESTARTS        AGE
static-web   1/1     Running   0               2m

Label dari Pod statis akan dibuat juga pada Pod mirror. Kamu dapat menggunakan label tersebut seperti biasa menggunakan selector, atau yang lainnya.

Kamu dapat mencoba untuk menggunakan kubelet untuk menghapus Pod mirror tersebut pada API server, namun kubelet tidak akan menghapus Pod statis:

kubectl delete pod static-web
pod "static-web" deleted

Kamu akan melihat bahwa Pod tersebut tetap berjalan:

kubectl get pods
NAME         READY   STATUS    RESTARTS   AGE
static-web   1/1     Running   0          4s

Kembali ke Node tempat kubelet berjalan, kamu dapat mencoba menghentikan Container Docker secara manual. Kamu akan melihat, setelah beberapa saat, kubelet akan mengetahui dan akan menjalankan ulang Pod secara otomatis:

# Jalankan perintah ini pada Node tempat kubelet berjalan
crictl stop 129fd7d382018 # ganti dengan ID pada Container-mu
sleep 20
crictl ps
CONTAINER       IMAGE                                 CREATED           STATE      NAME    ATTEMPT    POD ID
89db4553e1eeb   docker.io/library/nginx@sha256:...    19 seconds ago    Running    web     1          34533c6729106

Penambahan dan pengurangan secara dinamis pada Pod statis

Direktori konfigurasi (/etc/kubelet.d pada contoh kita) akan dipindai secara berkala oleh kubelet untuk melakukan perubahan dan penambahan/pengurangan Pod sesuai dengan penambahan/pengurangan berkas pada direktori tersebut.

# Ini mengasumsikan kamu menggunakan konfigurasi Pod statis pada _filesystem_
# Jalankan perintah ini pada Node tempat kubelet berjalan
#
mv /etc/kubernetes/manifests/static-web.yaml /tmp
sleep 20
crictl ps
# Kamu mendapatkan bahwa tidak ada Container nginx yang berjalan
mv /tmp/static-web.yaml  /etc/kubernetes/manifests/
sleep 20
crictl ps
CONTAINER       IMAGE                                 CREATED           STATE      NAME    ATTEMPT    POD ID
f427638871c35   docker.io/library/nginx@sha256:...    19 seconds ago    Running    web     1          34533c6729106