This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Tugas

Bagian dokumentasi Kubernetes ini berisi halaman-halaman yang perlihatkan bagaimana melakukan setiap tugas (task). Halaman tugas menunjukkan cara melakukan satu hal saja, biasanya dengan memberikan urutan langkah pendek.

Antarmuka Pengguna Berbasis Web (Dashboard)

Melakukan deploy dan mengakses dashboard berbasis web untuk membantu kamu mengelola dan memantau aplikasi yang dimasukkan ke dalam container di Kubernetes.

Menggunakan Baris Perintah kubectl

Instalasi dan konfigurasi utilitas baris perintah kubectl yang digunakan untuk mengelola secara langsung klaster Kubernetes.

Mengkonfigurasi Pod dan Container

Melakukan tugas konfigurasi yang umum untuk Pod dan Container.

Menjalankan Aplikasi

Melakukan tugas manajemen aplikasi secara umum, seperti rolling updates, memasukkan informasi ke dalam Pod, dan penskalaan Pod secara horisontal.

Menjalankan Job

Menjalankan Job dengan menggunakan pemrosesan paralel.

Mengakses Aplikasi dalam Klaster

Mengkonfigurasi load balancing, port forwarding, atau membangun firewall atau konfigurasi DNS untuk mengakses aplikasi dalam sebuah klaster.

Monitoring, Logging, dan Debugging

Mengatur monitoring (pemantauan) dan logging (pencatatan) untuk memecahkan masalah klaster atau melakukan debug (pelacakan) aplikasi yang dikontainerisasi.

Mengakses API Kubernetes

Mempelajari berbagai metode untuk mengakses API Kubernetes secara langsung.

Menggunakan TLS

Mengkonfigurasi aplikasi kamu untuk percaya dan menggunakan klaster Certificate Authority (CA).

Mengelola Klaster

Mempelajari tugas umum untuk mengelola klaster.

Mengelola Aplikasi yang Stateful

Melakukan tugas umum untuk mengelola aplikasi yang Stateful, termasuk penskalaan, penghapusan, dan debugging StatefulSets.

Daemon Klaster

Melakukan tugas-tugas umum untuk mengelola DaemonSet, seperti melakukan rolling updates.

Mengelola GPU

Mengkonfigurasi dan menjadwalkan GPU NVIDIA untuk digunakan sebagai sumber daya oleh Node dalam sebuah klaster.

Mengelola HugePages

Mengkonfigurasi dan menjadwalkan HugePages sebagai sumber daya yang dapat dijadwalkan dalam sebuah klaster.

Selanjutnya

Jika kamu ingin menulis halaman tugas (task), silahkan lihat Membuat Dokumentasi Pull Request.

1 - Menginstal Peralatan

Peralatan untuk melakukan instalasi Kubernetes dalam komputer kamu.

kubectl

Perangkat baris perintah Kubernetes, kubectl, memungkinkan kamu untuk menjalankan perintah pada klaster Kubernetes. Kamu dapat menggunakan kubectl untuk menerapkan aplikasi, memeriksa dan mengelola sumber daya klaster, dan melihat log (catatan). Untuk informasi lebih lanjut termasuk daftar lengkap operasi kubectl, lihat referensi dokumentasi kubectl.

kubectl dapat diinstal pada berbagai platform Linux, macOS dan Windows. Pilihlah sistem operasi pilihan kamu di bawah ini.

kind

kind memberikan kamu kemampuan untuk menjalankan Kubernetes pada komputer lokal kamu. Perangkat ini membutuhkan Docker yang sudah diinstal dan terkonfigurasi.

Halaman Memulai Cepat kind memperlihatkan kepada kamu tentang apa yang perlu kamu lakukan untuk kind berjalan dan bekerja.

Melihat Memulai Cepat Kind

minikube

Seperti halnya dengan kind, minikube merupakan perangkat yang memungkinkan kamu untuk menjalankan Kubernetes secara lokal. minikube menjalankan sebuah klaster Kubernetes dengan satu node saja dalam komputer pribadi (termasuk Windows, macOS dan Linux) sehingga kamu dapat mencoba Kubernetes atau untuk pekerjaan pengembangan sehari-hari.

Kamu bisa mengikuti petunjuk resmi Memulai! minikube jika kamu ingin fokus agar perangkat ini terinstal.

Lihat Panduan Memulai! Minikube

Setelah kamu memiliki minikube yang bekerja, kamu bisa menggunakannya untuk menjalankan aplikasi contoh.

kubeadm

Kamu dapat menggunakan kubeadm untuk membuat dan mengatur klaster Kubernetes. kubeadm menjalankan langkah-langkah yang diperlukan untuk mendapatkan klaster dengan kelaikan dan keamanan minimum, aktif dan berjalan dengan cara yang mudah bagi pengguna.

Instalasi kubeadm memperlihatkan tentang bagaimana melakukan instalasi kubeadm. Setelah terinstal, kamu dapat menggunakannya untuk membuat klaster.

Lihat panduan instalasi kubeadm

1.1 - Menginstal dan Menyiapkan kubectl

Kubectl adalah alat baris perintah (command line tool) Kubernetes yang digunakan untuk menjalankan berbagai perintah untuk klaster Kubernetes. Kamu dapat menggunakan kubectl untuk men-deploy aplikasi, mengatur sumber daya klaster, dan melihat log. Daftar operasi kubectl dapat dilihat di Ikhtisar kubectl.

Sebelum kamu memulai

Kamu harus menggunakan kubectl dengan perbedaan maksimal satu versi minor dengan klaster kamu. Misalnya, klien v1.2 masih dapat digunakan dengan master v1.1, v1.2, dan 1.3. Menggunakan versi terbaru kubectl dapat menghindari permasalahan yang tidak terduga.

Menginstal kubectl pada Linux

Menginstal program kubectl menggunakan curl pada Linux

  1. Unduh versi terbarunya dengan perintah:

    curl -LO https://dl.k8s.io/release/`curl -LS https://dl.k8s.io/release/stable.txt`/bin/linux/amd64/kubectl
    

    Untuk mengunduh versi spesifik, ganti bagian curl -LS https://dl.k8s.io/release/stable.txt dengan versi yang diinginkan.

    Misalnya, untuk mengunduh versi 1.31.0 di Linux, ketik:

    curl -LO https://dl.k8s.io/release/v1.31.0/bin/linux/amd64/kubectl
    
  2. Jadikan program kubectl dapat dieksekusi.

    chmod +x ./kubectl
    
  3. Pindahkan ke PATH kamu.

    sudo mv ./kubectl /usr/local/bin/kubectl
    
  4. Pastikan instalasinya sudah berhasil dengan melakukan pengecekan versi:

    kubectl version --client
    

Menginstal dengan manajer paket (package manager) bawaan


sudo apt-get update && sudo apt-get install -y apt-transport-https gnupg2
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
yum install -y kubectl

Menginstal dengan manajer paket lain

Jika kamu menggunakan Ubuntu atau versi Linux lain yang mendukung manajer paket snap, kubectl tersedia dalam bentuk aplikasi di snap.

snap install kubectl --classic

kubectl version --client

Jika kamu menggunakan Linux dengan manajer paket Homebrew, kubectl sudah tersedia untuk diinstal di Homebrew.

brew install kubectl

kubectl version --client

Menginstal kubectl pada macOS

Menginstal program kubectl dengan curl pada macOS

  1. Unduh versi terbarunya dengan perintah:

    curl -LO "https://dl.k8s.io/release/$(curl -LS https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl"
    

    Untuk mengunduh versi spesifik, ganti bagian curl -LS https://dl.k8s.io/release/stable.txt dengan versi yang diinginkan.

    Misalnya, untuk mengunduh versi 1.31.0 pada macOS, ketik:

    curl -LO https://dl.k8s.io/release/v1.31.0/bin/darwin/amd64/kubectl
    
  2. Buat agar program kubectl dapat dijalankan.

    chmod +x ./kubectl
    
  3. Pindahkan ke PATH kamu.

    sudo mv ./kubectl /usr/local/bin/kubectl
    
  4. Pastikan instalasinya sudah berhasil dengan melakukan pengecekan versi:

    kubectl version --client
    

Menginstal dengan Homebrew pada macOS

Jika kamu menggunakan macOS dan manajer paket Homebrew, kamu dapat menginstal kubectl langsung dengan Homebrew.

  1. Jalankan perintah:

    brew install kubectl 
    

    atau

    brew install kubernetes-cli
    
  2. Pastikan instalasinya sudah berhasil dengan melakukan pengecekan versi:

    kubectl version --client
    

Menginstal dengan Macports pada macOS

Jika kamu menggunakan macOS dan manajer paket Macports, kamu dapat menginstal kubectl langsung dengan Macports.

  1. Jalankan perintah:

    sudo port selfupdate
    sudo port install kubectl
    
  2. Pastikan instalasinya sudah berhasil dengan melakukan pengecekan versi:

    kubectl version --client
    

Menginstal kubectl pada Windows

Menginstal program kubectl dengan curl pada Windows

  1. Unduh versi terbarunya 1.31.0 dari tautan ini.

    Atau jika sudah ada curl pada mesin kamu, jalankan perintah ini:

    curl -LO https://dl.k8s.io/release/v1.31.0/bin/windows/amd64/kubectl.exe
    

    Untuk mendapatkan versi stabil terakhir (misalnya untuk scripting), lihat di https://dl.k8s.io/release/stable.txt.

  2. Tambahkan program yang sudah diunduh tersebut ke PATH kamu.

  3. Pastikan instalasinya sudah berhasil dengan melakukan pengecekan versi:

    kubectl version --client
    

Menginstal dengan Powershell dari PSGallery

Jika kamu menggunakan Windows dan manajer paket Powershell Gallery, kamu dapat menginstal dan melakukan pembaruan kubectl dengan Powershell.

  1. Jalankan perintah berikut (jangan lupa untuk memasukkan DownloadLocation):

    Install-Script -Name install-kubectl -Scope CurrentUser -Force
    install-kubectl.ps1 [-DownloadLocation <path>]
    

    Penginstal akan membuat $HOME/.kube dan membuat berkas konfigurasi

  2. Pastikan instalasinya sudah berhasil dengan melakukan pengecekan versi:

    kubectl version --client
    

Menginstal pada Windows menggunakan Chocolatey atau Scoop

Untuk menginstal kubectl pada Windows, kamu dapat menggunakan manajer paket Chocolatey atau penginstal baris perintah Scoop.

choco install kubernetes-cli

scoop install kubectl

  1. Pastikan instalasinya sudah berhasil dengan melakukan pengecekan versi:

    kubectl version --client
    
  2. Pindah ke direktori utama:

    cd %USERPROFILE%
    
  3. Buat direktori .kube:

    mkdir .kube
    
  4. Pindah ke direktori .kube yang baru saja dibuat:

    cd .kube
    
  5. Lakukan konfigurasi kubectl untuk menggunakan klaster Kubernetes remote:

    New-Item config -type file
    

Mengunduh sebagai bagian dari Google Cloud SDK

Kamu dapat menginstal kubectl sebagai bagian dari Google Cloud SDK.

  1. Instal Google Cloud SDK.

  2. Jalankan perintah instalasi kubectl:

    gcloud components install kubectl
    
  3. Pastikan instalasinya sudah berhasil dengan melakukan pengecekan versi:

    kubectl version --client
    

Memeriksa konfigurasi kubectl

Agar kubectl dapat mengakses klaster Kubernetes, dibutuhkan sebuah berkas kubeconfig, yang akan otomatis dibuat ketika kamu membuat klaster baru menggunakan kube-up.sh atau setelah berhasil men-deploy klaster Minikube. Secara bawaan, konfigurasi kubectl disimpan di ~/.kube/config.

Kamu dapat memeriksa apakah konfigurasi kubectl sudah benar dengan mengambil keadaan klaster:

kubectl cluster-info

Jika kamu melihat respons berupa URL, maka konfigurasi klaster kubectl sudah benar.

Tetapi, jika kamu melihat pesan seperti di bawah, maka kubectl belum dikonfigurasi dengan benar atau tidak dapat terhubung ke klaster Kubernetes.

The connection to the server <server-name:port> was refused - did you specify the right host or port?

Selanjutnya, jika kamu ingin menjalankan klaster Kubernetes di laptop (lokal) kamu, kamu memerlukan sebuah perangkat seperti Minikube sebelum menjalankan ulang perintah yang ada di atas.

Jika kubectl cluster-info mengembalikan respons URL tetapi kamu masih belum dapat mengakses klaster, kamu bisa menggunakan perintah di bawah untuk memeriksa apakah klaster sudah dikonfigurasi dengan benar.

kubectl cluster-info dump

Konfigurasi kubectl opsional

Menyalakan penyelesaian otomatis untuk terminal

kubectl menyediakan fitur penyelesaian otomatis (auto complete) untuk Bash dan Zsh yang dapat memudahkanmu ketika mengetik di terminal.

Ikuti petunjuk di bawah untuk menyalakan penyelesaian otomatis untuk Bash dan Zsh.

Pendahuluan

Skrip penyelesaian (completion script) kubectl untuk Bash dapat dibuat dengan perintah kubectl completion bash. Masukkan skrip tersebut ke dalam terminal sebagai sumber untuk menyalakan penyelesaian otomatis dari kubectl.

Namun, skrip penyelesaian tersebut bergantung pada bash-completion, yang artinya kamu harus menginstal program tersebut terlebih dahulu (kamu dapat memeriksa apakah kamu sudah memiliki bash-completion dengan menjalankan perintah type _init_completion).

Menginstal bash-completion

bash-completion disediakan oleh banyak manajer paket (lihat di sini). Kamu dapat menginstalnya dengan menggunakan perintah apt-get install bash-completion atau yum install bash-completion, dsb.

Perintah di atas akan membuat skrip utama bash-completion di /usr/share/bash-completion/bash_completion. Terkadang kamu juga harus menambahkan skrip tersebut ke dalam berkas ~/.bashrc, tergantung manajer paket yang kamu pakai.

Untuk memastikannya, muat ulang terminalmu dan jalankan type _init_completion. Jika perintah tersebut berhasil, maka instalasi selesai. Jika tidak, tambahkan teks berikut ke dalam berkas ~/.bashrc:

source /usr/share/bash-completion/bash_completion

Muat ulang terminalmu dan pastikan bash-completion sudah berhasil diinstal dengan menjalankan type _init_completion.

Menyalakan penyelesaian otomatis kubectl

Sekarang kamu harus memastikan bahwa skrip penyelesaian untuk kubectl sudah dimasukkan sebagai sumber penyelesaian otomatis pada semua sesi terminal. Kamu dapat melakukannya dengan dua cara:

  • Masukkan skrip penyelesaian sebagai sumber di berkas ~/.bashrc:

    echo 'source <(kubectl completion bash)' >>~/.bashrc
    
  • Tambahkan skrip penyelesaian ke direktori /etc/bash_completion.d:

    kubectl completion bash >/etc/bash_completion.d/kubectl
    

Jika kamu menggunakan alias untuk kubectl, kamu masih dapat menggunakan fitur penyelesaian otomatis dengan menjalankan perintah:

```shell
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -F __start_kubectl k' >>~/.bashrc
```

Kedua cara tersebut sama, kamu bisa memilih salah satunya. Setelah memuat ulang terminal, penyelesaian otomatis dari kubectl seharusnya sudah dapat bekerja.

Pendahuluan

Skrip penyelesaian (completion script) kubectl untuk Bash dapat dibuat dengan perintah kubectl completion bash. Masukkan skrip tersebut ke dalam terminal sebagai sumber untuk menyalakan penyelesaian otomatis dari kubectl.

Namun, skrip penyelesaian tersebut bergantung pada bash-completion, yang artinya kamu harus menginstal program tersebut terlebih dahulu.

Pemutakhiran Bash

Panduan di bawah berasumsi kamu menggunakan Bash 4.1+. Kamu dapat memeriksa versi Bash dengan menjalankan:

echo $BASH_VERSION

Jika versinya sudah terlalu usang, kamu dapat menginstal/memutakhirkannya dengan menggunakan Homebrew:

brew install bash

Muat ulang terminalmu dan pastikan versi yang diharapkan sudah dipakai:

echo $BASH_VERSION $SHELL

Homebrew biasanya akan menginstalnya di /usr/local/bin/bash.

Menginstal bash-completion

Kamu dapat memeriksa apakah kamu sudah memiliki bash-completion v2 dengan perintah type _init_completion. Jika belum, kamu dapat menginstalnya dengan menggunakan Homebrew:

brew install bash-completion@2

Seperti yang disarankan pada keluaran perintah di atas, tambahkan teks berikut ke berkas ~/.bashrc:

export BASH_COMPLETION_COMPAT_DIR="/usr/local/etc/bash_completion.d"
[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"

Muat ulang terminalmu dan pastikan bash-completion v2 sudah terinstal dengan perintah type _init_completion.

Menyalakan penyelesaian otomatis kubectl

Sekarang kamu harus memastikan bahwa skrip penyelesaian untuk kubectl sudah dimasukkan sebagai sumber penyelesaian otomatis di semua sesi terminal. Kamu dapat melakukannya dengan beberapa cara:

  • Masukkan skrip penyelesaian sebagai sumber di berkas ~/.bashrc:

    echo 'source <(kubectl completion bash)' >>~/.bashrc
    
  • Menambahkan skrip penyelesaian ke direktori /etc/bash_completion.d:

    kubectl completion bash >/etc/bash_completion.d/kubectl
    
  • Jika kamu menggunakan alias untuk kubectl, kamu masih dapat menggunakan fitur penyelesaian otomatis dengan menjalankan perintah:

    echo 'alias k=kubectl' >>~/.bashrc
    echo 'complete -F __start_kubectl k' >>~/.bashrc
    
  • Jika kamu menginstal kubectl dengan Homebrew (seperti yang sudah dijelaskan di atas), maka skrip penyelesaian untuk kubectl sudah berada di /usr/local/etc/bash_completion.d/kubectl. Kamu tidak perlu melakukan apa-apa lagi.

Setelah memuat ulang terminal, penyelesaian otomatis dari kubectl seharusnya sudah dapat bekerja.

Skrip penyelesaian (completion script) kubectl untuk Zsh dapat dibuat dengan perintah kubectl completion zsh. Masukkan skrip tersebut ke dalam terminal sebagai sumber untuk menyalakan penyelesaian otomatis dari kubectl.

Tambahkan baris berikut di berkas ~/.zshrc untuk menyalakan penyelesaian otomatis dari kubectl:

source <(kubectl completion zsh)

Jika kamu menggunakan alias untuk kubectl, kamu masih dapat menggunakan fitur penyelesaian otomatis dengan menjalankan perintah:

echo 'alias k=kubectl' >>~/.zshrc
echo 'compdef __start_kubectl k' >>~/.zshrc

Setelah memuat ulang terminal, penyelesaian otomatis dari kubectl seharusnya sudah dapat bekerja.

Jika kamu mendapatkan pesan gagal seperti complete:13: command not found: compdef, maka tambahkan teks berikut ke awal berkas ~/.zshrc:

autoload -Uz compinit
compinit

Selanjutnya

2 - Menjalankan Tugas-Tugas Otomatis dengan CronJob

Kamu dapat menggunakan CronJob untuk menjalankan Job yang dijadwalkan berbasis waktu. Job akan berjalan seperti pekerjaan-pekerjaan Cron di Linux atau sistem UNIX.

CronJob sangat berguna untuk membuat pekerjaan yang berjalan secara periodik dan berulang, misalnya menjalankan (backup) atau mengirim email. CronJob juga dapat menjalankan pekerjaan individu pada waktu tertentu, misalnya jika kamu ingin menjadwalkan sebuah pekerjaan dengan periode aktivitas yang rendah.

CronJob memiliki keterbatasan dan kekhasan. Misalnya, dalam keadaan tertentu, sebuah CronJob dapat membuat banyak Job. Karena itu, Job haruslah idempotent.

Untuk informasi lanjut mengenai keterbatasan, lihat CronJob.

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:

Membuat Sebuah CronJob

CronJob membutuhkan sebuah berkas konfigurasi. Ini adalah contoh dari berkas konfigurasi CronJob .spec yang akan mencetak waktu sekarang dan pesan "hello" setiap menit:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            command:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

Jalankan contoh CronJob menggunakan perintah berikut:

kubectl create -f https://k8s.io/examples/application/job/cronjob.yaml

Keluaran akan mirip dengan ini:

cronjob.batch/hello created

Kamu juga dapat menggunakan kubectl run untuk membuat sebuah CronJob tanpa menulis sebuah konfigurasi yang lengkap:

kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster"

Setelah membuat sebuah CronJob, untuk mengecek statusnya kamu dapat menggunakan perintah berikut:

kubectl get cronjob hello

Keluaran akan mirip dengan ini:

NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
hello   */1 * * * *   False     0        <none>          10s

Seperti yang kamu lihat dari hasil perintah di atas, CronJob belum menjadwalkan atau menjalankan pekerjaan apa pun. Waktu yang biasanya dibutuhkan untuk mengamati Job hingga Job tersebut dibuat akan membutuhkan sekitar satu menit:

kubectl get jobs --watch

Keluaran akan mirip dengan ini:

NAME               COMPLETIONS   DURATION   AGE
hello-4111706356   0/1                      0s
hello-4111706356   0/1           0s         0s
hello-4111706356   1/1           5s         5s

Sekarang kamu telah melihat satu Job berjalan yang dijadwalkan oleh "hello" CronJob. Kamu dapat berhenti mengamati Job dan melihat CronJob lagi untuk melihat CronJob menjadwalkan sebuah Job:

kubectl get cronjob hello

Keluaran akan mirip dengan ini:

NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
hello   */1 * * * *   False     0        50s             75s

Kamu dapat melihat bahwa CronJob hello berhasil menjadwalkan sebuah Job pada waktu yang ditentukan dalam LAST SCHEDULE. Saat ini ada 0 Job yang aktif, berarti sebuah Job telah selesai atau gagal.

Sekarang, temukan Pod yang dibuat oleh jadwal Job terakhir dan melihat keluaran bawaan dari salah satu Pod.

# Ganti "hello-4111706356" dengan nama Job di sistem kamu
pods=$(kubectl get pods --selector=job-name=hello-4111706356 --output=jsonpath={.items[*].metadata.name})

Menampilkan log sebuah Pod:

kubectl logs $pods

Keluaran akan mirip dengan ini:

Fri Feb 22 11:02:09 UTC 2019
Hello from the Kubernetes cluster

Menghapus sebuah CronJob

Ketika kamu tidak membutuhkan sebuah CronJob lagi, kamu dapat megnhapusnya dengan perintah kubectl delete cronjob <cronjob name>:

kubectl delete cronjob hello

Menghapus CronJob akan menghapus semua Job dan Pod yang telah terbuat dan menghentikanya dari pembuatan Job tambahan. Kamu dapat membaca lebih lanjut tentang menghapus Job di garbage collection.

Seperti semua konfigurasi Kubernetes, sebuah CronJob membutuhkan field apiVersion, kind, dan metadata. Untuk informasi umum tentang bekerja dengan berkas konfigurasi, lihat dokumentasi men-deploy aplikasi, dan mengunakan kubectl untuk manajemen sumber daya.

Sebuah konfigurasi CronJob juga membutuhkan sebuah bagian .spec.

Penjadwalan

.spec.schedule adalah field yang wajib diisi dari sebuah .spec Dibutuhkan sebuah format string Cron, misalnya 0 * * * * atau @hourly, sebagai jadwal Job untuk dibuat dan dieksekusi.

Format ini juga mencakup nilai langkah "Vixie cron". Seperti penjelasan di FreeBSD manual:

Nilai langkah dapat digunakan bersama dengan rentang. Sebuah rentang diikuti dengan /<number> menentukan lompatan angka melalui rentang. Misalnya, 0-23/2 dapat digunakan dalam jam untuk menentukan perintah akan dieksekusi setiap jam (alternatif dalam bawaan v7 adalah 0,2,4,6,8,10,12,14,16,18,20,22). Langkah-langkah juga diizinkan setelah tanda bintang, jadi jika kamu menginginkan "setiap dua jam", gunakan saja */2.

Templat Job

.spec.JobTemplate adalah templat untuk sebuah Job, dan itu wajib. Templat Job memiliki skema yang sama dengan Job, kecuali jika bersarang dan tidak memiliki sebuah apiVersion atau kind. Untuk informasi lebih lanjut tentang menulis sebuah Job .spec lihat Menulis spesifikasi Job.

Starting Deadline

Field .spec.startingDeadlineSeconds adalah field opsional. Field tersebut berarti batas waktu dalam satuan detik untuk memulai sebuah Job jika Job melewatkan waktu yang telah dijadwalkan karena alasan apapun. Setelah mencapai batas waktu, CronJob tidak akan memulai sebuah Job. Job yang tidak memenuhi batas waktu, dengan cara ini dianggap sebagai Job yang gagal. Jika field ini tidak ditentukan, maka Job tidak memiliki batas waktu.

Controller CronJob menghitung berapa banyak jadwal yang terlewat untuk sebuah CronJob. jika lebih dari 100 jadwal yang terlewat, maka tidak ada lagi CronJob yang akan dijadwalkan. Ketika .spec.startingDeadlineSeconds tidak disetel, CronJob Controller menghitung jadwal yang terlewat dari status.lastScheduleTime hingga sekarang.

Misalnya, sebuah CronJob seharusnya berjalan setiap menit, status.lastScheduleTime CronJob adalah pukul 5:00am, tetapi sekarang pukul 07:00am. Itu berarti ada 120 jadwal yang terlewat, maka tidak ada lagi CronJob yang akan dijadwalkan.

Jika field .spec.startingDeadlineSeconds disetel (tidak kosong), CronJob Controller akah menghitung berapa banyak Job yang terlewat dari nilai .spec.startingDeadlineSeconds hingga sekarang.

Misalnya, jika disetel ke 200, CronJob Controller akan menghitung jadwal yang terlewat dalam 200 detik terakhir. Pada kasus ini, jika terdapat lebih dari 100 jadwal yang terlewat dalam 200 detik terakhir, maka tidak ada lagi CronJob yang akan dijadwalkan.

Kebijakan Concurrency

Field .spec.concurrencyPolicy juga opsional. Field tersebut menentukan bagaimana memperlakukan eksekusi concurrent dari sebuah Job yang dibuat oleh CronJob. Kamu dapat menetapkan hanya satu dari kebijakan concurrency:

  • Allow (bawaan): CronJob mengizinkan Job berjalan secara concurrent
  • Forbid : Job tidak mengizinkan Job berjalan secara concurrent; jika sudah saatnya untuk menjalankan Job baru dan Job sebelumnya belum selesai, maka CronJob akan melewatkan Job baru yang akan berjalan
  • Replace: Jika sudah saatnya untuk menjalankan Job baru dan Job sebelumnya belum selesai, maka CronJob akan mengganti Job yang sedang berjalan dengan Job baru.

Perhatikan bahwa kebijakan concurrency hanya berlaku untuk Job yang dibuat dengan CronJob yang sama. Jika terdapat banyak CronJob, Job akan selalu diizinkan untuk berjalan secara concurrent.

Penangguhan

Field .spec.suspend juga opsional. Jika field tersebut disetel true, semua eksekusi selanjutnya akan ditangguhkan. Konfigurasi ini tidak dapat berlaku untuk eksekusi yang sudah dimulai. Secara bawaan false.

Batas Riwayat Pekerjaan

Field .spec.successfulJobsHistoryLimit dan .spec.failedJobsHistoryLimit juga opsional. Field tersebut menentukan berapa banyak Job yang sudah selesai dan gagal yang harus disimpan. Secara bawaan, masing-masing field tersebut disetel 3 dan 1. Mensetel batas ke 0 untuk menjaga tidak ada Job yang sesuai setelah Job tersebut selesai.

3 - Mengatur Pod dan Kontainer

3.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

3.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.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.

3.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

3.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

3.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:

3.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

3.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:

3.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.

3.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

3.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.

3.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

4 - Mengelola Sebuah Klaster

Pelajari tugas-tugas umum dalam pengelolaan sebuah klaster.

4.1 - Menggunakan Calico untuk NetworkPolicy

Laman ini menunjukkan beberapa cara cepat untuk membuat klaster Calico pada Kubernetes.

Sebelum kamu memulai

Putuskan apakah kamu ingin menggelar (deploy) sebuah klaster di cloud atau di lokal.

Membuat klaster Calico dengan menggunakan Google Kubernetes Engine (GKE)

Prasyarat: gcloud.

  1. Untuk meluncurkan klaster GKE dengan Calico, cukup sertakan opsi --enable-network-policy.

    Sintaksis

    gcloud container clusters create [CLUSTER_NAME] --enable-network-policy
    

    Contoh

    gcloud container clusters create my-calico-cluster --enable-network-policy
    
  2. Untuk memverifikasi penggelaran, gunakanlah perintah berikut ini.

    kubectl get pods --namespace=kube-system
    

    Pod Calico dimulai dengan kata calico. Periksa untuk memastikan bahwa statusnya Running.

Membuat klaster lokal Calico dengan kubeadm

Untuk membuat satu klaster Calico dengan hos tunggal dalam waktu lima belas menit dengan menggunakan kubeadm, silakan merujuk pada

Memulai cepat Calico.

Selanjutnya

Setelah klaster kamu berjalan, kamu dapat mengikuti Mendeklarasikan Kebijakan Jaringan untuk mencoba NetworkPolicy Kubernetes.

4.2 - Mengelola Memori, CPU, dan Sumber Daya API

4.2.1 - Mengatur Batas Minimum dan Maksimum Memori pada sebuah Namespace

Laman ini menunjukkan cara untuk mengatur nilai minimum dan maksimum memori yang digunakan oleh Container yang berjalan pada sebuah Namespace. Kamu dapat menentukan nilai minimum dan maksimum memori pada objek LimitRange. Jika sebuah Pod tidak memenuhi batasan yang ditentukan oleh LimitRange, maka Pod tersebut tidak dapat dibuat pada Namespace tersebut.

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.

Tiap Node dalam klastermu harus memiliki setidaknya 1 GiB memori.

Membuat sebuah Namespace

Buat sebuah Namespace sehingga sumber daya yang kamu buat pada latihan ini terisolasi dari komponen lain pada klastermu.

kubectl create namespace constraints-mem-example

Membuat LimitRange dan Pod

Berikut berkas konfigurasi untuk sebuah LimitRange:

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-min-max-demo-lr
spec:
  limits:
  - max:
      memory: 1Gi
    min:
      memory: 500Mi
    type: Container

Membuat LimitRange:

kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints.yaml --namespace=constraints-mem-example

Melihat informasi mendetail mengenai LimitRange:

kubectl get limitrange mem-min-max-demo-lr --namespace=constraints-mem-example --output=yaml

Keluaran yang dihasilkan menunjukkan batasan minimum dan maksimum dari memori seperti yang diharapkan. Tetapi perhatikan hal berikut, meskipun kamu tidak menentukan nilai bawaan pada berkas konfigurasi untuk LimitRange, namun nilai tersebut akan dibuat secara otomatis.

  limits:
  - default:
      memory: 1Gi
    defaultRequest:
      memory: 1Gi
    max:
      memory: 1Gi
    min:
      memory: 500Mi
    type: Container

Mulai sekarang setiap Container yang dibuat pada Namespace constraints-mem-example, Kubernetes akan menjalankan langkah-langkah berikut:

  • Jika Container tersebut tidak menentukan permintaan dan limit memori, maka diberikan nilai permintaan dan limit memori bawaan pada Container.

  • Memastikan Container memiliki permintaan memori yang lebih besar atau sama dengan 500 MiB.

  • Memastikan Container memiliki limit memori yang lebih kecil atau kurang dari 1 GiB.

Berikut berkas konfigurasi Pod yang memiliki satu Container. Manifes Container menentukan permintaan memori 600 MiB dan limit memori 800 MiB. Nilai tersebut memenuhi batasan minimum dan maksimum memori yang ditentukan oleh LimitRange.

apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo
spec:
  containers:
  - name: constraints-mem-demo-ctr
    image: nginx
    resources:
      limits:
        memory: "800Mi"
      requests:
        memory: "600Mi"

Membuat Pod:

kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod.yaml --namespace=constraints-mem-example

Memastikan Container pada Pod sudah berjalan:

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

Melihat informasi mendetail tentang Pod:

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

Keluaran yang dihasilkan menunjukkan Container memiliki permintaan memori 600 MiB dan limit memori 800 MiB. Nilai tersebut memenuhi batasan yang ditentukan oleh LimitRange.

resources:
  limits:
     memory: 800Mi
  requests:
    memory: 600Mi

Menghapus Podmu:

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

Mencoba membuat Pod yang melebihi batasan maksimum memori

Berikut berkas konfigurasi untuk sebuah Pod yang memiliki satu Container. Container tersebut menentukan permintaan memori 800 MiB dan batas memori 1.5 GiB.

apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo-2
spec:
  containers:
  - name: constraints-mem-demo-2-ctr
    image: nginx
    resources:
      limits:
        memory: "1.5Gi"
      requests:
        memory: "800Mi"

Mencoba membuat Pod:

kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-2.yaml --namespace=constraints-mem-example

Keluaran yang dihasilkan menunjukkan Pod tidak dibuat, karena Container menentukan limit memori yang terlalu besar:

Error from server (Forbidden): error when creating "examples/admin/resource/memory-constraints-pod-2.yaml":
pods "constraints-mem-demo-2" is forbidden: maximum memory usage per Container is 1Gi, but limit is 1536Mi.

Mencoba membuat Pod yang tidak memenuhi permintaan memori

Berikut berkas konfigurasi untuk sebuah Pod yang memiliki satu Container. Container tersebut menentukan permintaan memori 100 MiB dan limit memori 800 MiB.

apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo-3
spec:
  containers:
  - name: constraints-mem-demo-3-ctr
    image: nginx
    resources:
      limits:
        memory: "800Mi"
      requests:
        memory: "100Mi"

Mencoba membuat Pod:

kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-3.yaml --namespace=constraints-mem-example

Keluaran yang dihasilkan menunjukkan Pod tidak dibuat, karena Container menentukan permintaan memori yang terlalu kecil:

Error from server (Forbidden): error when creating "examples/admin/resource/memory-constraints-pod-3.yaml":
pods "constraints-mem-demo-3" is forbidden: minimum memory usage per Container is 500Mi, but request is 100Mi.

Membuat Pod yang tidak menentukan permintaan ataupun limit memori

Berikut berkas konfigurasi untuk sebuah Pod yang memiliki satu Container. Container tersebut tidak menentukan permintaan memori dan juga limit memori.

apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo-4
spec:
  containers:
  - name: constraints-mem-demo-4-ctr
    image: nginx

Mencoba membuat Pod:

kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-4.yaml --namespace=constraints-mem-example

Melihat informasi mendetail tentang Pod:

kubectl get pod constraints-mem-demo-4 --namespace=constraints-mem-example --output=yaml

Keluaran yang dihasilkan menunjukkan Container pada Pod memiliki permintaan memori 1 GiB dan limit memori 1 GiB. Bagaimana Container mendapatkan nilai tersebut?

resources:
  limits:
    memory: 1Gi
  requests:
    memory: 1Gi

Karena Containermu tidak menentukan permintaan dan limit memori, Container tersebut diberikan permintaan dan limit memori bawaan dari LimitRange.

Pada tahap ini, Containermu mungkin saja berjalan ataupun mungkin juga tidak berjalan. Ingat bahwa prasyarat untuk tugas ini adalah Node harus memiliki setidaknya 1 GiB memori. Jika tiap Node hanya memiliki 1 GiB memori, maka tidak akan ada cukup memori untuk dialokasikan pada setiap Node untuk memenuhi permintaan 1 GiB memori. Jika ternyata kamu menggunakan Node dengan 2 GiB memori, maka kamu mungkin memiliki cukup ruang untuk memenuhi permintaan 1 GiB tersebut.

Menghapus Pod:

kubectl delete pod constraints-mem-demo-4 --namespace=constraints-mem-example

Pelaksanaan batasan minimum dan maksimum memori

Batasan maksimum dan minimum memori yang yang ditetapkan pada sebuah Namespace oleh LimitRange dilaksanakan hanya ketika Pod dibuat atau diperbarui. Jika kamu mengubah LimitRange, hal tersebut tidak akan memengaruhi Pods yang telah dibuat sebelumnya.

Motivasi untuk batasan minimum dan maksimum memori

Sebagai seorang administrator klaster, kamu mungkin ingin menetapkan pembatasan jumlah memori yang dapat digunakan oleh Pod. Sebagai contoh:

  • Tiap Node dalam sebuah klaster memiliki 2 GB memori. Kamu tidak ingin menerima Pod yang meminta lebih dari 2 GB memori, karena tidak ada Node pada klater yang dapat memenuhi permintaan tersebut.

  • Sebuah klaster digunakan bersama pada departemen produksi dan pengembangan. Kamu ingin mengizinkan beban kerja (workload) pada produksi untuk menggunakan hingga 8 GB memori, tapi kamu ingin beban kerja pada pengembangan cukup terbatas sampai dengan 512 MB saja. Kamu membuat Namespace terpisah untuk produksi dan pengembangan, dan kamu menerapkan batasan memori pada tiap Namespace.

Bersih-bersih

Menghapus Namespace:

kubectl delete namespace constraints-mem-example

Selanjutnya

Untuk administrator klaster

Untuk pengembang aplikasi

4.3 - Debugging Resolusi DNS

Laman ini menyediakan beberapa petunjuk untuk mendiagnosis masalah DNS.

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:


Klaster kamu harus dikonfigurasi untuk menggunakan addon CoreDNS atau pendahulunya, kube-dns.

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

Membuat Pod sederhana yang digunakan sebagai lingkungan pengujian

apiVersion: v1
kind: Pod
metadata:
  name: dnsutils
  namespace: default
spec:
  containers:
  - name: dnsutils
    image: registry.k8s.io/e2e-test-images/agnhost:2.39
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

Gunakan manifes berikut untuk membuat sebuah Pod:

kubectl apply -f https://k8s.io/examples/admin/dns/dnsutils.yaml
pod/dnsutils created

…dan verifikasi statusnya:

kubectl get pods dnsutils
NAME      READY     STATUS    RESTARTS   AGE
dnsutils   1/1       Running   0          <some-time>

Setelah Pod tersebut berjalan, kamu dapat menjalankan perintah nslookup di lingkungan tersebut. Jika kamu melihat hal seperti ini, maka DNS sudah berjalan dengan benar.

kubectl exec -i -t dnsutils -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      kubernetes.default
Address 1: 10.0.0.1

Jika perintah nslookup gagal, periksa hal berikut:

Periksa konfigurasi DNS lokal terlebih dahulu

Periksa isi dari berkas resolv.conf. (Lihat Inheriting DNS dari node dan Isu-isu yang dikenal di bawah ini untuk informasi lebih lanjut)

kubectl exec -ti dnsutils -- cat /etc/resolv.conf

Verifikasi path pencarian dan nama server telah dibuat agar tampil seperti di bawah ini (perlu diperhatikan bahwa path pencarian dapat berbeda tergantung dari penyedia layanan cloud):

search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.gce_project_id.internal
nameserver 10.0.0.10
options ndots:5

Kesalahan yang muncul berikut ini mengindikasikan terdapat masalah dengan add-on CoreDNS (atau kube-dns) atau Service terkait:

kubectl exec -i -t dnsutils -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10

nslookup: can't resolve 'kubernetes.default'

atau

kubectl exec -i -t dnsutils -- nslookup kubernetes.default
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

nslookup: can't resolve 'kubernetes.default'

Periksa apakah Pod DNS sedang berjalan

Gunakan perintah kubectl get pods untuk memverifikasi apakah Pod DNS sedang berjalan.

kubectl get pods --namespace=kube-system -l k8s-app=kube-dns
NAME                       READY     STATUS    RESTARTS   AGE
...
coredns-7b96bf9f76-5hsxb   1/1       Running   0           1h
coredns-7b96bf9f76-mvmmt   1/1       Running   0           1h
...

Jika kamu melihat tidak ada Pod CoreDNS yang sedang berjalan atau Pod tersebut gagal/telah selesai, add-on DNS mungkin tidak dijalankan (deployed) secara bawaan di lingkunganmu saat ini dan kamu harus menjalankannya secara manual.

Periksa kesalahan pada Pod DNS

Gunakan perintah kubectl logs untuk melihat log dari Container DNS.

Untuk CoreDNS:

kubectl logs --namespace=kube-system -l k8s-app=kube-dns

Berikut contoh log dari CoreDNS yang sehat (healthy):

.:53
2018/08/15 14:37:17 [INFO] CoreDNS-1.2.2
2018/08/15 14:37:17 [INFO] linux/amd64, go1.10.3, 2e322f6
CoreDNS-1.2.2
linux/amd64, go1.10.3, 2e322f6
2018/08/15 14:37:17 [INFO] plugin/reload: Running configuration MD5 = 24e6c59e83ce706f07bcc82c31b1ea1c

Periksa jika ada pesan mencurigakan atau tidak terduga dalam log.

Apakah layanan DNS berjalan?

Verifikasi apakah layanan DNS berjalan dengan menggunakan perintah kubectl get service.

kubectl get svc --namespace=kube-system
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
...
kube-dns     ClusterIP   10.0.0.10      <none>        53/UDP,53/TCP        1h
...

Jika kamu telah membuat Service atau seharusnya Service telah dibuat secara bawaan namun ternyata tidak muncul, lihat debugging Service untuk informasi lebih lanjut.

Apakah endpoint DNS telah ekspos?

Kamu dapat memverifikasikan apakah endpoint DNS telah diekspos dengan menggunakan perintah kubectl get endpoints.

kubectl get endpoints kube-dns --namespace=kube-system
NAME       ENDPOINTS                       AGE
kube-dns   10.180.3.17:53,10.180.3.17:53    1h

Jika kamu tidak melihat endpoint, lihat bagian endpoint pada dokumentasi debugging Service.

Untuk tambahan contoh Kubernetes DNS, lihat contoh cluster-dns pada repositori Kubernetes GitHub.

Apakah kueri DNS diterima/diproses?

Kamu dapat memverifikasi apakah kueri telah diterima oleh CoreDNS dengan menambahkan plugin log pada konfigurasi CoreDNS (alias Corefile). CoreDNS Corefile disimpan pada ConfigMap dengan nama coredns. Untuk mengeditnya, gunakan perintah:

kubectl -n kube-system edit configmap coredns

Lalu tambahkan log pada bagian Corefile seperti contoh berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        log
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          upstream
          fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        proxy . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }    

Setelah perubahan disimpan, perubahan dapat memakan waktu satu hingga dua menit untuk Kubernetes menyebarkan perubahan ini pada Pod CoreDNS.

Berikutnya, coba buat beberapa kueri dan lihat log pada bagian atas dari dokumen ini. Jika pod CoreDNS menerima kueri, kamu seharusnya akan melihatnya pada log.

Berikut ini contoh kueri yang terdapat di dalam log:

.:53
2018/08/15 14:37:15 [INFO] CoreDNS-1.2.0
2018/08/15 14:37:15 [INFO] linux/amd64, go1.10.3, 2e322f6
CoreDNS-1.2.0
linux/amd64, go1.10.3, 2e322f6
2018/09/07 15:29:04 [INFO] plugin/reload: Running configuration MD5 = 162475cdf272d8aa601e6fe67a6ad42f
2018/09/07 15:29:04 [INFO] Reloading complete
172.17.0.18:41675 - [07/Sep/2018:15:29:11 +0000] 59925 "A IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR qr,aa,rd,ra 106 0.000066649s

Isu-isu yang Dikenal

Beberapa distribusi Linux (contoh Ubuntu) menggunakan resolver DNS lokal secara bawaan (systemd-resolved). Systemd-resolved memindahkan dan mengganti /etc/resolv.conf dengan berkas stub yang dapat menyebabkan forwarding loop yang fatal saat meresolusi nama pada server upstream. Ini dapat diatasi secara manual dengan menggunakan flag kubelet --resolv-conf untuk mengarahkan ke resolv.conf yang benar (Pada systemd-resolved, ini berada di /run/systemd/resolve/resolv.conf). kubeadm akan otomatis mendeteksi systemd-resolved, dan menyesuaikan flag kubelet sebagai mana mestinya.

Pemasangan Kubernetes tidak menggunakan berkas resolv.conf pada node untuk digunakan sebagai klaster DNS secara default, karena proses ini umumnya spesifik pada distribusi tertentu. Hal ini bisa jadi akan diimplementasi nantinya.

Libc Linux (alias glibc) secara bawaan memiliki batasan nameserver DNS sebanyak 3 rekaman (records). Selain itu, pada glibc versi yang lebih lama dari glibc-2.17-222 (versi terbaru lihat isu ini), jumlah rekaman DNS search dibatasi sejumlah 6 (lihat masalah sejak 2005 ini). Kubernetes membutuhkan 1 rekaman nameserver dan 3 rekaman search. Ini berarti jika instalasi lokal telah menggunakan 3 nameserver atau menggunakan lebih dari 3 search,sementara versi glibc kamu termasuk yang terkena dampak, beberapa dari pengaturan tersebut akan hilang. Untuk menyiasati batasan rekaman DNS nameserver, node dapat menjalankan dnsmasq,yang akan menyediakan nameserver lebih banyak. Kamu juga dapat menggunakan kubelet --resolv-conf flag. Untuk menyiasati batasan rekaman search, pertimbangkan untuk memperbarui distribusi linux kamu atau memperbarui glibc ke versi yang tidak terdampak.

Jika kamu menggunakan Alpine versi 3.3 atau lebih lama sebagai dasar image kamu, DNS mungkin tidak dapat bekerja dengan benar disebabkan masalah dengan Alpine. Masalah 30215 Kubernetes menyediakan informasi lebih detil tentang ini.

Selanjutnya

4.4 - Kustomisasi Service DNS

Laman ini menjelaskan cara mengonfigurasi DNS Pod kamu dan menyesuaikan proses resolusi DNS pada klaster kamu.

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:

Klaster kamu harus menjalankan tambahan (add-on) CoreDNS terlebih dahulu. Migrasi ke CoreDNS menjelaskan tentang bagaimana menggunakan kubeadm untuk melakukan migrasi dari kube-dns.

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

Pengenalan

DNS adalah Service bawaan dalam Kubernetes yang diluncurkan secara otomatis melalui addon manager add-on klaster.

Sejak Kubernetes v1.12, CoreDNS adalah server DNS yang direkomendasikan untuk menggantikan kube-dns. Jika klaster kamu sebelumnya menggunakan kube-dns, maka kamu mungkin masih menggunakan kube-dns daripada CoreDNS.

Jika kamu menjalankan CoreDNS sebagai sebuah Deployment, maka biasanya akan ditampilkan sebagai sebuah Service Kubernetes dengan alamat IP yang statis. Kubelet meneruskan informasi DNS resolver ke setiap Container dengan argumen --cluster-dns=<dns-service-ip>.

Nama DNS juga membutuhkan domain. Kamu dapat mengonfigurasi domain lokal di kubelet dengan argumen --cluster-domain=<default-local-domain>.

Server DNS mendukung forward lookup (record A dan AAAA), port lookup (record SRV), reverse lookup alamat IP (record PTR), dan lain sebagainya. Untuk informasi lebih lanjut, lihatlah DNS untuk Service dan Pod.

Jika dnsPolicy dari Pod diatur menjadi default, itu berarti mewarisi konfigurasi resolusi nama dari Node yang dijalankan Pod. Resolusi DNS pada Pod harus berperilaku sama dengan Node tersebut. Tapi lihat Isu-isu yang telah diketahui.

Jika kamu tidak menginginkan hal ini, atau jika kamu menginginkan konfigurasi DNS untuk Pod berbeda, kamu bisa menggunakan argumen --resolv-conf pada kubelet. Atur argumen ini menjadi "" untuk mencegah Pod tidak mewarisi konfigurasi DNS. Atur ke jalur (path) berkas yang tepat untuk berkas yang berbeda dengan /etc/resolv.conf untuk menghindari mewarisi konfigurasi DNS.

CoreDNS

CoreDNS adalah server DNS otoritatif untuk kegunaan secara umum yang dapat berfungsi sebagai Service DNS untuk klaster, yang sesuai dengan spesifikasi dns.

Opsi ConfigMap pada CoreDNS

CoreDNS adalah server DNS yang modular dan mudah dipasang, dan setiap plugin dapat menambahkan fungsionalitas baru ke CoreDNS. Fitur ini dapat dikonfigurasikan dengan menjaga berkas Corefile, yang merupakan berkas konfigurasi dari CoreDNS. Sebagai administrator klaster, kamu dapat memodifikasi ConfigMap untuk Corefile dari CoreDNS dengan mengubah cara perilaku pencarian Service DNS pada klaster tersebut.

Di Kubernetes, CoreDNS diinstal dengan menggunakan konfigurasi Corefile bawaan sebagai berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }    

Konfigurasi Corefile meliputi plugin berikut ini dari CoreDNS:

  • errors: Kesalahan yang ditampilkan ke output standar (stdout)
  • health: Kesehatan dari CoreDNS dilaporkan pada http://localhost:8080/health. Dalam sintaks yang diperluas lameduck akan menangani proses tidak sehat agar menunggu selama 5 detik sebelum proses tersebut dimatikan.
  • ready: Endpoint HTTP pada port 8181 akan mengembalikan OK 200, ketika semua plugin yang dapat memberi sinyal kesiapan, telah memberikan sinyalnya.
  • kubernetes: CoreDNS akan menjawab pertanyaan (query) DNS berdasarkan IP Service dan Pod pada Kubernetes. Kamu dapat menemukan lebih detail tentang plugin itu dalam situs web CoreDNS. ttl memungkinkan kamu untuk mengatur TTL khusus untuk respon dari pertanyaan DNS. Standarnya adalah 5 detik. TTL minimum yang diizinkan adalah 0 detik, dan maksimum hanya dibatasi sampai 3600 detik. Mengatur TTL ke 0 akan mencegah record untuk di simpan sementara dalam cache.
    Opsi pods insecure disediakan untuk kompatibilitas dengan Service kube-dns sebelumnya. Kamu dapat menggunakan opsi pods verified, yang mengembalikan record A hanya jika ada Pod pada Namespace yang sama untuk alamat IP yang sesuai. Opsi pods disabled dapat digunakan jika kamu tidak menggunakan record Pod.
  • prometheus: Metrik dari CoreDNS tersedia pada http://localhost:9153/metrics dalam format yang sesuai dengan Prometheus (dikenal juga sebagai OpenMetrics).
  • forward: Setiap pertanyaan yang tidak berada dalam domain klaster Kubernetes akan diteruskan ke resolver yang telah ditentukan dalam berkas (/etc/resolv.conf).
  • cache: Ini untuk mengaktifkan frontend cache.
  • loop: Mendeteksi forwarding loop sederhana dan menghentikan proses CoreDNS jika loop ditemukan.
  • reload: Mengizinkan reload otomatis Corefile yang telah diubah. Setelah kamu mengubah konfigurasi ConfigMap, beri waktu sekitar dua menit agar perubahan yang kamu lakukan berlaku.
  • loadbalance: Ini adalah load balancer DNS secara round-robin yang mengacak urutan record A, AAAA, dan MX dalam setiap responnya.

Kamu dapat memodifikasi perilaku CoreDNS bawaan dengan memodifikasi ConfigMap.

Konfigurasi Stub-domain dan Nameserver Upstream dengan menggunakan CoreDNS

CoreDNS memiliki kemampuan untuk mengonfigurasi stubdomain dan nameserver upstream dengan menggunakan plugin forward.

Contoh

Jika operator klaster memiliki sebuah server domain Consul yang terletak di 10.150.0.1, dan semua nama Consul memiliki akhiran .consul.local. Untuk mengonfigurasinya di CoreDNS, administrator klaster membuat bait (stanza) berikut dalam ConfigMap CoreDNS.

consul.local:53 {
        errors
        cache 30
        forward . 10.150.0.1
    }

Untuk memaksa secara eksplisit semua pencarian DNS non-cluster melalui nameserver khusus pada 172.16.0.1, arahkan forward ke nameserver bukan ke /etc/resolv.conf

forward .  172.16.0.1

ConfigMap terakhir bersama dengan konfigurasi Corefile bawaan terlihat seperti berikut:

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . 172.16.0.1
        cache 30
        loop
        reload
        loadbalance
    }
    consul.local:53 {
        errors
        cache 30
        forward . 10.150.0.1
    }    

Perangkat kubeadm mendukung terjemahan otomatis dari ConfigMap kube-dns ke ConfigMap CoreDNS yang setara.

Konfigurasi CoreDNS yang setara dengan kube-dns

CoreDNS mendukung fitur kube-dns dan banyak lagi lainnya. ConfigMap dibuat agar kube-dns mendukung StubDomains dan upstreamNameservers untuk diterjemahkan ke plugin forward dalam CoreDNS. Begitu pula dengan plugin Federations dalam kube-dns melakukan translasi untuk plugin federation dalam CoreDNS.

Contoh

Contoh ConfigMap ini untuk kube-dns menentukan federasi, stub domain dan server upstream nameserver:

apiVersion: v1
data:
  federations: |
    {"foo" : "foo.feddomain.com"}    
  stubDomains: |
    {"abc.com" : ["1.2.3.4"], "my.cluster.local" : ["2.3.4.5"]}    
  upstreamNameservers: |
    ["8.8.8.8", "8.8.4.4"]    
kind: ConfigMap

Untuk konfigurasi yang setara dengan CoreDNS buat Corefile berikut:

  • Untuk federasi:
federation cluster.local {
    foo foo.feddomain.com
}
  • Untuk stubDomain:
abc.com:53 {
    errors
    cache 30
    forward . 1.2.3.4
}
my.cluster.local:53 {
    errors
    cache 30
    forward . 2.3.4.5
}

Corefile lengkap dengan plugin bawaan:

.:53 {
    errors
    health
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
    }
    federation cluster.local {
        foo foo.feddomain.com
    }
    prometheus :9153
    forward . 8.8.8.8 8.8.4.4
    cache 30
}
abc.com:53 {
    errors
    cache 30
    forward . 1.2.3.4
}
my.cluster.local:53 {
    errors
    cache 30
    forward . 2.3.4.5
}

Migrasi ke CoreDNS

Untuk bermigrasi dari kube-dns ke CoreDNS, artikel blog yang detail tersedia untuk membantu pengguna mengadaptasi CoreDNS sebagai pengganti dari kube-dns.

Kamu juga dapat bermigrasi dengan menggunakan skrip deploy CoreDNS yang resmi.

Selanjutnya

4.5 - Melakukan Reservasi Sumber Daya Komputasi untuk Daemon Sistem

Node Kubernetes dapat dijadwalkan sesuai dengan kapasitas. Secara bawaan, Pod dapat menggunakan semua kapasitas yang tersedia pada sebuah Node. Ini merupakan masalah karena Node sebenarnya menjalankan beberapa daemon sistem yang diperlukan oleh OS dan Kubernetes itu sendiri. Jika sumber daya pada Node tidak direservasi untuk daemon-daemon tersebut, maka Pod dan daemon akan berlomba-lomba menggunakan sumber daya yang tersedia, sehingga menyebabkan starvation sumber daya pada Node.

Fitur bernama Allocatable pada Node diekspos oleh kubelet yang berfungsi untuk melakukan reservasi sumber daya komputasi untuk daemon sistem. Kubernetes merekomendasikan admin klaster untuk mengatur Allocatable pada Node berdasarkan tingkat kepadatan (density) beban kerja setiap Node.

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 1.8. Untuk melihat versi, tekan kubectl version. Kamu harus menjalankan Kubernetes server dengan versi 1.17 atau yang lebih baru untuk menggunakan perintah baris kubelet dengan opsi --reserved-cpus untuk menyetel daftar reservasi CPU secara eksplisit.

Allocatable pada Node

       Kapasitas Node
------------------------------
|       kube-reserved        |
|----------------------------|
|      system-reserved       |
|----------------------------|
|     eviction-threshold     |
|     (batas pengusiran)     |
|----------------------------|
|                            |
|        allocatable         |
| (dapat digunakan oleh Pod) |
|                            |
|                            |
------------------------------

Allocatable atau sumber daya yang dialokasikan pada sebuah Node Kubernetes merupakan jumlah sumber daya komputasi yang dapat digunakan oleh Pod. Penjadwal tidak dapat melakukan penjadwalan melebihi Allocatable. Saat ini dukungan terhadap CPU, memory dan ephemeral-storage tersedia.

Allocatable pada Node diekspos oleh objek API v1.Node dan merupakan bagian dari baris perintah kubectl describe node.

Sumber daya dapat direservasi untuk dua kategori daemon sistem melalui kubelet.

Mengaktifkan QoS dan tingkatan cgroup dari Pod

Untuk menerapkan batasan Allocatable pada Node, kamu harus mengaktifkan hierarki cgroup yang baru melalui flag --cgroups-per-qos. Secara bawaan, flag ini telah aktif. Saat aktif, kubelet akan memasukkan semua Pod pengguna di bawah sebuah hierarki cgroup yang dikelola oleh kubelet.

Mengonfigurasi driver cgroup

Manipulasi terhadap hierarki cgroup pada hos melalui driver cgroup didukung oleh kubelet. Driver dikonfigurasi melalui flag --cgroup-driver.

Nilai yang didukung adalah sebagai berikut:

  • cgroupfs merupakan driver bawaan yang melakukan manipulasi secara langsung terhadap filesystem cgroup pada hos untuk mengelola sandbox cgroup.
  • systemd merupakan driver alternatif yang mengelola sandbox cgroup menggunakan bagian dari sumber daya yang didukung oleh sistem init yang digunakan.

Tergantung dari konfigurasi runtime Container yang digunakan, operator dapat memilih driver cgroup tertentu untuk memastikan perilaku sistem yang tepat. Misalnya, jika operator menggunakan driver cgroup systemd yang disediakan oleh runtime docker, maka kubelet harus diatur untuk menggunakan driver cgroup systemd.

Kube Reserved

  • Flag Kubelet: --kube-reserved=[cpu=100m][,][memory=100Mi][,][ephemeral-storage=1Gi][,][pid=1000]
  • Flag Kubelet: --kube-reserved-cgroup=

kube-reserved berfungsi untuk mengambil informasi sumber daya reservasi untuk daemon sistem Kubernetes, seperti kubelet, runtime Container, detektor masalah pada Node, dsb. kube-reserved tidak berfungsi untuk mereservasi sumber daya untuk daemon sistem yang berjalan sebagai Pod. kube-reserved merupakan fungsi dari kepadatan Pod pada Node.

Selain dari cpu, memory, dan ephemeral-storage,pid juga dapat diatur untuk mereservasi jumlah ID proses untuk daemon sistem Kubernetes.

Secara opsional, kamu dapat memaksa daemon sistem melalui setelan kube-reserved. Ini dilakukan dengan menspesifikasikan parent cgroup sebagai nilai dari flag --kube-reserved-cgroup pada kubelet.

Kami merekomendasikan daemon sistem Kubernetes untuk ditempatkan pada tingkatan cgroup yang tertinggi (contohnya, runtime.slice pada mesin systemd). Secara ideal, setiap daemon sistem sebaiknya dijalankan pada child cgroup di bawah parent ini. Lihat dokumentasi untuk mengetahui rekomendasi hierarki cgroup secara detail.

Catatan: kubelet tidak membuat --kube-reserved-cgroup jika cgroup yang diberikan tidak ada pada sistem. Jika cgroup yang tidak valid diberikan, maka kubelet akan mengalami kegagalan.

System Reserved

  • Flag Kubelet: --system-reserved=[cpu=100m][,][memory=100Mi][,][ephemeral-storage=1Gi][,][pid=1000]
  • Flag Kubelet: --system-reserved-cgroup=

system-reserved berfungsi untuk mengetahui reservasi sumber daya untuk daemon sistem pada OS, seperti sshd, udev, dan lainnya. system-reserved sebaiknya mereservasi memori untuk kernel juga, karena memori kernel tidak termasuk dalam hitungan kalkulasi Pod pada Kubernetes. Kami juga merekomendasikan reservasi sumber daya untuk sesi (session) login pengguna (contohnya, user.slice di dalam dunia systemd).

Melakukan Reservasi Daftar CPU secara Eksplisit

FEATURE STATE: Kubernetes v1.17 [stable]
  • Flag Kubelet: --reserved-cpus=0-3

reserved-cpus berfungsi untuk mendefinisikan cpuset secara eksplisit untuk daemon sistem OS dan daemon sistem Kubernetes. reserved-cpus dimaksudkan untuk sistem-sistem yang tidak mendefinisikan tingkatan cgroup tertinggi secara terpisah untuk daemon sistem OS dan daemon sistem Kubernetes yang berkaitan dengan sumber daya cpuset.

Jika kubelet tidak memiliki --system-reserved-cgroup dan --kube-reserved-cgroup, cpuset akan diberikan secara eksplisit oleh reserved-cpus, yang akan menimpa definisi yang diberikan oleh opsi --kube-reserved dan --system-reserved.

Opsi ini dirancang secara spesifik untuk kasus-kasus Telco/NFV, di mana interrupt atau timer yang tidak terkontrol bisa memengaruhi performa dari beban kerja. Kamu dapat menggunakan opsi untuk untuk mendefinisikan cpuset secara eksplisit untuk daemon sistem/Kubernetes dan interrupt/timer, sehingga CPU sisanya dalam sistem akan digunakan untuk beban kerja saja, dengan dampak yang sedikit terhadap interrupt/timer yang tidak terkontrol. Untuk memindahkan daemon sistem, daemon Kubernetes serta interrrupt/timer Kubernetes supaya menggunakan cpuset yang eksplisit didefinisikan oleh opsi ini, sebaiknya digunakan mekanisme lain di luar Kubernetes. Contohnya: pada Centos, kamu dapat melakukan ini dengan menggunakan toolset yang sudah disetel.

Batas Pengusiran (Eviction Threshold)

  • Flag Kubelet: --eviction-hard=[memory.available<500Mi]

Tekanan memori pada tingkatan Node menyebabkan sistem OOM (Out Of Memory) yang berdampak pada Node secara keseluruhan dan semua Pod yang dijalankan di dalamnya. Node dapat berubah menjadi offline sementara sampai memori berhasil diklaim kembali. Untuk menghindari sistem OOM, atau mengurangi kemungkinan terjadinya OOM, kubelet menyediakan fungsi untuk pengelolaan saat Kehabisan Sumber Daya (Out of Resource). Pengusiran dapat dilakukan hanya untuk kasus kehabisan memory dan ephemeral-storage. Dengan mereservasi sebagian memori melalui flag --eviction-hard, kubelet akan berusaha untuk "mengusir" (evict) Pod ketika ketersediaan memori pada Node jatuh di bawah nilai yang telah direservasi. Dalam bahasa sederhana, jika daemon sistem tidak ada pada Node, maka Pod tidak dapat menggunakan memori melebihi nilai yang ditentukan oleh flag --eviction-hard. Karena alasan ini, sumber daya yang direservasi untuk pengusiran tidak tersedia untuk Pod.

Memaksakan Allocatable pada Node

  • Flag Kubelet: --enforce-node-allocatable=pods[,][system-reserved][,][kube-reserved]

Penjadwal menganggap Allocatable sebagai kapasitas yang tersedia untuk digunakan oleh Pod.

Secara bawaan, kubelet memaksakan Allocatable untuk semua Pod. Pemaksaan dilakukan dengan cara "mengusir" Pod-Pod ketika penggunaan sumber daya Pod secara keseluruhan telah melewati nilai Allocatable. Lihat bagian ini untuk mengetahui kebijakan pengusiran secara detail. Pemaksaan ini dikendalikan dengan cara memberikan nilai Pod melalui flag --enforce-node-allocatable pada kubelet.

Secara opsional, kubelet dapat diatur untuk memaksakan kube-reserved dan system-reserved dengan memberikan nilai melalui flag tersebut. Sebagai catatan, jika kamu mengatur kube-reserved, maka kamu juga harus mengatur --kube-reserved-cgroup. Begitu pula jika kamu mengatur system-reserved, maka kamu juga harus mengatur --system-reserved-cgroup.

Panduan Umum

Daemon sistem dilayani mirip seperti Pod Guaranteed yang terjamin sumber dayanya. Daemon sistem dapat melakukan burst di dalam jangkauan cgroup. Perilaku ini dikelola sebagai bagian dari penggelaran (deployment) Kubernetes. Sebagai contoh, kubelet harus memiliki cgroup sendiri dan membagikan sumber daya kube-reserved dengan runtime Container. Namun begitu, kubelet tidak dapat melakukan burst dan menggunakan semua sumber daya yang tersedia pada Node jika kube-reserved telah dipaksakan pada sistem.

Kamu harus berhati-hati ekstra ketika memaksakan reservasi system-reserved karena dapat menyebabkan layanan sistem yang terpenting mengalami CPU starvation, OOM killed, atau tidak dapat melakukan fork pada Node. Kami menyarankan untuk memaksakan system-reserved hanya jika pengguna telah melakukan profiling sebaik mungkin pada Node mereka untuk mendapatkan estimasi yang akurat dan percaya diri terhadap kemampuan mereka untuk memulihkan sistem ketika ada grup yang terkena OOM killed.

  • Untuk memulai, paksakan Allocatable pada Pod.
  • Ketika monitoring dan alerting telah cukup dilakukan untuk memonitor daemon dari sistem Kubernetes, usahakan untuk memaksakan kube-reserved berdasarkan penggunakan heuristik.
  • Jika benar-benar diperlukan, paksakan system-reserved secara bertahap.

Sumber daya yang diperlukan oleh daemon sistem Kubernetes dapat tumbuh seiring waktu dengan adanya penambahan fitur-fitur baru. Proyek Kubernetes akan berusaha untuk menurunkan penggunaan sumber daya dari daemon sistem Node, tetapi belum menjadi prioritas untuk saat ini. Kamu dapat berekspektasi bahwa fitur kapasitas Allocatable ini akan dihapus pada versi yang akan datang.

Contoh Skenario

Berikut ini merupakan contoh yang menggambarkan komputasi Allocatable pada Node:

  • Node memiliki 16 CPU, memori sebesar 32Gi, dan penyimpanan sebesar 100Gi.
  • --kube-reserved diatur menjadi cpu=1,memory=2Gi,ephemeral-storage=1Gi
  • --system-reserved diatur menjadi cpu=500m,memory=1Gi,ephemeral-storage=1Gi
  • --eviction-hard diatur menjadi memory.available<500Mi,nodefs.available<10%

Dalam skenario ini, Allocatable akan menjadi 14.5 CPU, memori 28.5Gi, dan penyimpanan lokal 88Gi. Penjadwal memastikan bahwa semua Pod yang berjalan pada Node ini secara total tidak meminta memori melebihi 28.5Gi dan tidak menggunakan penyimpanan lokal melebihi 88Gi. Pengusiran Pod akan dilakukan kubelet ketika penggunaan memori keseluruhan oleh Pod telah melebihi 28.5Gi, atau jika penggunaan penyimpanan keseluruhan telah melebihi 88Gi. Jika semua proses pada Node mengonsumsi CPU sebanyak-banyaknya, Pod-Pod tidak dapat mengonsumsi lebih dari 14.5 CPU.

Jika kube-reserved dan/atau system-reserved tidak dipaksakan dan daemon sistem melebihi reservasi mereka, maka kubelet akan mengusir Pod ketika penggunaan memori pada Node melebihi 31.5Gi atau penggunaan penyimpanan melebihi 90Gi.

4.6 - Membagi sebuah Klaster dengan Namespace

Laman ini menunjukkan bagaimana cara melihat, menggunakan dan menghapus namespaces. Laman ini juga menunjukkan bagaimana cara menggunakan Namespace Kubernetes namespaces untuk membagi klaster kamu.

Sebelum kamu memulai

Melihat Namespace

  1. Untuk melihat Namespace yang ada saat ini pada sebuah klaster anda bisa menggunakan:
kubectl get namespaces
NAME          STATUS    AGE
default       Active    11d
kube-system   Active    11d
kube-public   Active    11d

Kubernetes mulai dengan tiga Namespace pertama:

  • default Namespace bawaan untuk objek-objek yang belum terkait dengan Namespace lain
  • kube-system Namespace untuk objek-objek yang dibuat oleh sistem Kubernetes
  • kube-public Namespace ini dibuat secara otomatis dan dapat dibaca oleh seluruh pengguna (termasuk yang tidak terotentikasi). Namespace ini sering dicadangkan untuk kepentingan klaster, untuk kasus dimana beberapa sumber daya seharusnya dapat terlihat dan dapat terlihat secara publik di seluruh klaster. Aspek publik pada Namespace ini hanya sebuah konvensi bukan suatu kebutuhan.

Kamu bisa mendapat ringkasan Namespace tertentu dengan menggunakan:

kubectl get namespaces <name>

Atau kamu bisa mendapatkan informasi detail menggunakan:

kubectl describe namespaces <name>
Name:           default
Labels:         <none>
Annotations:    <none>
Status:         Active

No resource quota.

Resource Limits
 Type       Resource    Min Max Default
 ----               --------    --- --- ---
 Container          cpu         -   -   100m

Sebagai catatan, detail diatas menunjukkan baik kuota sumber daya (jika ada) dan juga jangkauan batas sumber daya.

Kuota sumber daya melacak penggunaan total sumber daya didalam Namespace dan mengijinkan operator-operator klaster mendefinisikan batas atas penggunaan sumber daya yang dapat di gunakan sebuah Namespace.

Jangkauan batas mendefinisikan pertimbangan min/maks jumlah sumber daya yang dapat di gunakan oleh sebuah entitas dalam sebuah Namespace.

Lihatlah Kontrol Admisi: Rentang Batas

Sebuah Namespace dapat berada dalam salah satu dari dua buah fase:

  • Active Namespace sedang digunakan
  • Terminating Namespace sedang dihapus dan tidak dapat digunakan untuk objek-objek baru

Lihat dokumentasi desain untuk detil lebih lanjut.

Membuat sebuah Namespace baru

  1. Buat berkas YAML baru dengan nama my-namespace.yaml dengan isi berikut ini:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: <masukkan-nama-namespace-disini>
    

    Then run:

    kubectl create -f ./my-namespace.yaml
    
  2. Sebagai alternatif, kamu bisa membuat Namespace menggunakan perintah dibawah ini:

    kubectl create namespace <masukkan-nama-namespace-disini>
    

Nama Namespace kamu harus merupakan Label DNS yang valid.

Ada kolom opsional finalizers, yang memungkinkan observables untuk membersihkan sumber daya ketika Namespace dihapus. Ingat bahwa jika kamu memberikan finalizer yang tidak ada, Namespace akan dibuat tapi akan berhenti pada status Terminating jika pengguna mencoba untuk menghapusnya.

Informasi lebih lanjut mengenai finalizers bisa dibaca pada dokumentasi desain dari Namespace.

Menghapus Namespace

Hapus Namespace dengan

kubectl delete namespaces <insert-some-namespace-name>

Proses penghapusan ini asinkron, jadi untuk beberapa waktu kamu akan melihat Namespace dalam status Terminating.

Membagi klaster kamu menggunakan Namespace Kubernetes

  1. Pahami Namespace bawaan

    Secara bawaan, sebuah klaster Kubernetes akan membuat Namespace bawaan ketika menyediakan klaster untuk menampung Pod, Service, dan Deployment yang digunakan oleh klaster.

    Dengan asumsi kamu memiliki klaster baru, kamu bisa mengecek Namespace yang tersedia dengan melakukan hal berikut:

    kubectl get namespaces
    
    NAME      STATUS    AGE
    default   Active    13m
    
  2. Membuat Namespace baru

    Untuk latihan ini, kita akan membuat dua Namespace Kubernetes tambahan untuk menyimpan konten kita

    Dalam sebuah skenario dimana sebuah organisasi menggunakan klaster Kubernetes yang digunakan bersama untuk penggunaan pengembangan dan produksi:

    Tim pengembang ingin mengelola ruang di dalam klaster dimana mereka bisa melihat daftar Pod, Service, dan Deployment yang digunakan untuk membangun dan menjalankan apliksi mereka. Di ruang ini sumber daya akan datang dan pergi, dan pembatasan yang tidak ketat mengenai siapa yang bisa atau tidak bisa memodifikasi sumber daya untuk mendukung pengembangan secara gesit (agile).

    Tim operasi ingin mengelola ruang didalam klaster dimana mereka bisa memaksakan prosedur ketat mengenai siapa yang bisa atau tidak bisa melakukan manipulasi pada kumpulan Pod, Layanan, dan Deployment yang berjalan pada situs produksi.

    Satu pola yang bisa diikuti organisasi ini adalah dengan membagi klaster Kubernetes menjadi dua Namespace: development dan production

    Mari kita buat dua Namespace untuk menyimpan hasil kerja kita.

    Buat Namespace development menggunakan kubectl:

    kubectl create -f https://k8s.io/examples/admin/namespace-dev.json
    

    Kemudian mari kita buat Namespace production menggunakan kubectl:

    kubectl create -f https://k8s.io/examples/admin/namespace-prod.json
    

    Untuk memastikan apa yang kita lakukan benar, lihat seluruh Namespace dalam klaster.

    kubectl get namespaces --show-labels
    
    NAME          STATUS    AGE       LABELS
    default       Active    32m       <none>
    development   Active    29s       name=development
    production    Active    23s       name=production
    
  3. Buat pod pada setiap Namespace

    Sebuah Namespace Kubernetes memberikan batasan untuk Pod, Service, dan Deployment dalam klaster.

    Pengguna yang berinteraksi dengan salah satu Namespace tidak melihat konten di dalam Namespace lain

    Untuk menunjukkan hal ini, mari kita jalankan Deployment dan Pod sederhana di dalam Namespace development.

    kubectl create deployment snowflake --image=registry.k8s.io/serve_hostname -n=development
    kubectl scale deployment snowflake --replicas=2 -n=development
    

    Kita baru aja membuat sebuah Deployment yang memiliki ukuran replika dua yang menjalankan Pod dengan nama snowflake dengan sebuah Container dasar yang hanya melayani hostname.

    kubectl get deployment -n=development
    
    NAME         READY   UP-TO-DATE   AVAILABLE   AGE
    snowflake    2/2     2            2           2m
    
    kubectl get pods -l app=snowflake -n=development
    
    NAME                         READY     STATUS    RESTARTS   AGE
    snowflake-3968820950-9dgr8   1/1       Running   0          2m
    snowflake-3968820950-vgc4n   1/1       Running   0          2m
    

    Dan ini merupakan sesuatu yang bagus, dimana pengembang bisa melakukan hal yang ingin mereka lakukan tanpa harus khawatir hal itu akan mempengaruhi konten pada namespace production.

    Mari kita pindah ke Namespace production dan menujukkan bagaimana sumber daya di satu Namespace disembunyikan dari yang lain

    Namespace production seharusnya kosong, dan perintah berikut ini seharusnya tidak menghasilkan apapun.

    kubectl get deployment -n=production
    kubectl get pods -n=production
    

    Production Namespace ingin menjalankan cattle, mari kita buat beberapa Pod cattle.

    kubectl create deployment cattle --image=registry.k8s.io/serve_hostname -n=production
    kubectl scale deployment cattle --replicas=5 -n=production
    
    kubectl get deployment -n=production
    
    NAME         READY   UP-TO-DATE   AVAILABLE   AGE
    cattle       5/5     5            5           10s
    
    kubectl get pods -l app=cattle -n=production
    
    NAME                      READY     STATUS    RESTARTS   AGE
    cattle-2263376956-41xy6   1/1       Running   0          34s
    cattle-2263376956-kw466   1/1       Running   0          34s
    cattle-2263376956-n4v97   1/1       Running   0          34s
    cattle-2263376956-p5p3i   1/1       Running   0          34s
    cattle-2263376956-sxpth   1/1       Running   0          34s
    

Sampai sini, seharusnya sudah jelas bahwa sumber daya yang dibuat pengguna pada sebuah Namespace disembunyikan dari Namespace lainnya.

Seiring dengan evolusi dukungan kebijakan di Kubernetes, kami akan memperluas skenario ini untuk menunjukkan bagaimana kamu bisa menyediakan aturan otorisasi yang berbeda untuk tiap Namespace.

Memahami motivasi penggunaan Namespace

Sebuah klaster tunggal umumnya bisa memenuhi kebutuhan pengguna yang berbeda atau kelompok pengguna (itulah sebabnya disebut 'komunitas pengguna').

Namespace Kubernetes membantu proyek-proyek, tim-tim dan pelanggan yang berbeda untuk berbagi klaster Kubernetes.

Ini dilakukan dengan menyediakan hal berikut:

  1. Cakupan untuk Names.
  2. Sebuah mekanisme untuk memasang otorisasi dan kebijakan untuk bagian dari klaster.

Penggunaan Namespace berbeda merupakan hal opsional.

Tiap komunitas pengguna ingin bisa bekerja secara terisolasi dari komunitas lainnya.

Tiap komunitas pengguna memiliki hal berikut sendiri:

  1. sumber daya (Pod, Service, ReplicationController, dll.)
  2. kebijakan (siapa yang bisa atau tidak bisa melakukan hal tertentu dalam komunitasnya)
  3. batasan (komunitas ini diberi kuota sekian, dll.)

Seorang operator klaster dapat membuat sebuah Namespace untuk tiap komunitas user yang unik.

Namespace tersebut memberikan cakupan yang unik untuk:

  1. penamaan sumber daya (untuk menghindari benturan penamaan dasar)
  2. pendelegasian otoritas pengelolaan untuk pengguna yang dapat dipercaya
  3. kemampuan untuk membatasi konsumsi sumber daya komunitas

Contoh penggunaan mencakup

  1. Sebagai operator klaster, aku ingin mendukung beberapa komunitas pengguna dalam sebuah klaster.
  2. Sebagai operator klaster, aku ingin mendelegasikan otoritas untuk mempartisi klaster ke pengguna terpercaya di komunitasnya.
  3. Sebagai operator klaster, aku ingin membatasi jumlah sumber daya yang bisa dikonsumsi komunitas dalam rangka membatasi dampak ke komunitas lain yang menggunakan klaster yang sama.
  4. Sebagai pengguna klaster, aku ingin berinteraksi dengan sumber daya yang berkaitan dengan komunitas pengguna saya secara terisolasi dari apa yang dilakukan komunitas lain di klaster yang sama.

Memahami Namespace dan DNS

Ketika kamu membuat sebuah Service, akan terbentuk entri DNS untuk Service tersebut. Entri DNS ini dalam bentuk <service-name>.<namespace-name>.svc.cluster.local, yang berarti jika sebuah Container hanya menggunakan <service-name> maka dia akan me-resolve ke layanan yang lokal dalam Namespace yang sama. Ini berguna untuk menggunakan konfigurasi yang sama pada Namespace yang berbeda seperti Development, Staging dan Production. Jika kami ingin menjangkau antar Namespace, kamu harus menggunakan fully qualified domain name (FQDN).

Selanjutnya

4.7 - Mengatur Control Plane Kubernetes dengan Ketersediaan Tinggi (High-Availability)

FEATURE STATE: Kubernetes v1.5 [alpha]

Kamu dapat mereplikasi control plane Kubernetes dalam skrip kube-up atau kube-down untuk Google Compute Engine (GCE). Dokumen ini menjelaskan cara menggunakan skrip kube-up/down untuk mengelola control plane dengan ketersedian tinggi atau high_availability (HA) dan bagaimana control plane HA diimplementasikan untuk digunakan dalam GCE.

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.

Memulai klaster yang kompatibel dengan HA

Untuk membuat klaster yang kompatibel dengan HA, kamu harus mengatur tanda ini pada skrip kube-up:

  • MULTIZONE=true - untuk mencegah penghapusan replika control plane kubelet dari zona yang berbeda dengan zona bawaan server. Ini diperlukan jika kamu ingin menjalankan replika control plane pada zona berbeda, dimana hal ini disarankan.

  • ENABLE_ETCD_QUORUM_READ=true - untuk memastikan bahwa pembacaan dari semua server API akan mengembalikan data terbaru. Jika true, bacaan akan diarahkan ke replika pemimpin dari etcd. Menetapkan nilai ini menjadi true bersifat opsional: pembacaan akan lebih dapat diandalkan tetapi juga akan menjadi lebih lambat.

Sebagai pilihan, kamu dapat menentukan zona GCE tempat dimana replika control plane pertama akan dibuat. Atur tanda berikut:

  • KUBE_GCE_ZONE=zone - zona tempat di mana replika control plane pertama akan berjalan.

Berikut ini contoh perintah untuk mengatur klaster yang kompatibel dengan HA pada zona GCE europe-west1-b:

MULTIZONE=true KUBE_GCE_ZONE=europe-west1-b  ENABLE_ETCD_QUORUM_READS=true ./cluster/kube-up.sh

Perhatikan bahwa perintah di atas digunakan untuk membuat klaster dengan sebuah control plane; Namun, kamu bisa menambahkan replika control plane baru ke klaster dengan perintah berikutnya.

Menambahkan replika control plane yang baru

Setelah kamu membuat klaster yang kompatibel dengan HA, kamu bisa menambahkan replika control plane ke sana. Kamu bisa menambahkan replika control plane dengan menggunakan skrip kube-up dengan tanda berikut ini:

  • KUBE_REPLICATE_EXISTING_MASTER=true - untuk membuat replika dari control plane yang sudah ada.

  • KUBE_GCE_ZONE=zone - zona di mana replika control plane itu berjalan. Region ini harus sama dengan region dari zona replika yang lain.

Kamu tidak perlu mengatur tanda MULTIZONE atau ENABLE_ETCD_QUORUM_READS, karena tanda itu diturunkan pada saat kamu memulai klaster yang kompatible dengan HA.

Berikut ini contoh perintah untuk mereplikasi control plane pada klaster sebelumnya yang kompatibel dengan HA:

KUBE_GCE_ZONE=europe-west1-c KUBE_REPLICATE_EXISTING_MASTER=true ./cluster/kube-up.sh

Menghapus replika control plane

Kamu dapat menghapus replika control plane dari klaster HA dengan menggunakan skrip kube-down dengan tanda berikut:

  • KUBE_DELETE_NODES=false - untuk mencegah penghapusan kubelet.

  • KUBE_GCE_ZONE=zone - zona di mana replika control plane akan dihapus.

  • KUBE_REPLICA_NAME=replica_name - (opsional) nama replika control plane yang akan dihapus. Jika kosong: replika mana saja dari zona yang diberikan akan dihapus.

Berikut ini contoh perintah untuk menghapus replika control plane dari klaster HA yang sudah ada sebelumnya:

KUBE_DELETE_NODES=false KUBE_GCE_ZONE=europe-west1-c ./cluster/kube-down.sh

Mengatasi replika control plane yang gagal

Jika salah satu replika control plane di klaster HA kamu gagal, praktek terbaik adalah menghapus replika dari klaster kamu dan menambahkan replika baru pada zona yang sama. Berikut ini contoh perintah yang menunjukkan proses tersebut:

  1. Menghapus replika yang gagal:
KUBE_DELETE_NODES=false KUBE_GCE_ZONE=replica_zone KUBE_REPLICA_NAME=replica_name ./cluster/kube-down.sh
  1. Menambahkan replika baru untuk menggantikan replika yang lama
KUBE_GCE_ZONE=replica-zone KUBE_REPLICATE_EXISTING_MASTER=true ./cluster/kube-up.sh

Praktek terbaik untuk mereplikasi control plane untuk klaster HA

  • Usahakan untuk menempatkan replika control plane pada zona yang berbeda. Pada saat terjadi kegagalan zona, semua control plane yang ditempatkan dalam zona tersebut akan gagal pula. Untuk bertahan dari kegagalan pada sebuah zona, tempatkan juga Node pada beberapa zona yang lain (Lihatlah multi-zona untuk lebih detail).

  • Jangan gunakan klaster dengan dua replika control plane. Konsensus pada klaster dengan dua replika membutuhkan kedua replika tersebut berjalan pada saat mengubah keadaan yang persisten. Akibatnya, kedua replika tersebut diperlukan dan kegagalan salah satu replika mana pun mengubah klaster dalam status kegagalan mayoritas. Dengan demikian klaster dengan dua replika lebih buruk, dalam hal HA, daripada klaster dengan replika tunggal.

  • Ketika kamu menambahkan sebuah replika control plane, status klaster (etcd) disalin ke sebuah instance baru. Jika klaster itu besar, mungkin butuh waktu yang lama untuk menduplikasi keadaannya. Operasi ini dapat dipercepat dengan memigrasi direktori data etcd, seperti yang dijelaskan di sini (Kami sedang mempertimbangkan untuk menambahkan dukungan untuk migrasi direktori data etcd di masa mendatang).

Catatan implementasi

ha-master-gce

Ikhtisar

Setiap replika control plane akan menjalankan komponen berikut dalam mode berikut:

  • instance etcd: semua instance akan dikelompokkan bersama menggunakan konsensus;

  • server API : setiap server akan berbicara dengan lokal etcd - semua server API pada cluster akan tersedia;

  • pengontrol (controller), penjadwal (scheduler), dan scaler klaster automatis: akan menggunakan mekanisme sewa - dimana hanya satu instance dari masing-masing mereka yang akan aktif dalam klaster;

  • manajer tambahan (add-on): setiap manajer akan bekerja secara independen untuk mencoba menjaga tambahan dalam sinkronisasi.

Selain itu, akan ada penyeimbang beban (load balancer) di depan server API yang akan mengarahkan lalu lintas eksternal dan internal menuju mereka.

Penyeimbang Beban

Saat memulai replika control plane kedua, penyeimbang beban yang berisi dua replika akan dibuat dan alamat IP dari replika pertama akan dipromosikan ke alamat IP penyeimbang beban. Demikian pula, setelah penghapusan replika control plane kedua yang dimulai dari paling akhir, penyeimbang beban akan dihapus dan alamat IP-nya akan diberikan ke replika terakhir yang ada. Mohon perhatikan bahwa pembuatan dan penghapusan penyeimbang beban adalah operasi yang rumit dan mungkin perlu beberapa waktu (~20 menit) untuk dipropagasikan.

Service control plane & kubelet

Daripada sistem mencoba untuk menjaga daftar terbaru dari apiserver Kubernetes yang ada dalam Service Kubernetes, sistem akan mengarahkan semua lalu lintas ke IP eksternal:

  • dalam klaster dengan satu control plane, IP diarahkan ke control plane tunggal.

  • dalam klaster dengan multiple control plane, IP diarahkan ke penyeimbang beban yang ada di depan control plane.

Demikian pula, IP eksternal akan digunakan oleh kubelet untuk berkomunikasi dengan control plane.

Sertifikat control plane

Kubernetes menghasilkan sertifikat TLS control plane untuk IP publik eksternal dan IP lokal untuk setiap replika. Tidak ada sertifikat untuk IP publik sementara (ephemeral) dari replika; Untuk mengakses replika melalui IP publik sementara, kamu harus melewatkan verifikasi TLS.

Pengklasteran etcd

Untuk mengizinkan pengelompokkan etcd, porta yang diperlukan untuk berkomunikasi antara instance etcd akan dibuka (untuk komunikasi dalam klaster). Untuk membuat penyebaran itu aman, komunikasi antara instance etcd diotorisasi menggunakan SSL.

Bacaan tambahan

Dokumen desain - Penyebaran master HA automatis

4.8 - Menggunakan sysctl dalam Sebuah Klaster Kubernetes

FEATURE STATE: Kubernetes v1.12 [beta]

Dokumen ini menjelaskan tentang cara mengonfigurasi dan menggunakan parameter kernel dalam sebuah klaster Kubernetes dengan menggunakan antarmuka sysctl.

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.

Melihat Daftar Semua Parameter Sysctl

Dalam Linux, antarmuka sysctl memungkinkan administrator untuk memodifikasi kernel parameter pada runtime. Parameter tersedia melalui sistem file virtual dari proses /proc/sys/. Parameter mencakup berbagai subsistem seperti:

  • kernel (dengan prefiks umum: kernel.)
  • networking (dengan prefiks umum: net.)
  • virtual memory (dengan prefiks umum: vm.)
  • MDADM (dengan prefiks umum: dev.)
  • subsistem yang lainnya dideskripsikan pada dokumentasi Kernel.

Untuk mendapatkan daftar semua parameter, kamu bisa menjalankan perintah:

sudo sysctl -a

Mengaktifkan Sysctl Unsafe

Sysctl dikelompokkan menjadi sysctl safe dan sysctl unsafe. Sebagai tambahan untuk pengaturan Namespace yang benar, sebuah sysctl safe harus diisolasikan dengan benar diantara Pod dalam Node yang sama. Hal ini berarti mengatur sysctl safe dalam satu Pod:

  • tidak boleh mempengaruhi Pod lain dalam Node
  • tidak boleh membahayakan kesehatan dari Node
  • tidak mengizinkan untuk mendapatkan sumber daya CPU atau memori di luar batas sumber daya dari sebuah Pod.

Sejauh ini, sebagian besar sysctl yang diatur sebagai Namespace belum tentu dianggap sysctl safe. Sysctl berikut ini didukung dalam kelompok safe:

  • kernel.shm_rmid_forced,
  • net.ipv4.ip_local_port_range,
  • net.ipv4.tcp_syncookies,
  • net.ipv4.ping_group_range (sejak Kubernetes 1.18),
  • net.ipv4.ip_unprivileged_port_start (sejak Kubernetes 1.22).

Daftar ini akan terus dikembangkan dalam versi Kubernetes berikutnya ketika kubelet mendukung mekanisme isolasi yang lebih baik.

Semua sysctl safe diaktifkan secara bawaan.

Semua sysctl unsafe dinon-aktifkan secara bawaan dan harus diizinkan secara manual oleh administrator klaster untuk setiap Node. Pod dengan sysctl unsafe yang dinon-aktifkan akan dijadwalkan, tetapi akan gagal untuk dijalankan.

Dengan mengingat peringatan di atas, administrator klaster dapat mengizinkan sysctl unsafe tertentu untuk situasi yang sangat spesial seperti pada saat kinerja tinggi atau penyetelan aplikasi secara real-time. Unsafe syctl diaktifkan Node demi Node melalui flag pada kubelet; sebagai contoh:

kubelet --allowed-unsafe-sysctls \
  'kernel.msg*,net.core.somaxconn' ...

Untuk Minikube, ini dapat dilakukan melalui flag extra-config:

minikube start --extra-config="kubelet.allowed-unsafe-sysctls=kernel.msg*,net.core.somaxconn"...

Hanya sysctl yang diatur sebagai Namespace dapat diaktifkan dengan cara ini.

Mnegatur Sysctl untuk Pod

Sejumlah sysctl adalah diatur sebagai Namespace dalam Kernel Linux hari ini. Ini berarti mereka dapat diatur secara independen untuk setiap Pod dalam sebuah Node. Hanya sysctl dengan Namespace yang dapat dikonfigurasi melalui Pod securityContext dalam Kubernetes.

Sysctl berikut dikenal sebagai Namespace. Daftar ini dapat berubah pada versi kernel Linux yang akan datang.

  • kernel.shm*,
  • kernel.msg*,
  • kernel.sem,
  • fs.mqueue.*,
  • Parameter dibawah net.* dapat diatur sebagai Namespace dari container networking Namun, ada beberapa perkecualian (seperti net.netfilter.nf_conntrack_max dan net.netfilter.nf_conntrack_expect_max yang dapat diatur dalam Namespace container networking padahal bukan merupakan Namespace).

Sysctl tanpa Namespace disebut dengan sysctl node-level. Jika kamu perlu mengatur mereka, kamu harus secara manual mengonfigurasi mereka pada sistem operasi setiap Node, atau dengan menggunakan DaemonSet melalui Container yang berwenang.

Gunakan securityContext dari Pod untuk mengonfigurasi sysctl Namespace. securityContext berlaku untuk semua Container dalam Pod yang sama.

Contoh ini menggunakan securityContext dari Pod untuk mengatur sebuah sysctl safe kernel.shm_rmid_forced, dan dua buah sysctl unsafe net.core.somaxconn dan kernel.msgmax. Tidak ada perbedaan antara sysctl safe dan sysctl unsafe dalam spesifikasi tersebut.

apiVersion: v1
kind: Pod
metadata:
  name: sysctl-example
spec:
  securityContext:
    sysctls:
    - name: kernel.shm_rmid_forced
      value: "0"
    - name: net.core.somaxconn
      value: "1024"
    - name: kernel.msgmax
      value: "65536"
  ...

Merupakan sebuah praktik yang baik untuk mempertimbangkan Node dengan pengaturan sysctl khusus sebagai Node yang tercemar (tainted) dalam sebuah cluster, dan hanya menjadwalkan Pod yang membutuhkan pengaturan sysctl. Sangat disarankan untuk menggunakan Kubernetes fitur taints and toleration untuk mengimplementasikannya.

Pod dengan sysctl unsafe akan gagal diluncurkan pada sembarang Node yang belum mengaktifkan kedua sysctl unsafe secara eksplisit. Seperti halnya sysctl node-level sangat disarankan untuk menggunakan fitur taints and toleration atau pencemaran dalam Node untuk Pod dalam Node yang tepat.

PodSecurityPolicy

Kamu selanjutnya dapat mengontrol sysctl mana saja yang dapat diatur dalam Pod dengan menentukan daftar sysctl atau pola (pattern) sysctl dalam forbiddenSysctls dan/atau field allowedUnsafeSysctls dari PodSecurityPolicy. Pola sysctl diakhiri dengan karakter *, seperti kernel.*. Karakter * saja akan mencakup semua sysctl.

Secara bawaan, semua sysctl safe diizinkan.

Kedua forbiddenSysctls dan allowedUnsafeSysctls merupakan daftar dari nama sysctl atau pola sysctl yang polos (yang diakhiri dengan karakter *). Karakter * saja berarti sesuai dengan semua sysctl.

Field forbiddenSysctls tidak memasukkan sysctl tertentu. Kamu dapat melarang kombinasi sysctl safe dan sysctl unsafe dalam daftar tersebut. Untuk melarang pengaturan sysctl, hanya gunakan * saja.

Jika kamu menyebutkan sysctl unsafe pada field allowedUnsafeSysctls dan tidak ada pada field forbiddenSysctls, maka sysctl dapat digunakan pada Pod dengan menggunakan PodSecurityPolicy ini. Untuk mengizinkan semua sysctl unsafe diatur dalam PodSecurityPolicy, gunakan karakter * saja.

Jangan mengonfigurasi kedua field ini sampai tumpang tindih, dimana sysctl yang diberikan akan diperbolehkan dan dilarang sekaligus.

Ini merupakan contoh sysctl unsafe yang diawali dengan kernel.msg yang diperbolehkan dan sysctl kernel.shm_rmid_forced yang dilarang.

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: sysctl-psp
spec:
  allowedUnsafeSysctls:
  - kernel.msg*
  forbiddenSysctls:
  - kernel.shm_rmid_forced
 ...

4.9 - Mengoperasikan klaster etcd untuk Kubernetes

etcd adalah penyimpanan key value konsisten yang digunakan sebagai penyimpanan data klaster Kubernetes.

Selalu perhatikan mekanisme untuk mem-backup data etcd pada klaster Kubernetes kamu. Untuk informasi lebih lanjut tentang etcd, lihat dokumentasi etcd.

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.

Prerequisites

  • Jalankan etcd sebagai klaster dimana anggotanya berjumlah ganjil.

  • Etcd adalah sistem terdistribusi berbasis leader. Pastikan leader secara berkala mengirimkan heartbeat dengan tepat waktu ke semua pengikutnya untuk menjaga kestabilan klaster.

  • Pastikan tidak terjadi kekurangan sumber daya.

    Kinerja dan stabilitas dari klaster sensitif terhadap jaringan dan IO disk. Kekurangan sumber daya apa pun dapat menyebabkan timeout dari heartbeat, yang menyebabkan ketidakstabilan klaster. Etcd yang tidak stabil mengindikasikan bahwa tidak ada leader yang terpilih. Dalam keadaan seperti itu, sebuah klaster tidak dapat membuat perubahan apa pun ke kondisi saat ini, yang menyebabkan tidak ada Pod baru yang dapat dijadwalkan.

  • Menjaga kestabilan klaster etcd sangat penting untuk stabilitas klaster Kubernetes. Karenanya, jalankan klaster etcd pada mesin khusus atau lingkungan terisolasi untuk persyaratan sumber daya terjamin.

  • Versi minimum yang disarankan untuk etcd yang dijalankan dalam lingkungan produksi adalah 3.2.10+.

Persyaratan sumber daya

Mengoperasikan etcd dengan sumber daya terbatas hanya cocok untuk tujuan pengujian. Untuk peluncuran dalam lingkungan produksi, diperlukan konfigurasi perangkat keras lanjutan. Sebelum meluncurkan etcd dalam produksi, lihat dokumentasi referensi persyaratan sumber daya.

Memulai Klaster etcd

Bagian ini mencakup bagaimana memulai klaster etcd dalam Node tunggal dan Node multipel.

Klaster etcd dalam Node tunggal

Gunakan Klaster etcd Node tunggal hanya untuk tujuan pengujian

  1. Jalankan perintah berikut ini:

    ./etcd --listen-client-urls=http://$PRIVATE_IP:2379 --advertise-client-urls=http://$PRIVATE_IP:2379
    
  2. Start server API Kubernetes dengan flag --etcd-servers=$PRIVATE_IP:2379.

    Ganti PRIVATE_IP dengan IP klien etcd kamu.

Klaster etcd dengan Node multipel

Untuk daya tahan dan ketersediaan tinggi, jalankan etcd sebagai klaster dengan Node multipel dalam lingkungan produksi dan cadangkan secara berkala. Sebuah klaster dengan lima anggota direkomendasikan dalam lingkungan produksi. Untuk informasi lebih lanjut, lihat Dokumentasi FAQ.

Mengkonfigurasi klaster etcd baik dengan informasi anggota statis atau dengan penemuan dinamis. Untuk informasi lebih lanjut tentang pengklasteran, lihat Dokumentasi pengklasteran etcd.

Sebagai contoh, tinjau sebuah klaster etcd dengan lima anggota yang berjalan dengan URL klien berikut: http://$IP1:2379, http://$IP2:2379, http://$IP3:2379, http://$IP4:2379, dan http://$IP5:2379. Untuk memulai server API Kubernetes:

  1. Jalankan perintah berikut ini:

    ./etcd --listen-client-urls=http://$IP1:2379, http://$IP2:2379, http://$IP3:2379, http://$IP4:2379, http://$IP5:2379 --advertise-client-urls=http://$IP1:2379, http://$IP2:2379, http://$IP3:2379, http://$IP4:2379, http://$IP5:2379
    
  2. Start server Kubernetes API dengan flag --etcd-servers=$IP1:2379, $IP2:2379, $IP3:2379, $IP4:2379, $IP5:2379.

    Ganti IP dengan alamat IP klien kamu.

Klaster etcd dengan Node multipel dengan load balancer

Untuk menjalankan penyeimbangan beban (load balancing) untuk klaster etcd:

  1. Siapkan sebuah klaster etcd.
  2. Konfigurasikan sebuah load balancer di depan klaster etcd. Sebagai contoh, anggap saja alamat load balancer adalah $LB.
  3. Mulai Server API Kubernetes dengan flag --etcd-servers=$LB:2379.

Mengamankan klaster etcd

Akses ke etcd setara dengan izin root pada klaster sehingga idealnya hanya server API yang memiliki akses ke etcd. Dengan pertimbangan sensitivitas data, disarankan untuk memberikan izin hanya kepada Node-Node yang membutuhkan akses ke klaster etcd.

Untuk mengamankan etcd, tetapkan aturan firewall atau gunakan fitur keamanan yang disediakan oleh etcd. Fitur keamanan etcd tergantung pada Infrastruktur Kunci Publik / Public Key Infrastructure (PKI) x509. Untuk memulai, buat saluran komunikasi yang aman dengan menghasilkan pasangan kunci dan sertifikat. Sebagai contoh, gunakan pasangan kunci peer.key dan peer.cert untuk mengamankan komunikasi antara anggota etcd, dan client.key dan client.cert untuk mengamankan komunikasi antara etcd dan kliennya. Lihat contoh skrip yang disediakan oleh proyek etcd untuk menghasilkan pasangan kunci dan berkas CA untuk otentikasi klien.

Mengamankan komunikasi

Untuk mengonfigurasi etcd dengan secure peer communication, tentukan flag --peer-key-file=peer.key dan --peer-cert-file=peer.cert, dan gunakan https sebagai skema URL.

Demikian pula, untuk mengonfigurasi etcd dengan secure client communication, tentukan flag --key-file=k8sclient.key dan --cert-file=k8sclient.cert, dan gunakan https sebagai skema URL.

Membatasi akses klaster etcd

Setelah konfigurasi komunikasi aman, batasi akses klaster etcd hanya ke server API Kubernetes. Gunakan otentikasi TLS untuk melakukannya.

Sebagai contoh, anggap pasangan kunci k8sclient.key dan k8sclient.cert dipercaya oleh CA etcd.ca. Ketika etcd dikonfigurasi dengan --client-cert-auth bersama dengan TLS, etcd memverifikasi sertifikat dari klien dengan menggunakan CA dari sistem atau CA yang dilewati oleh flag --trusted-ca-file. Menentukan flag --client-cert-auth=true dan --trusted-ca-file=etcd.ca akan membatasi akses kepada klien yang mempunyai sertifikat k8sclient.cert.

Setelah etcd dikonfigurasi dengan benar, hanya klien dengan sertifikat yang valid dapat mengaksesnya. Untuk memberikan akses kepada server Kubernetes API, konfigurasikan dengan flag --etcd-certfile=k8sclient.cert,--etcd-keyfile=k8sclient.key dan --etcd-cafile=ca.cert.

Mengganti anggota etcd yang gagal

Etcd klaster mencapai ketersediaan tinggi dengan mentolerir kegagalan dari sebagian kecil anggota. Namun, untuk meningkatkan kesehatan keseluruhan dari klaster, segera ganti anggota yang gagal. Ketika banyak anggota yang gagal, gantilah satu per satu. Mengganti anggota yang gagal melibatkan dua langkah: menghapus anggota yang gagal dan menambahkan anggota baru.

Meskipun etcd menyimpan ID anggota unik secara internal, disarankan untuk menggunakan nama unik untuk setiap anggota untuk menghindari kesalahan manusia. Sebagai contoh, sebuah klaster etcd dengan tiga anggota. Jadikan URL-nya, member1=http://10.0.0.1, member2=http://10.0.0.2, and member3=http://10.0.0.3. Ketika member1 gagal, ganti dengan member4=http://10.0.0.4.

  1. Dapatkan ID anggota yang gagal dari member1:

    etcdctl --endpoints=http://10.0.0.2,http://10.0.0.3 member list

    Akan tampil pesan berikut:

     8211f1d0f64f3269, started, member1, http://10.0.0.1:2380, http://10.0.0.1:2379
     91bc3c398fb3c146, started, member2, http://10.0.0.2:2380, http://10.0.0.2:2379
     fd422379fda50e48, started, member3, http://10.0.0.3:2380, http://10.0.0.3:2379
    
  2. Hapus anggota yang gagal:

    etcdctl member remove 8211f1d0f64f3269

    Akan tampil pesan berikut:

    Removed member 8211f1d0f64f3269 from cluster
    
  3. Tambahkan anggota baru:

    ./etcdctl member add member4 --peer-urls=http://10.0.0.4:2380

    Akan tampil pesan berikut:

    Member 2be1eb8f84b7f63e added to cluster ef37ad9dc622a7c4
    
  4. Jalankan anggota yang baru ditambahkan pada mesin dengan IP 10.0.0.4:

     export ETCD_NAME="member4"
     export ETCD_INITIAL_CLUSTER="member2=http://10.0.0.2:2380,member3=http://10.0.0.3:2380,member4=http://10.0.0.4:2380"
     export ETCD_INITIAL_CLUSTER_STATE=existing
     etcd [flags]
    
  5. Lakukan salah satu dari yang berikut:

    1. Perbarui flag --etcd-server untuk membuat Kubernetes mengetahui perubahan konfigurasi, lalu start ulang server API Kubernetes.
    2. Perbarui konfigurasi load balancer jika load balancer digunakan dalam Deployment.

Untuk informasi lebih lanjut tentang konfigurasi ulang klaster, lihat Dokumentasi Konfigurasi etcd.

Mencadangkan klaster etcd

Semua objek Kubernetes disimpan dalam etcd. Mencadangkan secara berkala data klaster etcd penting untuk memulihkan klaster Kubernetes di bawah skenario bencana, seperti kehilangan semua Node control plane. Berkas snapshot berisi semua status Kubernetes dan informasi penting. Untuk menjaga data Kubernetes yang sensitif aman, enkripsi berkas snapshot.

Mencadangkan klaster etcd dapat dilakukan dengan dua cara: snapshot etcd bawaan dan snapshot volume.

Snapshot bawaan

Fitur snapshot didukung oleh etcd secara bawaan, jadi mencadangkan klaster etcd lebih mudah. Snapshot dapat diambil dari anggota langsung dengan command etcdctl snapshot save atau dengan menyalin member/snap/db berkas dari etcd direktori data yang saat ini tidak digunakan oleh proses etcd. Mengambil snapshot biasanya tidak akan mempengaruhi kinerja anggota.

Di bawah ini adalah contoh untuk mengambil snapshot dari keyspace yang dilayani oleh $ENDPOINT ke berkas snapshotdb:

ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save snapshotdb
# keluar 0

# memverifikasi hasil snapshot
ETCDCTL_API=3 etcdctl --write-out=table snapshot status snapshotdb
+----------+----------+------------+------------+
|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| fe01cf57 |       10 |          7 | 2.1 MB     |
+----------+----------+------------+------------+

Snapshot volume

Jika etcd berjalan pada volume penyimpanan yang mendukung cadangan, seperti Amazon Elastic Block Store, buat cadangan data etcd dengan mengambil snapshot dari volume penyimpanan.

Memperbesar skala dari klaster etcd

Peningkatan skala klaster etcd meningkatkan ketersediaan dengan menukarnya untuk kinerja. Penyekalaan tidak akan meningkatkan kinerja atau kemampuan klaster. Aturan umum adalah untuk tidak melakukan penyekalaan naik atau turun untuk klaster etcd. Jangan mengonfigurasi grup penyekalaan otomatis untuk klaster etcd. Sangat disarankan untuk selalu menjalankan klaster etcd statis dengan lima anggota untuk klaster produksi Kubernetes untuk setiap skala yang didukung secara resmi.

Penyekalaan yang wajar adalah untuk meningkatkan klaster dengan tiga anggota menjadi dengan lima anggota, ketika dibutuhkan lebih banyak keandalan. Lihat Dokumentasi Rekonfigurasi etcd untuk informasi tentang cara menambahkan anggota ke klaster yang ada.

Memulihkan klaster etcd

Etcd mendukung pemulihan dari snapshot yang diambil dari proses etcd dari versi major.minor. Memulihkan versi dari versi patch lain dari etcd juga didukung. Operasi pemulihan digunakan untuk memulihkan data klaster yang gagal.

Sebelum memulai operasi pemulihan, berkas snapshot harus ada. Ini bisa berupa berkas snapshot dari operasi pencadangan sebelumnya, atau dari sisa direktori data. Untuk informasi dan contoh lebih lanjut tentang memulihkan klaster dari berkas snapshot, lihat dokumentasi pemulihan bencana etcd.

Jika akses URL dari klaster yang dipulihkan berubah dari klaster sebelumnya, maka server API Kubernetes harus dikonfigurasi ulang sesuai dengan URL tersebut. Pada kasus ini, start kembali server API Kubernetes dengan flag --etcd-servers=$NEW_ETCD_CLUSTER bukan flag --etcd-servers=$OLD_ETCD_CLUSTER. Ganti $NEW_ETCD_CLUSTER dan $OLD_ETCD_CLUSTER dengan alamat IP masing-masing. Jika load balancer digunakan di depan klaster etcd, kamu mungkin hanya perlu memperbarui load balancer sebagai gantinya.

Jika mayoritas anggota etcd telah gagal secara permanen, klaster etcd dianggap gagal. Dalam skenario ini, Kubernetes tidak dapat membuat perubahan apa pun ke kondisi saat ini. Meskipun Pod terjadwal mungkin terus berjalan, tidak ada Pod baru yang bisa dijadwalkan. Dalam kasus seperti itu, pulihkan klaster etcd dan kemungkinan juga untuk mengonfigurasi ulang server API Kubernetes untuk memperbaiki masalah ini.

Memutakhirkan dan memutar balikan klaster etcd

Pada Kubernetes v1.13.0, etcd2 tidak lagi didukung sebagai backend penyimpanan untuk klaster Kubernetes baru atau yang sudah ada. Timeline untuk dukungan Kubernetes untuk etcd2 dan etcd3 adalah sebagai berikut:

  • Kubernetes v1.0: hanya etcd2
  • Kubernetes v1.5.1: dukungan etcd3 ditambahkan, standar klaster baru yang dibuat masih ke etcd2
  • Kubernetes v1.6.0: standar klaster baru yang dibuat dengan kube-up.sh adalah etcd3, dan kube-apiserver standarnya ke etcd3
  • Kubernetes v1.9.0: pengumuman penghentian backend penyimpanan etcd2 diumumkan
  • Kubernetes v1.13.0: backend penyimpanan etcd2 dihapus, kube-apiserver akan menolak untuk start dengan --storage-backend=etcd2, dengan pesan etcd2 is no longer a supported storage backend

Sebelum memutakhirkan v1.12.x kube-apiserver menggunakan --storage-backend=etcd2 ke v1.13.x, data etcd v2 harus dimigrasikan ke backend penyimpanan v3 dan permintaan kube-apiserver harus diubah untuk menggunakan --storage-backend=etcd3.

Proses untuk bermigrasi dari etcd2 ke etcd3 sangat tergantung pada bagaimana klaster etcd diluncurkan dan dikonfigurasi, serta bagaimana klaster Kubernetes diluncurkan dan dikonfigurasi. Kami menyarankan kamu berkonsultasi dengan dokumentasi penyedia kluster kamu untuk melihat apakah ada solusi yang telah ditentukan.

Jika klaster kamu dibuat melalui kube-up.sh dan masih menggunakan etcd2 sebagai penyimpanan backend, silakan baca Kubernetes v1.12 etcd cluster upgrade docs

Masalah umum: penyeimbang klien etcd dengan secure endpoint

Klien etcd v3, dirilis pada etcd v3.3.13 atau sebelumnya, memiliki critical bug yang mempengaruhi kube-apiserver dan penyebaran HA. Pemindahan kegagalan (failover) penyeimbang klien etcd tidak bekerja dengan baik dengan secure endpoint. Sebagai hasilnya, server etcd boleh gagal atau terputus sesaat dari kube-apiserver. Hal ini mempengaruhi peluncuran HA dari kube-apiserver.

Perbaikan dibuat di etcd v3.4 (dan di-backport ke v3.3.14 atau yang lebih baru): klien baru sekarang membuat bundel kredensial sendiri untuk menetapkan target otoritas dengan benar dalam fungsi dial.

Karena perbaikan tersebut memerlukan pemutakhiran dependensi dari gRPC (ke v1.23.0), downstream Kubernetes tidak mendukung upgrade etcd, yang berarti perbaikan etcd di kube-apiserver hanya tersedia mulai Kubernetes 1.16.

Untuk segera memperbaiki celah keamanan (bug) ini untuk Kubernetes 1.15 atau sebelumnya, buat kube-apiserver khusus. kamu dapat membuat perubahan lokal ke vendor/google.golang.org/grpc/credentials/credentials.go dengan etcd@db61ee106.

Lihat "kube-apiserver 1.13.x menolak untuk bekerja ketika server etcd pertama tidak tersedia".

5 - Mengelola Objek Kubernetes

Paradigma deklaratif dan imperatif untuk berinteraksi dengan API Kubernetes.

5.1 - Pengelolaan Objek Kubernetes secara Deklaratif dengan Menggunakan Berkas Konfigurasi

Objek-objek Kubernetes dapat dibuat, diperbarui, dan dihapus dengan menjalankan perintah kubectl apply terhadap file-file konfigurasi objek yang disimpan dalam sebuah direktori secara rekursif sesuai dengan kebutuhan. Perintah kubectl diff bisa digunakan untuk menampilkan pratinjau tentang perubahan apa saja yang akan dibuat oleh perintah kubectil apply.

Kelebihan dan kekurangan

Perintah kubectl memungkinkan tiga cara untuk mengelola objek:

  • Perintah imperatif
  • Konfigurasi objek imperatif
  • Konfigurasi objek deklaratif

Lihat Pengelolaan Objek Kubernetes untuk menyimak diskusi mengenai kelebihan dan kekurangan dari tiap cara pengelolaan objek.

Sebelum kamu mulai

Konfigurasi objek secara deklaratif membutuhkan pemahaman yang baik tentang definisi dan konfigurasi objek-objek Kubernetes. Jika belum pernah, kamu disarankan untuk membaca terlebih dulu dokumen-dokumen berikut:

Berikut adalah beberapa defnisi dari istilah-istilah yang digunakan dalam dokumen ini:

  • objek berkas konfigurasi / berkas konfigurasi: Sebuah file yang mendefinisikan konfigurasi untuk sebuah objek Kubernetes. Dokumen ini akan memperlihatkan cara menggunakan file konfigurasi dengan perintah kubectl apply. File-file konfigurasi biasanya disimpan di sebuah source control seperti Git.
  • konfigurasi objek live / konfigurasi live: nilai konfigurasi live dari sebuah objek, sebagaimana yang tersimpan di klaster Kubernetes. Nilai-nilai ini disimpan di storage klaster Kubernetes, biasanya etcd.
  • writer konfigurasi deklaratif / writer deklaratif: Seseorang atau sebuah komponen perangkat lunak yang membuat pembaruan ke objek live. Live writer yang disebut pada dokumen ini adalah writer yang membuat perubahan terhadap file konfigurasi objek dan menjalankan perintah kubectl apply untuk menulis perubahan-perubahan tersebut.

Cara membuat objek

Gunakan perintah kubectl apply untuk membuat semua objek, kecuali objek-objek yang sudah ada sebelumnya, yang didefinisikan di file-file konfigurasi dalam direktori yang ditentukan:

kubectl apply -f <directory>/

Perintah di atas akan memberi anotasi kubectl.kubernetes.io/last-applied-configuration: '{...}' pada setiap objek yang dibuat. Anotasi ini berisi konten dari file konfigurasi objek yang digunakan untuk membuat objek tersebut.

Berikut sebuah contoh file konfigurasi objek:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Jalankan perintah kubectl diff untuk menampilkan objek yang akan dibuat:

kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml

Buat objek dengan perintah kubectl apply:

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

Tampilkan konfigurasi live dengan perintah kubectl get:

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

Keluaran perintah di atas akan menunjukkan bahwa anotasi kubectl.kubernetes.io/last-applied-configuration sudah dituliskan ke konfigurasi live, dan anotasi tersebut sesuai dengan file konfigurasi:

kind: Deployment
metadata:
  annotations:
    # ...
    # Ini merupakan representasi dari simple_deployment.yaml dalam format json
    # Ini ditulis oleh perintah `kubectl apply` ketika objek dibuat
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.7.9
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

Cara memperbarui objek

Kamu juga bisa menggunakan kubectl apply untuk memperbarui semua objek yang didefinisikan dalam sebuah direktori, termasuk objek-objek yang sudah ada sebelumnya. Cara ini akan melakukan hal-hal berikut:

  1. Menyimpan nilai field-field yang ada di file konfigurasi ke konfigurasi live.
  2. Menghapus field-field yang dihapus di file konfigurasi dari konfigurasi live.
kubectl diff -f <directory>/
kubectl apply -f <directory>/

Berikut sebuah contoh file konfigurasi:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Buat objek dengan perintah kubectl apply::

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

Tampilkan konfigurasi live dengan perintah kubectl get:

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

Keluaran perintah di atas akan menunjukkan bahwa anotasi kubectl.kubernetes.io/last-applied-configuration sudah dituliskan ke konfigurasi live, dan anotasi tersebut sesuai dengan file konfigurasi:

kind: Deployment
metadata:
  annotations:
    # ...
    # Berikut merupakan representasi dari simple_deployment.yaml dalam format json
    # Representasi berikut ditulis oleh perintah kubectl apply ketika objek dibuat
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.7.9
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

Perbarui nilai replicas secara langsung di konfigurasi live dengan menggunakan perintah kubectl scale. Pembaruan ini tidak menggunakan perintah kubectl apply:

kubectl scale deployment/nginx-deployment --replicas=2

Tampilkan konfigurasi live dengan perintah kubectl get:

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

Keluaran perintah di atas akan menunjukkan bahwa nilai replicas telah diubah menjadi 2, dan anotasi last-applied-configuration tidak memuat nilai replicas:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # perhatikan bahwa anotasi tidak memuat nilai replicas
    # karena nilai tersebut tidak diperbarui melalui perintah kubectl-apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  replicas: 2 # ditulis oleh perintah kubectl scale
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.7.9
        # ...
        name: nginx
        ports:
        - containerPort: 80
      # ...

Perbarui file konfigurasi simple_deployment.yaml, ubah image dari nginx:1.7.9 ke nginx:1.11.9, dan hapus field minReadySeconds:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.11.9 # perbarui image
        ports:
        - containerPort: 80

Terapkan perubahan yang telah dibuat di file konfigurasi:

kubectl diff -f https://k8s.io/examples/application/update_deployment.yaml
kubectl apply -f https://k8s.io/examples/application/update_deployment.yaml

Tampilkan konfigurasi live dengan perintah kubectl get:

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

Keluaran perintah di atas akan menunjukkan perubahan-perubahan berikut pada konfiguasi live:

  • Field replicas tetap bernilai 2 sesuai dengan nilai yang diatur oleh perintah kubectl scale. Hal ini karena field replicas dihapuskan dari file konfigurasi.
  • Nilai field image telah diperbarui menjadi nginx:1.11.9 dari nginx:1.7.9.
  • Anotasi last-applied-configuration telah diperbari dengan image terbaru.
  • Field minReadySeconds telah dihapus.
  • Anotasi last-applied-configuration tidak lagi memuat field minReadySeconds.
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # Anotasi memuat image yang telah diperbarui ke nginx 1.11.9,
    # tetapi tidak memuat nilai replica yang telah diperbarui menjadi 2
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.11.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
    # ...
spec:
  replicas: 2 # Diatur oleh `kubectl scale`, tidak diubah oleh `kubectl apply`.
  # minReadySeconds dihapuskan oleh `kubectl apply`
  # ...
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.11.9 # Diatur oleh `kubectl apply`
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

Cara menghapus objek

Ada dua cara untuk menghapus objek-objek yang dikelola dengan kubectl apply.

Rekomendasi: kubectl delete -f <filename>

Penghapusan objek secara manual dengan menggunakan perintah imperatif merupakan cara yang direkomendasikan karena lebih eksplisit dalam menentukan objek apa yang akan dihapus dan lebih kecil kemungkinannya untuk pengguna menghapus objek lain secara tidak sengaja:

kubectl delete -f <filename>

Alternatif: kubectl apply -f <directory/> --prune -l your=label

Lakukan ini hanya jika kamu benar-benar mengetahui apa yang kamu lakukan.

Sebagai alternatif dari kubectl delete, kamu bisa menggunakan kubectl apply untuk mengidentifikasi objek-objek yang hendak dihapus setelah berkas konfigurasi objek-objek tersebut dihapus dari direktori. Ketika dijalankan dengan argumen --prune, perintah kubectl apply akan melakukan query ke API server untuk mencari semua objek yang sesuai dengan himpunan label-label tertentu, dan berusaha untuk mencocokkan kofigurasi objek live yg diperoleh terhadap file konfigurasi objek. Jika sebuah objek cocok dengan query yang dilakukan, dan objek tersebut tidak memiliki file konfigurasi di direktori serta tidak memiliki anotasi last-applied-configuration, objek tersebut akan dihapus.

kubectl apply -f <directory/> --prune -l <labels>

Cara melihat objek

Kamu bisa menggunakan perintah kubectl get dengan parameter -o yaml untuk melihat konfigurasi dari sebuah objek live:

kubectl get -f <filename|url> -o yaml

Cara kubectl apply menghitung perbedaan dan menggabungkan perubahan

Ketika memperbarui konfigurasi live dari sebuah objek, kubectl apply melakukannya dengan mengirimkan request untuk melakukan patch ke API server. Patch mendefinisikan pembaruan-pembaruan yang likungpnya sepsifik terhadap sejumlah field dari objek konfigurasi live. Perintah kubectl apply menghitung patch request ini menggunakan file konfigurasi, konfigurasi live, dan anotasi last-applied-configuration yang tersimpan di konfigurasi live.

Perhitungan penggabungan patch

Perintah kubectl apply menulis konten dari berkas konfigurasi ke anotasi kubectl.kubernetes.io/last-applied-configuration. Ini digunakan untuk mengidentifikasi field apa saja yang telah dihapus dari file konfigurasi dan perlu dihapus dari konfigurasi live. Berikut adalah langkah-langkah yang digunakan untuk menghitung field apa saja yang harus dihapus atau diubah:

  1. Hitung field-field yang perlu dihapus. Ini mencakup field-field yang ada di last-applied-configuration tapi tidak ada di file konfigurasi.
  2. Hitung field-field yang perlu ditambah atau diubah. Ini mencakup field-field yang ada di file konfigurasi yang nilainya tidak sama dengan konfigurasi live.

Agar lebih jelas, simak contoh berikut. Misalkan, berikut adalah file konfigurasi untuk sebuah objek Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.11.9 # perbarui image
        ports:
        - containerPort: 80

Juga, misalkan, berikut adalah konfigurasi live dari objek Deployment yang sama:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # perhatikan bagaimana anotasi berikut tidak memuat replicas
    # karena replicas tidak diperbarui melalui perintah kubectl apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  replicas: 2 # ditulis oleh perintah kubectl scale
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.7.9
        # ...
        name: nginx
        ports:
        - containerPort: 80
      # ...

Berikut merupakan perhitungan penggabungan yang akan dilakukan oleh perintah kubectl apply:

  1. Hitung semua field yang akan dihapus dengan membaca nilai dari last-applied-configuration dan membandingkannya dengan nilai yang ada di file konfigurasi. Hapus semua field yang nilainya secara eksplisit diubah menjadi null pada file konfigurasi objek lokal terlepas dari apakah field-field tersebut ada di anotasi last-applied-configuration atau tidak. Pada contoh di atas, field minReadySeconds muncul pada anotasi last-applied-configuration, tapi tidak ada di file konfigurasi. Aksi: Hapus minReadySeconds dari konfigurasi live.
  2. Hitung semua field yang akan diubah dengan membaca nilai-nilai dari file konfigurasi dan membandingkannya dengan nilai-nilai yang ada di konfigurasi live. Pada contoh ini, nilai dari field image di file konfigurasi tidak sama dengan nilai dari konfigurasi live. Aksi: Ubah nilai image pada konfigurasi live.
  3. Ubah anotasi last-applied-configuration agar sesuai dengan nilai yang ada di file konfigurasi.
  4. Gabungkan hasil-hasil dari langkah 1, 2, dan 3 ke dalam satu patch request ke API server.

Berikut konfigurasi live yang dihasilkan oleh proses penggabungan pada contoh di atas:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # Anotasi memuat pembaruan image menjadi nginx 1.11.9,
    # tetapi tidak memuat pembaruan replicas menjadi 2
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.11.9","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
    # ...
spec:
  selector:
    matchLabels:
      # ...
      app: nginx
  replicas: 2 # Diubah oleh `kubectl scale`, tidak diubah oleh `kubectl apply`.
  # minReadySeconds dihapus oleh `kubectl apply`
  # ...
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.11.9 # Diubah oleh `kubectl apply`
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

Cara penggabungan tipe-tipe field yang berbeda

Cara sebuah field terentu dalam sebuah file konfigurasi digabungkan dengan konfigurasi live bergantung pada tipe field tersebut. Ada beberapa tipe field:

  • primitif: field yang bertipe string, integer, atau boolean. Sebagai contoh, image dan replicas termasuk sebagai field primitif. Aksi: Replace.

  • map, atau objek: field yang bertipe map atau tipe kompleks yang mengandung sub field. Sebagai contoh, labels, annotations, spec, dan metadata termasuk sebagai map. Aksi: Lakukan penggabungan tiap-tiap elemen atau sub field.

  • list: field yang berisi sejumlah item yang tiap itemnya bisa berupa tipe primitif maupun map. Sebagai contoh, containers, ports, dan args termasuk sebagai list. Aksi: Bervariasi.

Ketika digunakan untuk memperbarui sebuah field bertipe map atau list, perintah kubectl apply memperbarui nilai tiap-tiap sub elemen ketimbang mengganti nilai semua field. Misalnya, ketika menggabungkan field spec pada sebuah Deployment, bukan keseluruhan field spec yang diubah nilainya. Alih-alih, sub field dari spec seperti replicas yang kemudian dibandingkan nilainya dan digabungkan.

Menggabungkan perubahan pada field primitif

Field primitif diganti nilainya atau dihapus sama sekali.

Field pada file konfigurasi objek Field pada objek konfigurasi live Field pada last-applied-configuration Aksi
Ya Ya - Ubah nilai di konfigurasi live mengikuti nilai pada file konfigurasi.
Ya Tidak - Ubah nilai di konfigurasi live mengikuti nilai pada konfigurasi lokal.
Tidak - Ya Hapus dari konfigurasi live.
Tidak - Tidak Tidak melakukan apa-apa, pertahankan nilai konfigurasi live.

Menggabungkan perubahan pada field bertipe map

Field yang bertipe map digabungkan dengan membandingkan tiap sub field atau elemen dari map:

Key pada file konfigurasi objek Key pada objek konfigurasi live Field pada last-applied-configuration Aksi
Ya Ya - Bandingkan nilai tiap sub field.
Ya Tidak - Ubah nilai pada konfigurasi live mengikuti nilai pada konfigurasi lokal.
Tidak - Ya Hapus dari konfigurasi live.
Tidak - Tidak Tidak melakukan apa-apa, pertahankan nilai konfigurasi live.

Menggabungkan perubahan pada field yang bertipe list

Penggabungan perubahan pada sebuah list bisa menggunakan salah satu dari tiga strategi:

  • Ganti nilai keseluruhan list.
  • Gabungkan nilai tiap-tiap elemen di dalam sebuah list yang elemennya kompleks.
  • Gabungkan list yang elemennya primitif.

Pilihan strategi dibuat berbeda-beda bergantung tipe tiap field.

Ganti nilai keseluruhan list

Perlakukan list sama dengan field primitif. Ganti atau hapus keseluruhan list. Ini akan menjaga urutan dari list.

Contoh: Gunakan kubectl apply untuk memperbarui field args pada sebuah kontainer di dalam sebuah pod. Ini akan mengubah nilai args di konfigurasi live mengikuti nilai di file konfigurasi. Elemen args apapun yang sebelumnya ditambahkan ke konfigurasi live akan hilang. Urutan dari elemen-elemen args yang didefinisikan di file konfigurasi akan dipertahankan ketika ditulis ke konfigurasi live.

# nilai last-applied-configuration*
    args: ["a", "b"]

# nilai berkas konfigurasi
    args: ["a", "c"]

# nilai konfigurasi live
    args: ["a", "b", "d"]

# hasil setelah penggabungan
    args: ["a", "c"]

Penjelasan: Penggabungan menggunakan nilai pada file konfigurasi sebagai nilai baru untuk list args.

Menggabungkan tiap-tiap elemen dari sebuah list dengan elemen kompleks:

Perlakukan list selayaknya sebuah map, perlakukan field spesifik dari tiap element sebagai sebuah key. Tambah, hapus, atau perbarui tiap-tiap elemen. Operasi ini tidak mempertahankan urutan elemen di dalam list.

Strategi penggabungan ini menggunakan tag khusus patchMergeKey pada tiap field. Tag patchMergeKey didefinisikan untuk tiap field pada source code Kubernetes: types.go. Ketika menggabungkan sebuah list yang berisi map, field yang dispesifikasikan sebagai patchMergeKey untuk tiap elemen digunakan sebagai map key untuk elemen tersebut.

Contoh: Gunakan kubectl apply untuk memperbarui field containers pada sebuah PodSpec. Perintah ini akan menggabungkan list containers seolah-olah list tersebut adalah sebuah map dan tiap elemennya menggunakan name sebagai key.

# nilai last-applied-configuration
    containers:
    - name: nginx
      image: nginx:1.10
    - name: nginx-helper-a # key: nginx-helper-a; akan dihapus pada hasil akhir
      image: helper:1.3
    - name: nginx-helper-b # key: nginx-helper-b; akan dipertahankan pada hasil akhir
      image: helper:1.3

# nilai berkas konfigurasi
    containers:
    - name: nginx
      image: nginx:1.10
    - name: nginx-helper-b
      image: helper:1.3
    - name: nginx-helper-c # key: nginx-helper-c; akan ditambahkan pada hasil akhir
      image: helper:1.3

# konfigurasi live
    containers:
    - name: nginx
      image: nginx:1.10
    - name: nginx-helper-a
      image: helper:1.3
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"] # Field ini akan dipertahankan pada hasil akhir
    - name: nginx-helper-d # key: nginx-helper-d; akan dipertahankan pada hasil akhir
      image: helper:1.3

# hasil akhir setelah penggabungan
    containers:
    - name: nginx
      image: nginx:1.10
      # Elemen nginx-helper-a dihapus
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"] # Field dipertahankan
    - name: nginx-helper-c # Elemen ditambahkan
      image: helper:1.3
    - name: nginx-helper-d # Elemen tidak diubah
      image: helper:1.3

Penjelasan:

  • Kontainer dengan nama "nginx-helper-a" dihapus karena tidak ada kontainer dengan nama tersebut di file konfigurasi.
  • Kontainer dengan nama "nginx-helper-b" tetap mempertahankan nilai args pada konfigurasi live. Perintah kubectl apply bisa mengenali bahwa "nginx-helper-b" di konfigurasi live sama dengan "ngnix-helper-b" di file konfigurasi, meskipun keduanya memiliki field yang berbeda (tidak ada args pada file konfigurasi). Ini karena nilai patchMergeKey di kedua konfigurasi identik.
  • Kontainer dengan nama "nginx-helper-c" ditambahkan karena tidak ada kontainer dengan nama tersebut di konfigurasi live, tapi ada di file konfigurasi.
  • Kontainer dengan nama "nginx-helper-d" dipertahankan karena tidak ada elemen dengan nama tersebut pada last-applied-configuration.

Menggabungkan sebuah list dengan elemen-elemen primitif

Pada versi Kubernetes 1.5, penggabungan list dengan elemen-elemen primitif tidak lagi didukung.

Nilai default dari sebuah field

API server mengisi field tertentu dengan nilai default pada konfigurasi live jika nilai field-field tersebut tidak dispesifikasikan ketika objek dibuat.

Berikut adalah sebuah file konfigurasi untuk sebuah Deployment. Berkas berikut tidak menspesifikasikan strategy:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Buat objek dengan perintah kubectl apply:

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

Tampilkan konfigurasi live dengan perintah kubectl get:

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

Keluaran dari perintah tadi menunjukkan bahwa API server mengisi beberapa field dengan nilai default pada konfigurasi live. Field-field berikut tidak dispesifikan pada file konfigurasi.

apiVersion: apps/v1
kind: Deployment
# ...
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  replicas: 1 # nilai default dari apiserver
  strategy:
    rollingUpdate: # nilai default dari apiserver - diturunkan dari strategy.type
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate # nilai default dari apiserver
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.7.9
        imagePullPolicy: IfNotPresent # nilai default dari apiserver
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP # nilai default dari apiserver
        resources: {} # nilai default dari apiserver
        terminationMessagePath: /dev/termination-log # nilai default dari apiserver
      dnsPolicy: ClusterFirst # nilai default dari apiserver
      restartPolicy: Always # nilai default dari apiserver
      securityContext: {} # nilai default dari apiserver
      terminationGracePeriodSeconds: 30 # nilai default dari apiserver
# ...

Dalam sebuah patch request, field-field dengan nilai default tidak diisi kembali dengan nilai default kecuali secara eksplisit nilainya dihapuskan sebagai bagian dari patch request. Ini bisa menimbulkan hasil yang tak terduga jika sebagian field diisi dengan nilai default yang diturunkan dari nilai field lainnya. Ketika field lain tersebut nilainya diubah, field-field yang diisi dengan nilai default berdasarkan field yang berubah tadi tidak akan diperbarui kecuali secara eksplisit dihapus.

Oleh karena itu, beberapa field yang nilainya diisi secara default oleh server perlu didefinisikan secara eksplisit di file konfigurasi, meskipun nilai yang diinginkan sudah sesuai dengan nilai default dari server. Ini untuk mempermudah mengenali nilai-nilai yang berselisih yang tidak akan diisi dengan nilai default oleh server.

Contoh:

# last-applied-configuration
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

# berkas konfigurasi
spec:
  strategy:
    type: Recreate # nilai yang diperbarui
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

# konfigurasi live
spec:
  strategy:
    type: RollingUpdate # nilai default
    rollingUpdate: # nilai default yang diturunkan dari type
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

# hasil setelah penggabungan - ERROR!
spec:
  strategy:
    type: Recreate # nilai yang diperbarui: tidak kompatibel dengan field rollingUpdate
    rollingUpdate: # nilai default: tidak kompatibel dengan "type: Recreate"
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Penjelasan:

  1. Pengguna sebelumnya sudah membuat sebuah Deployment tanpa mendefinisikan strategy.type (seperti yang bisa dilihat pada last-applied-configuration).
  2. Server mengisi strategy.type dengan nilai default RollingUpdate dan mengisi strategy.rollingUpdate dengan nilai default pada konfigurasi live.
  3. Pengguna mengubah nilai field strategy.type menjadi Recreate pada file konfigurasi. Nilai strategy.rollingUpdate tidak berubah dari nilai default, meskipun server sekarang berekspektasi nilai tersebut dihapus. Jika nilai strategy.rollingUpdate didefinisikan di awal pada file konfigurasi, akan jelas bagi server bahwa field tersebut perlu dihapus.
  4. Perintah kubect apply gagal karena strategy.rollingUpdate tidak dihapus. Field strategy.rollingUpdate tidak bisa didefinisikan jika field strategy.type berisi Recreate.

Rekomendasi: Field-field ini harus didefinisikan secara eksplisit di file konfigurasi objek:

  • Label Selectors dan PodTemplate pada workloads, misalnya Deployment, StatefulSet, Job, DaemonSet, ReplicaSet, dan ReplicationController
  • Strategi Deployment rollout

Cara menghilangkan field-field yang diisi dengan nilai default atau diisi oleh writer lainnya

Field-field yang tidak muncul di file konfigurasi bisa dihilangkan dengan mengisi nilainya dengan null dan kemudian jalankan kubectl apply dengan file konfigurasi tersebut. Untuk field-field yang nilainya diisi dengan nilai default oleh server, aksi ini akan mmenyebabkan pengisian ulang field dengan nilai default.

Cara mengubah kepemilikan sebuah field antara file konfigurasi dan writer imperatif

Hanya metode-metode berikut yang bisa kamu gunakan untuk mengubah satu field objek:

  • Gunakan kubectl apply.
  • Tulis secara langsung ke konfigurasi live tanpa memodifikasi file konfigurasi: misalnya, dengan perintah kubectl scale.

Mengubah kepemilikan dari writer imperatif ke file konfigurasi

Tambahkan field ke file konfigurasi. Hentikan pembaruan secara langsung ke konfigurasi live tanpa melalui kubectl apply.

Mengubah kepemilikan dari file konfigurasi ke writer imperatif

Pada versi Kubernetes 1.5, mengubah kepemilikan sebuah field dari file konfigurasi memerlukan langkah-langkah manual:

  • Hapus field dari file konfigurasi.
  • Hapus field dari anotasi kubectl.kubernetes.io/last-applied-configuration pada objek live.

Mengubah metode-metode pengelolaan objek

Objek-objek Kubernetes sebaiknya dikelola dengan satu metode dalam satu waktu. Berpindah dari satu metode ke metode lain dimungkinkan, tetapi memerlukan proses manual.

Migrasi dari pengelolaan dengan perintah imperatif ke konfigurasi objek deklaratif

Migrasi dari pengelolaan objek dengan perintah imperatif ke pengelolaan objek dengan konfigurasi deklaratif memerlukan beberapa langkah manual:

  1. Ekspor objek live ke file konfigurasi lokal:

    kubectl get <kind>/<name> -o yaml > <kind>_<name>.yaml
    
  2. Hapus secara manual field status dari file konfigurasi.

  3. Ubah anotasi kubectl.kubernetes.io/last-applied-configuration pada objek:

    kubectl replace --save-config -f <kind>_<name>.yaml
    
  4. Selanjutnya gunakan kubectl apply secara eksklusif untuk mengelola objek.

Migrasi dari konfigurasi objek imperatif ke konfigurasi objek deklaratif

  1. Atur anotasi kubectl.kubernetes.io/last-applied-configuration pada objek:

    kubectl replace --save-config -f <kind>_<name>.yaml
    
  2. Gunakan selalu perintah kubectl apply saja untuk mengelola objek.

Pendefinisian selektor controller dan label PodTemplate

Cara yang disarankan adalah dengan mendefinisikan sebuah PodTemplate immutable yang hanya digunakan oleh selektor controller tanpa memiliki arti semantik lainnya.

Contoh:

selector:
  matchLabels:
      controller-selector: "extensions/v1beta1/deployment/nginx"
template:
  metadata:
    labels:
      controller-selector: "extensions/v1beta1/deployment/nginx"

Selanjutnya

5.2 - Mengelola Objek Kubernetes secara Deklaratif menggunakan Kustomize

Kustomize merupakan sebuah alat untuk melakukan kustomisasi objek Kubernetes melalui sebuah berkas berkas kustomization.

Sejak versi 1.14, kubectl mendukung pengelolaan objek Kubernetes melalui berkas kustomization. Untuk melihat sumber daya yang ada di dalam direktori yang memiliki berkas kustomization, jalankan perintah berikut:

kubectl kustomize <direktori_kustomization>

Untuk menerapkan sumber daya tersebut, jalankan perintah kubectl apply dengan flag --kustomize atau -k:

kubectl apply -k <kustomization_directory>

Sebelum kamu memulai

Instal kubectl terlebih dahulu.

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.

Gambaran Umum Kustomize

Kustomize adalah sebuah alat untuk melakukan kustomisasi konfigurasi Kubernetes. Untuk mengelola berkas-berkas konfigurasi, kustomize memiliki fitur -fitur di bawah ini:

  • membangkitkan (generate) sumber daya dari sumber lain
  • mengatur field dari berbagai sumber daya yang bersinggungan
  • mengkomposisikan dan melakukan kustomisasi sekelompok sumber daya

Membangkitkan Sumber Daya

ConfigMap dan Secret menyimpan konfigurasi atau data sensitif yang digunakan oleh objek-objek Kubernetes lainnya, seperti Pod. Biasanya, source of truth dari ConfigMap atau Secret berasal dari luar klaster, seperti berkas .properties atau berkas kunci SSH. Kustomize memiliki secretGenerator dan configMapGenerator, yang akan membangkitkan (generate) Secret dan ConfigMap dari berkas-berkas atau nilai-nilai literal.

configMapGenerator

Untuk membangkitkan sebuah ConfigMap dari berkas, tambahkan entri ke daftar files pada configMapGenerator. Contoh di bawah ini membangkitkan sebuah ConfigMap dengan data dari berkas .properties:

# Membuat berkas application.properties
cat <<EOF >application.properties
FOO=Bar
EOF

cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-1
  files:
  - application.properties
EOF

ConfigMap yang telah dibangkitkan dapat dilihat menggunakan perintah berikut:

kubectl kustomize ./

Isinya seperti di bawah ini:

apiVersion: v1
data:
  application.properties: |
    FOO: Bar    
kind: ConfigMap
metadata:
  name: example-configmap-1-42cfbf598f

ConfigMap juga dapat dibangkitkan dari pasangan key-value literal. Untuk membangkitkan secara literal, tambahkan entri pada daftar literals di configMapGenerator. Contoh di bawah ini membangkitkan ConfigMap dengan data dari pasangan key-value:

cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-2
  literals:
  - FOO=Bar
EOF

ConfigMap yang dibangkitkan dapat dilihat menggunakan perintah berikut:

kubectl kustomize ./

Isinya seperti ini:

apiVersion: v1
data:
  FOO: Bar
kind: ConfigMap
metadata:
  name: example-configmap-2-g2hdhfc6tk

secretGenerator

Kamu dapat membangkitkan Secret dari berkas atau pasangan key-value literal. Untuk membangkitkan dari berkas, tambahkan entri pada daftar files di secretGenerator. Contoh di bawah ini membangkitkan Secret dengan data dari berkas:

# Membuat berkas password.txt
cat <<EOF >./password.txt
username=admin
password=secret
EOF

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-1
  files:
  - password.txt
EOF

Isinya seperti ini:

apiVersion: v1
data:
  password.txt: dXNlcm5hbWU9YWRtaW4KcGFzc3dvcmQ9c2VjcmV0Cg==
kind: Secret
metadata:
  name: example-secret-1-t2kt65hgtb
type: Opaque

Untuk membangkitkan secara literal dari pasangan key-value, tambahkan entri pada daftar literals di secretGenerator. Contoh di bawah ini membangkitkan Secret dengan data dari pasangan key-value:

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-2
  literals:
  - username=admin
  - password=secret
EOF

Isinya seperti ini:

apiVersion: v1
data:
  password: c2VjcmV0
  username: YWRtaW4=
kind: Secret
metadata:
  name: example-secret-2-t52t6g96d8
type: Opaque

generatorOptions

ConfigMap dan Secret yang dibangkitkan memiliki informasi sufiks hash. Hal ini memastikan bahwa ConfigMap atau Secret yang baru, dibangkitkan saat isinya berubah. Untuk menonaktifkan penambahan sufiks ini, kamu bisa menggunakan generatorOptions. Selain itu, melalui field ini kamu juga bisa mengatur opsi-opsi yang bersinggungan untuk ConfigMap dan Secret yang dibangkitkan.

cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-3
  literals:
  - FOO=Bar
generatorOptions:
  disableNameSuffixHash: true
  labels:
    type: generated
  annotations:
    note: generated
EOF

Jalankan perintah kubectl kustomize ./ untuk melihat ConfigMap yang dibangkitkan:

apiVersion: v1
data:
  FOO: Bar
kind: ConfigMap
metadata:
  annotations:
    note: generated
  labels:
    type: generated
  name: example-configmap-3

Mengatur field yang bersinggungan

Mengatur field-field yang bersinggungan untuk semua sumber daya Kubernetes dalam sebuah proyek. Beberapa contoh kasusnya seperti di bawah ini:

  • mengatur Namespace yang sama untuk semua sumber daya
  • menambahkan prefiks atau sufiks yang sama
  • menambahkan kumpulan label yang sama
  • menambahkan kumpulan anotasi yang sama

Lihat contoh di bawah ini:

# Membuat sebuah deployment.yaml
cat <<EOF >./deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
EOF

cat <<EOF >./kustomization.yaml
namespace: my-namespace
namePrefix: dev-
nameSuffix: "-001"
commonLabels:
  app: bingo
commonAnnotations:
  oncallPager: 800-555-1212
resources:
- deployment.yaml
EOF

Jalankan perintah kubectl kustomize ./ untuk melihat field-field tersebut telah terisi di dalam sumber daya Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    oncallPager: 800-555-1212
  labels:
    app: bingo
  name: dev-nginx-deployment-001
  namespace: my-namespace
spec:
  selector:
    matchLabels:
      app: bingo
  template:
    metadata:
      annotations:
        oncallPager: 800-555-1212
      labels:
        app: bingo
    spec:
      containers:
      - image: nginx
        name: nginx

Mengkomposisi dan Melakukan Kustomisasi Sumber Daya

Mengkomposisi kumpulan sumber daya dalam sebuah proyek dan mengelolanya di dalam berkas atau direktori yang sama merupakan hal yang cukup umum dilakukan. Kustomize menyediakan cara untuk mengkomposisi sumber daya dari berkas-berkas yang berbeda, lalu menerapkan patch atau kustomisasi lain di atasnya.

Melakukan Komposisi

Kustomize mendukung komposisi dari berbagai sumber daya yang berbeda. Field resources pada berkas kustomization.yaml, mendefinisikan daftar sumber daya yang diinginkan dalam sebuah konfigurasi. Atur terlebih dahulu jalur (path) ke berkas konfigurasi sumber daya pada daftar resources. Contoh di bawah ini merupakan sebuah aplikasi NGINX yang terdiri dari sebuah Deployment dan sebuah Service:

# Membuat berkas deployment.yaml
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# Membuat berkas service.yaml
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF

# Membuat berkas kustomization.yaml yang terdiri dari keduanya
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF

Sumber daya dari kubectl kustomize ./ berisi kedua objek Deployment dan Service.

Melakukan Kustomisasi

Patch dapat digunakan untuk menerapkan berbagai macam kustomisasi pada sumber daya. Kustomize mendukung berbagai mekanisme patching yang berbeda melalui patchesStrategicMerge dan patchesJson6902. patchesStrategicMerge adalah daftar dari yang berisi tentang path berkas. Setiap berkas akan dioperasikan dengan cara strategic merge patch. Nama di dalam patch harus sesuai dengan nama sumber daya yang telah dimuat. Kami menyarankan patch-patch kecil yang hanya melakukan satu hal saja. Contoh membuat sebuah patch di bawah ini akan menambahkan jumlah replika Deployment dan patch lainnya untuk mengatur limit memori.

# Membuat berkas deployment.yaml
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# Membuat sebuah patch increase_replicas.yaml
cat <<EOF > increase_replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
EOF

# Membuat patch lainnya set_memory.yaml
cat <<EOF > set_memory.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  template:
    spec:
      containers:
      - name: my-nginx
        resources:
        limits:
          memory: 512Mi
EOF

cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesStrategicMerge:
- increase_replicas.yaml
- set_memory.yaml
EOF

Jalankan perintah kubectl kustomize ./ untuk melihat isi dari Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - image: nginx
        limits:
          memory: 512Mi
        name: my-nginx
        ports:
        - containerPort: 80

Tidak semua sumber daya atau field mendukung strategic merge patch. Untuk mendukung field sembarang pada sumber daya field, Kustomize menyediakan penerapan patch JSON melalui patchesJson6902. Untuk mencari sumber daya yang tepat dengan sebuah patch Json, maka grup, versi, jenis dan nama dari sumber daya harus dispesifikasikan dalam kustomization.yaml. Contoh di bawah ini menambahkan jumlah replika dari objek Deployment yang bisa juga dilakukan melalui patchesJson6902.

# Membuat berkas deployment.yaml
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# Membuat patch json
cat <<EOF > patch.yaml
- op: replace
  path: /spec/replicas
  value: 3
EOF

# Membuat berkas kustomization.yaml
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml

patchesJson6902:
- target:
    group: apps
    version: v1
    kind: Deployment
    name: my-nginx
  path: patch.yaml
EOF

Jalankan perintah kubectl kustomize ./ untuk melihat field replicas yang telah diperbarui:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - image: nginx
        name: my-nginx
        ports:
        - containerPort: 80

Selain patch, Kustomize juga menyediakan cara untuk melakukan kustomisasi image Container atau memasukkan nilai field dari objek lainnya ke dalam Container tanpa membuat patch. Sebagai contoh, kamu dapat melakukan kustomisasi image yang digunakan di dalam Container dengan menyebutkan spesifikasi field images di dalam kustomization.yaml.

cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
images:
- name: nginx
  newName: my.image.registry/nginx
  newTag: 1.4.0
EOF

Jalankan perintah kubectl kustomize ./ untuk melihat image yang sedang digunakan telah diperbarui:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - image: my.image.registry/nginx:1.4.0
        name: my-nginx
        ports:
        - containerPort: 80

Terkadang, aplikasi yang berjalan di dalam Pod perlu untuk menggunakan nilai konfigurasi dari objek lainnya. Contohnya, sebuah Pod dari objek Deployment perlu untuk membaca nama Service dari Env atau sebagai argumen perintah. Ini karena nama Service bisa saja berubah akibat dari penambahan namePrefix atau nameSuffix pada berkas kustomization.yaml. Kami tidak menyarankan kamu untuk meng-hardcode nama Service di dalam argumen perintah. Untuk penggunaan ini, Kustomize dapat memasukkan nama Service ke dalam Container melalui vars.

# Membuat berkas deployment.yaml
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        command: ["start", "--host", "\$(MY_SERVICE_NAME)"]
EOF

# Membuat berkas service.yaml
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF

cat <<EOF >./kustomization.yaml
namePrefix: dev-
nameSuffix: "-001"

resources:
- deployment.yaml
- service.yaml

vars:
- name: MY_SERVICE_NAME
  objref:
    kind: Service
    name: my-nginx
    apiVersion: v1
EOF

Jalankan perintah kubectl kustomize ./ untuk melihat nama Service yang dimasukkan ke dalam Container menjadi dev-my-nginx-001:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dev-my-nginx-001
spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - command:
        - start
        - --host
        - dev-my-nginx-001
        image: nginx
        name: my-nginx

Base dan Overlay

Kustomize memiliki konsep base dan overlay. base merupakan direktori dengan kustomization.yaml, yang berisi sekumpulan sumber daya dan kustomisasi yang terkait. base dapat berupa direktori lokal maupun direktori dari repo remote, asalkan berkas kustomization.yaml ada di dalamnya. overlay merupakan direktori dengan kustomization.yaml yang merujuk pada direktori kustomization lainnya sebagai base-nya. base tidak memiliki informasi tentang overlay. dan dapat digunakan pada beberapa overlay sekaligus. overlay bisa memiliki beberapa base dan terdiri dari semua sumber daya yang berasal dari base yang juga dapat memiliki kustomisasi lagi di atasnya.

Contoh di bawah ini memperlihatkan kegunaan dari base:

# Membuat direktori untuk menyimpan base
mkdir base
# Membuat base/deployment.yaml
cat <<EOF > base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
EOF

# Membuat berkas base/service.yaml
cat <<EOF > base/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF

# Membuat berkas base/kustomization.yaml
cat <<EOF > base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF

base ini dapat digunakan di dalam beberapa overlay sekaligus. Kamu dapat menambahkan namePrefix yang berbeda ataupun field lainnya yang bersinggungan di dalam overlay berbeda. Di bawah ini merupakan dua buah overlay yang menggunakan base yang sama.

mkdir dev
cat <<EOF > dev/kustomization.yaml
resources:
- ../base
namePrefix: dev-
EOF

mkdir prod
cat <<EOF > prod/kustomization.yaml
resources:
- ../base
namePrefix: prod-
EOF

Cara menerapkan/melihat/menghapus objek menggunakan Kustomize

Gunakan --kustomize atau -k di dalam perintah kubectl untuk mengenali sumber daya yang dikelola oleh kustomization.yaml. Perhatikan bahwa -k harus merujuk pada direktori kustomization, misalnya:

kubectl apply -k <direktori kustomization>/

Buatlah kustomization.yaml seperti di bawah ini:

# Membuat berkas deployment.yaml
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# Membuat berkas kustomization.yaml
cat <<EOF >./kustomization.yaml
namePrefix: dev-
commonLabels:
  app: my-nginx
resources:
- deployment.yaml
EOF

Jalankan perintah di bawah ini untuk menerapkan objek Deployment dev-my-nginx:

> kubectl apply -k ./
deployment.apps/dev-my-nginx created

Jalankan perintah di bawah ini untuk melihat objek Deployment dev-my-nginx:

kubectl get -k ./
kubectl describe -k ./

Jalankan perintah di bawah ini untuk membandingkan objek Deployment dev-my-nginx dengan kondisi yang diinginkan pada klaster jika manifes telah berhasil diterapkan:

kubectl diff -k ./

Jalankan perintah di bawah ini untuk menghapus objek Deployment dev-my-nginx:

> kubectl delete -k ./
deployment.apps "dev-my-nginx" deleted

Daftar Fitur Kustomize

Field Tipe Deskripsi
namespace string menambahkan Namespace untuk semua sumber daya
namePrefix string nilai dari field ini ditambahkan di awal pada nama dari semua sumber daya
nameSuffix string nilai dari field ini ditambahkan di akhir pada nama dari semua sumber daya
commonLabels map[string]string label untuk ditambahkan pada semua sumber daya dan selektor
commonAnnotations map[string]string anotasi untuk ditambahkan pada semua sumber daya
resources []string setiap entri di dalam daftar ini harus diselesaikan pada berkas konfigurasi sumber daya yang sudah ada
configmapGenerator []ConfigMapArgs setiap entri di dalam daftar ini membangkitkan ConfigMap
secretGenerator []SecretArgs setiap entri di dalam daftar ini membangkitkan Secret
generatorOptions GeneratorOptions memodifikasi perilaku dari semua generator ConfigMap dan Secret
bases []string setiap entri di dalam daftar ini harus diselesaikan ke dalam sebuah direktori yang berisi berkas kustomization.yaml
patchesStrategicMerge []string setiap entri di dalam daftar ini harus diselesaikan dengan strategic merge patch dari sebuah objek Kubernetes
patchesJson6902 []Json6902 setiap entri di dalam daftar ini harus diselesaikan ke suatu objek Kubernetes atau patch Json
vars []Var setiap entri digunakan untuk menangkap teks yang berasal dari field sebuah sumber daya
images []Image setiap entri digunakan untuk memodifikasi nama, tag dan/atau digest untuk sebuah image tanpa membuat patch
configurations []string setiap entri di dalam daftar ini harus diselesaikan ke sebuah berkas yang berisi konfigurasi transformer Kustomize
crds []string setiap entri di dalam daftar ini harus diselesaikan ke sebuah berkas definisi OpenAPI untuk tipe Kubernetes

Selanjutnya

5.3 - Pengelolaan Objek Kubernetes dengan Perintah Imperatif

Objek-objek Kubernetes bisa dibuat, diperbarui, dan dihapus secara langsung dengan menggunakan perintah-perintah imperatif yang ada pada command-line kubectl. Dokumen ini menjelaskan cara perintah-perintah tersebut diorganisir dan cara menggunakan perintah-perintah tersebut untuk mengelola objek live.

Kelebihan dan kekurangan

Perintah kubectl mendukung tiga cara pengelolaan objek:

  • Perintah imperatif
  • Konfigurasi objek imperatif
  • Konfigurasi objek deklaratif

Lihat Pengelolaan Objek Kubernetes untuk mengenali lebih lanjut kelebihan dan kekurangan dari tiap pengelolaan objek.

Cara membuat objek

Perangkat kubectl mendukung perintah-perintah berbentuk kata kerja untuk membuat beberapa tipe objek yang paling umum. Perintah-perintah tersebut diberi nama yang mudah dikenali oleh pengguna yang belum familiar dengan tipe-tipe objek Kubernetes.

  • run: Membuat sebuah objek Deployment untuk menjalankan kontainer di satu atau lebih Pod.
  • expose: Membuat sebuah objek Service untuk mengatur lalu lintas beban antar Pod.
  • autoscale: Membuat sebuah objek Autoscaler untuk melakukan scaling horizontal secara otomatis terhadap sebuah objek controller, misalnya sebuah objek Deployment.

Perangkat kubectl juga mendukung perintah-perintah pembuatan objek yang berdasarkan pada tipe objek. Perintah-perintah ini mendukung lebih banyak tipe objek dan lebih eksplisit tentang intensi mereka. Tapi, perintah-perintah ini memerlukan pengguna untuk memahami tipe dari objek-objek yang hendak mereka buat.

  • create <objecttype> [<subtype>] <instancename>

Beberapa tipe objek memiliki sub tipe yang bisa kamu spesifikasikan pada perintah create. Misalnya, objek Service memiliki beberapa sub tipe seperti ClusterIP, LoadBalancer, dan NodePort. Berikut adalah sebuah contoh cara membuat sebuah Service dengan sub tipe NodePort:

kubectl create service nodeport <myservicename>

Pada contoh di atas, perintah create service nodeport merupakan sub perintah dari create service.

Kamu bisa menggunakan parameter -h untuk mencari argumen-argumen dan paramenter-parameter yang didukung oleh sebuah sub perintah:

kubectl create service nodeport -h

Cara memperbarui objek

Perintah kubectl mendukung perintah-perintah berbasis kata kerja untuk beberapa operasi pembaruan yang umum. Perintah-perintah ini diberi nama yang memudahkan pengguna yang belum familiar dengan objek-objek Kubernetes untuk melakukan pembaruan tanpa terlebih dulu mengetahui field-field spesifik yang harus diperbarui:

  • scale: Melakukan scaling horizontal terhadap sebuah controller untuk menambah atau menghapus Pod dengan memperbarui jumlah replika dari controller tersebut.
  • annotate: Menambah atau menghapus anotasi sebuah objek.
  • label: Menambah atau menghapus label sebuah objek.

Perintah kubectl juga mendukung perintah-perintah pembaruan berdasarkan salah satu aspek dari sebuah objek. Untuk tiap tipe objek yang berbeda, memperbarui sebuah aspek tertentu bisa berarti memperbarui sekumpulan field yang berbeda pula:

  • set <field>: Memperbarui salah satu aspek dari sebuah objek.

Perangkat kubectl juga mendukung beberapa cara lain untuk memperbarui objek live secara langsung, meskipun cara-cara berikut membutuhkan pemahaman yang lebih tentang skema objek Kubernetes.

  • edit: Secara langsung mengedit konfigurasi mentah dari sebuah objek live dengan membuka konfigurasinya di sebuah editor.
  • patch: Secara langsung memodifikasi field-field spesifik dari sebuah objek live dengan menggunakan patch string. Untuk detil lebih lanjut mengenai patch string, lihat bagian tentang patch pada Konvensi API.

Cara menghapus objek

Kamu bisa menggunakan perintah delete pada sebuah objek dari sebuah klaster:

  • delete <type>/<name>
kubectl delete deployment/nginx

Cara melihat objek

Ada beberapa perintah untuk menampilkan informasi tentang sebuah objek:

  • get: Menampilkan informasi dasar dari objek-objek yang sesuai dengan parameter dari perintah ini. Gunakan get -h untuk melihat daftar opsi yang bisa digunakan.
  • describe: Menampilkan agregat informasi detil dari objek-objek yang sesuai dengan parameter dari perintah ini.
  • logs: Menampilkan isi stdout dan stderr dari sebuah kontainer yang berjalan di sebuah Pod.

Menggunakan perintah set untuk memodifikasi objek sebelum dibuat

Ada beberapa field objek yang tidak memiliki parameter yang bisa kamu gunakan pada perintah create. Pada kasus-kasus tersebut, kamu bisa menggunakan kombinasi dari perintah set dan create untuk menspesifikasikan nilai untuk field-field tersebut sebelum objek dibuat. Ini dilakukan dengan melakukan piping pada hasil dari perintah create ke perintah set, dan kemudian mengembalikan hasilnya ke perintah create. Simak contoh berikut:

kubectl create service clusterip my-svc --clusterip="None" -o yaml --dry-run | kubectl set selector --local -f - 'environment=qa' -o yaml | kubectl create -f -
  1. Perintah kubectl create service -o yaml --dry-run membuat konfigurasi untuk sebuah Service, tapi kemudian menuliskan konfigurasi tadi ke stdout dalam format YAML alih-alih mengirimnya ke API Server Kubernetes.
  2. Perintah kubectl set selector --local -f - -o yaml membaca konfigurasi dari stdin, dan menuliskan pembaruan konfigurasi ke stdout dalam format YAML.
  3. Perintah kubectl create -f - membuat objek dengan menggunakan konfigurasi yang disediakan pada stdin.

Menggunakan --edit untuk memodifikasi objek sebelum dibuat

Kamu bisa menggunakan perintah kubectl create --edit untuk membuat perubahan terhadap sebuah objek sebelum objek tersebut dibuat. Simak contoh berikut:

kubectl create service clusterip my-svc --clusterip="None" -o yaml --dry-run > /tmp/srv.yaml
kubectl create --edit -f /tmp/srv.yaml
  1. Perintah kubectl create service membuat konfigurasi untuk objek Service dan menyimpannya di /tmp/srv.yaml.
  2. Perintah kubectl create --edit membuka berkas konfigurasi untuk disunting sebelum objek dibuat.

Selanjutnya

5.4 - Pengelolaan Objek Kubernetes Secara Imperatif dengan Menggunakan File Konfigurasi

Objek-objek Kubernetes bisa dibuat, diperbarui, dan dihapus dengan menggunakan perangkat command-line kubectl dan file konfigurasi objek yang ditulis dalam format YAML atau JSON. Dokumen ini menjelaskan cara mendefinisikan dan mengelola objek dengan menggunakan file konfigurasi.

Kelebihan dan kekurangan

Perintah kubectl mendukung tiga cara pengelolaan objek:

  • Perintah imperatif
  • Konfigurasi objek imperatif
  • Konfigurasi objek deklaratif

Lihat Pengelolaan Objek Kubernetes untuk mengenali lebih lanjut kelebihan dan kekurangan dari tiap cara pengelolaan objek.

Cara membuat objek

Kamu bisa menggunakan perintah kubectl create -f untuk membuat sebuah objek dari sebuah file konfigurasi. Rujuk dokumen referensi API Kubernetes untuk detil lebih lanjut.

  • kubectl create -f <nama-file|url>

Cara memperbarui objek

Kamu bisa menggunakan perintah kubectl replace -f untuk memperbarui sebuah objek live sesuai dengan sebuah file konfigurasi.

  • kubectl replace -f <nama-file|url>

Cara menghapus objek

Kamu bisa menggunakan perintah kubectl delete -f untuk menghapus sebuah objek yang dideskripsikan pada sebuah file konfigurasi.

  • kubectl delete -f <nama-file|url>

Cara melihat objek

Kamu bisa menggunakan perintah kubectl get -f untuk melihat informasi tentang sebuah objek yang dideskripsikan pada sebuah file konfigurasi.

  • kubectl get -f <nama-file|url> -o yaml

Parameter -o yaml menetapkan bahwa keseluruhan konfigurasi objek ditulis ke file yaml. Gunakan perintah kubectl get -h untuk melihat daftar pilihan selengkapnya.

Keterbatasan

Perintah-perintah create, replace, dan delete bekerja dengan baik saat tiap konfigurasi dari sebuah objek didefinisikan dan dicatat dengan lengkap pada file konfigurasi objek tersebut. Akan tetapi, ketika sebuah objek live diperbarui dan pembaruannya tidak dicatat di file konfigurasinya, pembaruan tersebut akan hilang ketika perintah replace dieksekusi di waktu berikutnya. Ini bisa terjadi saat sebuah controller, misalnya sebuah HorizontalPodAutoscaler, membuat pembaruan secara langsung ke sebuah objek live. Berikut sebuah contoh:

  1. Kamu membuat sebuah objek dari sebuah file konfigurasi.
  2. Sebuah sumber lain memperbarui objek tersebut dengan mengubah beberapa field.
  3. Kamu memperbarui objek tersebut dengan kubectl replace dari file konfigurasi. Perubahan yang dibuat dari sumber lain pada langkah nomor 2 di atas akan hilang.

Jika kamu perlu mendukung beberapa writer untuk objek yang sama, kamu bisa menggunakan kubectl apply untuk mengelola objek tersebut.

Membuat dan mengedit objek dari URL tanpa menyimpan konfigurasinya

Misalkan kamu memiliki URL dari sebuah file konfigurasi objek. Kamu bisa menggunakan kubectl create --edit untuk membuat perubahan pada konfigurasi sebelum objek tersebut dibuat. Langkah ini terutama berguna untuk mengikuti tutorial atau untuk pekerjaan-pekerjaan yang menggunakan sebuah file konfigurasi di URL terentu yang perlu dimodifikasi.

kubectl create -f <url> --edit

Migrasi dari perintah imperatif ke konfigurasi objek imperatif

Migrsasi dari perintah imperatif ke konfigurasi objek imperatif melibatkan beberapa langkah manual.

  1. Ekspor objek live ke sebuah file konfigurasi objek lokal:
kubectl get <kind>/<name> -o yaml --export > <kind>_<name>.yaml
  1. Hapus secara manual field status dari file konfigurasi objek.

  2. Untuk pengelolaan objek selanjutnya, gunakan perintah replace secara eksklusif.

kubectl replace -f <kind>_<name>.yaml

Mendefinisikan controller selectors dan label PodTemplate

Pendekatan yang direkomendasikan adalah mendefinisikan sebuah label PodTemplate tunggal dan immutable yang hanya digunakan oleh controller selector tersebut, tanpa makna semantik lainnya.

Contoh label:

selector:
  matchLabels:
      controller-selector: "extensions/v1beta1/deployment/nginx"
template:
  metadata:
    labels:
      controller-selector: "extensions/v1beta1/deployment/nginx"

Selanjutnya

6 - Memasukkan Data ke dalam Aplikasi

6.1 - Mendefinisikan Perintah dan Argumen untuk sebuah Kontainer

Laman ini menunjukkan bagaimana cara mendefinisikan perintah-perintah dan argumen-argumen saat kamu menjalankan Container dalam sebuah 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.

Mendefinisikan sebuah perintah dan argumen-argumen saat kamu membuat sebuah Pod

Saat kamu membuat sebuah Pod, kamu dapat mendefinisikan sebuah perintah dan argumen-argumen untuk Container-Container yang berjalan di dalam Pod. Untuk mendefinisikan sebuah perintah, sertakan bidang command di dalam berkas konfigurasi. Untuk mendefinisikan argumen-argumen untuk perintah, sertakan bidang args di dalam berkas konfigurasi. Perintah dan argumen-argumen yang telah kamu definisikan tidak dapat diganti setelah Pod telah terbuat.

Perintah dan argumen-argumen yang kamu definisikan di dalam berkas konfigurasi membatalkan perintah dan argumen-argumen bawaan yang disediakan oleh image Container. Jika kamu mendefinisikan argumen-argumen, tetapi tidak mendefinisikan sebuah perintah, perintah bawaan digunakan dengan argumen-argumen baru kamu.

Pada latihan ini, kamu akan membuat sebuah Pod baru yang menjalankan sebuah Container. Berkas konfigurasi untuk Pod mendefinisikan sebuah perintah dan dua argumen:

apiVersion: v1
kind: Pod
metadata:
  name: command-demo
  labels:
    purpose: demonstrate-command
spec:
  containers:
  - name: command-demo-container
    image: debian
    command: ["printenv"]
    args: ["HOSTNAME", "KUBERNETES_PORT"]
  restartPolicy: OnFailure
  1. Buat sebuah Pod dengan berkas konfigurasi YAML:

    kubectl apply -f https://k8s.io/examples/pods/commands.yaml
    
  2. Daftar Pod yang sedang berjalan

    kubectl get pods
    

    Keluaran menunjukkan bahwa Container yang berjalan di dalam Pod command-demo telah selesai.

  3. Untuk melihat keluaran dari perintah yang berjalan di dalam Container, lihat log dari Pod tersebut:

    kubectl logs command-demo
    

    Keluaran menunjukan nilai dari variabel lingkungan HOSTNAME dan KUBERNETES_PORT:

    command-demo
    tcp://10.3.240.1:443
    

Menggunakan variabel lingkungan untuk mendefinisikan argumen

Dalam contoh sebelumnya, kamu mendefinisikan langsung argumen-argumen dengan menyediakan string. Sebagai sebuah alternatif untuk menyediakan string secara langsung, kamu dapat mendefinisikan argumen-argumen dengan menggunakan variabel lingkungan:

env:
- name: MESSAGE
  value: "hello world"
command: ["/bin/echo"]
args: ["$(MESSAGE)"]

Ini berarti kamu dapat mendefinisikan sebuah argumen untuk sebuah Pod menggunakan salah satu teknik yang tersedia untuk mendefinisikan variabel-variabel lingkungan, termasuk ConfigMap dan Secret.

Menjalankan sebuah perintah di dalam shell

Di beberapa kasus, kamu butuh perintah untuk menjalankan sebuah shell. Contohnya, perintah kamu mungkin terdiri dari beberapa perintah yang digabungkan, atau mungkin berupa skrip shell. Untuk menjalankan perintah kamu di sebuah shell, bungkus seperti ini:

command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]

Catatan

Tabel ini merangkum nama-nama bidang yang digunakan oleh Docker dan Kubernetes.

Deskripsi Nama bidang pada Docker Nama bidang pada Kubernetes
Perintah yang dijalankan oleh Container Entrypoint command
Argumen diteruskan ke perintah Cmd args

Saat kamu mengesampingkan Entrypoint dan Cmd standar, aturan-aturan ini berlaku:

  • Jika kamu tidak menyediakan command atau args untuk sebuah Container, maka command dan args yang didefinisikan di dalam image Docker akan digunakan.

  • Jika kamu menyediakan command tetapi tidak menyediakan args untuk sebuah Container, akan digunakan command yang disediakan. Entrypoint dan Cmd bawaan yang didefinisikan di dalam image Docker diabaikan.

  • Jika kamu hanya menyediakan args untuk sebuah Container, Entrypoint bawaan yang didefinisikan di dalam image Docker dijalakan dengan args yang kamu sediakan.

  • Jika kamu menyediakan command dan args, Entrypoint dan Cmd standar yang didefinisikan di dalam image Docker diabaikan. command kamu akan dijalankan dengan args kamu.

Berikut ini beberapa contoh:

Image Entrypoint Image Cmd Container command Container args Command run
[/ep-1] [foo bar] <not set> <not set> [ep-1 foo bar]
[/ep-1] [foo bar] [/ep-2] <not set> [ep-2]
[/ep-1] [foo bar] <not set> [zoo boo] [ep-1 zoo boo]
[/ep-1] [foo bar] [/ep-2] [zoo boo] [ep-2 zoo boo]

Selanjutnya

6.2 - Mendefinisikan Variabel Lingkungan untuk sebuah Kontainer

Laman ini menunjukkan bagaimana cara untuk mendefinisikan variabel lingkungan (environment variable) untuk sebuah Container di dalam sebuah Pod 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:

Untuk melihat versi, tekan kubectl version.

Mendefinisikan sebuah variabel lingkungan untuk sebuah Container

Ketika kamu membuat sebuah Pod, kamu dapat mengatur variabel lingkungan untuk Container-Container yang berjalan di dalam sebuah Pod. Untuk mengatur variabel lingkungan, sertakan bagian env atau envFrom pada berkas konfigurasi.

Dalam latihan ini, kamu membuat sebuah Pod yang menjalankan satu buah Container. Berkas konfigurasi untuk Pod tersebut mendefinisikan sebuah variabel lingkungan dengan nama DEMO_GREETING yang bernilai "Hello from the environment". Berikut berkas konfigurasi untuk Pod tersebut:

apiVersion: v1
kind: Pod
metadata:
  name: envar-demo
  labels:
    purpose: demonstrate-envars
spec:
  containers:
  - name: envar-demo-container
    image: gcr.io/google-samples/node-hello:1.0
    env:
    - name: DEMO_GREETING
      value: "Hello from the environment"
    - name: DEMO_FAREWELL
      value: "Such a sweet sorrow"
  1. Buatlah sebuah Pod berdasarkan berkas konfigurasi YAML tersebut:

    kubectl apply -f https://k8s.io/examples/pods/inject/envars.yaml
    
  2. Tampilkan Pod-Pod yang sedang berjalan:

    kubectl get pods -l purpose=demonstrate-envars
    

    Keluarannya mirip seperti ini:

    NAME            READY     STATUS    RESTARTS   AGE
    envar-demo      1/1       Running   0          9s
    
  3. Dapatkan sebuah shell ke Container yang sedang berjalan di Pod kamu:

    kubectl exec -it envar-demo -- /bin/bash
    
  4. Di shell kamu, jalankan perintah printenv untuk melihat daftar variabel lingkungannya.

    root@envar-demo:/# printenv
    

    Keluarannya mirip seperti ini:

    NODE_VERSION=4.4.2
    EXAMPLE_SERVICE_PORT_8080_TCP_ADDR=10.3.245.237
    HOSTNAME=envar-demo
    ...
    DEMO_GREETING=Hello from the environment
    DEMO_FAREWELL=Such a sweet sorrow
    
  5. Untuk keluar dari shell tersebut, masukkan perintah exit.

Menggunakan variabel-variabel lingkungan di dalam konfigurasi kamu

Variabel-variabel lingkungan yang kamu definisikan di dalam sebuah konfigurasi Pod dapat digunakan di tempat lain dalam konfigurasi, contohnya di dalam perintah-perintah dan argumen-argumen yang kamu atur dalam Container-Container milik Pod. Pada contoh konfigurasi berikut, variabel-variabel lingkungan GREETING, HONORIFIC, dan NAME disetel masing-masing menjadi Warm greetings to, The Most Honorable, dan Kubernetes. Variabel-variabel lingkungan tersebut kemudian digunakan dalam argumen CLI yang diteruskan ke Container env-print-demo.

apiVersion: v1
kind: Pod
metadata:
  name: print-greeting
spec:
  containers:
  - name: env-print-demo
    image: bash
    env:
    - name: GREETING
      value: "Warm greetings to"
    - name: HONORIFIC
      value: "The Most Honorable"
    - name: NAME
      value: "Kubernetes"
    command: ["echo"]
    args: ["$(GREETING) $(HONORIFIC) $(NAME)"]

Setelah dibuat, perintah echo Warm greetings to The Most Honorable Kubernetes dijalankan di Container tersebut.

Selanjutnya

6.3 - Mendistribusikan Kredensial dengan Aman Menggunakan Secret

Laman ini menjelaskan bagaimana cara menginjeksi data sensitif, seperti kata sandi (password) dan kunci enkripsi, ke dalam 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:

Mengubah data rahasia kamu ke dalam representasi Base64

Misalnya kamu mempunyai dua buah data rahasia: sebuah nama pengguna my-app dan kata sandi 39528$vdg7Jb. Pertama, gunakan alat penyandian Base64 untuk mengubah nama pengguna kamu dan kata sandi ke dalam representasi Base64. Berikut ini contoh menggunakan program Base64 yang umum digunakan:

echo -n 'my-app' | base64
echo -n '39528$vdg7Jb' | base64

Hasil keluaran menampilkan representasi Base64 dari nama pengguna kamu yaitu bXktYXBw, dan representasi Base64 dari kata sandi kamu yaitu Mzk1MjgkdmRnN0pi.

Membuat Secret

Berikut ini adalah berkas konfigurasi yang dapat kamu gunakan untuk membuat Secret yang akan menampung nama pengguna dan kata sandi kamu:

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  username: bXktYXBw
  password: Mzk1MjgkdmRnN0pi
  1. Membuat Secret

    kubectl apply -f https://k8s.io/examples/pods/inject/secret.yaml
    
  2. Melihat informasi dari Secret:

    kubectl get secret test-secret
    

    Hasil keluaran:

    NAME          TYPE      DATA      AGE
    test-secret   Opaque    2         1m
    
  3. Melihat informasi detil dari Secret:

    kubectl describe secret test-secret
    

    Hasil keluaran:

    Name:       test-secret
    Namespace:  default
    Labels:     <none>
    Annotations:    <none>
    
    Type:   Opaque
    
    Data
    ====
    password:   13 bytes
    username:   7 bytes
    

Membuat Secret langsung dengan kubectl

Jika kamu ingin melompati langkah penyandian dengan Base64, kamu dapat langsung membuat Secret yang sama dengan menggunakan perintah kubectl create secret. Contohnya:

kubectl create secret generic test-secret --from-literal='username=my-app' --from-literal='password=39528$vdg7Jb'

Tentu saja ini lebih mudah. Pendekatan yang mendetil setiap langkah di atas bertujuan untuk mendemonstrasikan apa yang sebenarnya terjadi pada setiap langkah.

Membuat Pod yang memiliki akses ke data Secret melalui Volume

Berikut ini adalah berkas konfigurasi yang dapat kamu gunakan untuk membuat Pod:

apiVersion: v1
kind: Pod
metadata:
  name: secret-test-pod
spec:
  containers:
    - name: test-container
      image: nginx
      volumeMounts:
        # nama harus sesuai dengan nama Volume di bawah ini
        - name: secret-volume
          mountPath: /etc/secret-volume
  # Data Secret diekspos ke Container di dalam Pod melalui Volume
  volumes:
    - name: secret-volume
      secret:
        secretName: test-secret
  1. Membuat Pod:

    kubectl apply -f https://k8s.io/examples/pods/inject/secret-pod.yaml
    
  2. Verifikasikan apakah Pod kamu sudah berjalan:

    kubectl get pod secret-test-pod
    

    Hasil keluaran:

    NAME              READY     STATUS    RESTARTS   AGE
    secret-test-pod   1/1       Running   0          42m
    
  3. Gunakan shell untuk masuk ke dalam Container yang berjalan di dalam Pod kamu:

    kubectl exec -i -t secret-test-pod -- /bin/bash
    
  4. Data Secret terekspos ke Container melalui Volume yang dipasang (mount) pada /etc/secret-volume.

    Di dalam shell kamu, tampilkan berkas yang ada di dalam direktori /etc/secret-volume:

    # Jalankan ini di dalam shell dalam Container
    ls /etc/secret-volume
    

    Hasil keluaran menampilkan dua buah berkas, masing-masing untuk setiap data Secret:

    password username
    
  5. Di dalam shell kamu, tampilkan konten dari berkas username dan password:

    # Jalankan ini di dalam shell dalam Container
    echo "$( cat /etc/secret-volume/username )"
    echo "$( cat /etc/secret-volume/password )"
    

    Hasil keluarannya adalah nama pengguna dan kata sandi kamu:

    my-app
    39528$vdg7Jb
    

Mendefinisikan variabel lingkungan Container menggunakan data Secret

Mendefinisikan variabel lingkungan Container menggunakan data dari Secret tunggal

  • Definisikan variabel lingkungan sebagai pasangan key-value pada Secret:

    kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
    
  • Tentukan nilai backend-username yang didefinisikan di Secret ke variabel lingkungan SECRET_USERNAME di dalam spesifikasi Pod.

    apiVersion: v1
    kind: Pod
    metadata:
      name: env-single-secret
    spec:
      containers:
      - name: envars-test-container
        image: nginx
        env:
        - name: SECRET_USERNAME
          valueFrom:
            secretKeyRef:
              name: backend-user
              key: backend-username
    
  • Membuat Pod:

    kubectl create -f https://k8s.io/examples/pods/inject/pod-single-secret-env-variable.yaml
    
  • Di dalam shell kamu, tampilkan konten dari variabel lingkungan SECRET_USERNAME dari Container

    kubectl exec -i -t env-single-secret -- /bin/sh -c 'echo $SECRET_USERNAME'
    

    Hasil keluarannya

    backend-admin
    

Mendefinisikan variabel lingkungan Container dengan data dari multipel Secret

  • Seperti contoh sebelumnya, buat Secret terlebih dahulu.

    kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
    kubectl create secret generic db-user --from-literal=db-username='db-admin'
    
  • Definisikan variabel lingkungan di dalam spesifikasi Pod.

    apiVersion: v1
    kind: Pod
    metadata:
      name: envvars-multiple-secrets
    spec:
      containers:
      - name: envars-test-container
        image: nginx
        env:
        - name: BACKEND_USERNAME
          valueFrom:
            secretKeyRef:
              name: backend-user
              key: backend-username
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: db-user
              key: db-username
    
  • Membuat Pod:

    kubectl create -f https://k8s.io/examples/pods/inject/pod-multiple-secret-env-variable.yaml
    
  • Di dalam shell kamu, tampilkan konten dari variabel lingkungan Container

    kubectl exec -i -t envvars-multiple-secrets -- /bin/sh -c 'env | grep _USERNAME'
    

    Hasil keluarannya

    DB_USERNAME=db-admin
    BACKEND_USERNAME=backend-admin
    

Mengonfigurasi semua pasangan key-value di dalam Secret sebagai variabel lingkungan Container

  • Membuat Secret yang berisi banyak pasangan key-value

    kubectl create secret generic test-secret --from-literal=username='my-app' --from-literal=password='39528$vdg7Jb'
    
  • Gunakan envFrom untuk mendefinisikan semua data Secret sebagai variabel lingkungan Container. Key dari Secret akan mennjadi nama variabel lingkungan di dalam Pod.

    apiVersion: v1
     kind: Pod
     metadata:
       name: envfrom-secret
     spec:
       containers:
       - name: envars-test-container
         image: nginx
         envFrom:
         - secretRef:
             name: test-secret
     
  • Membuat Pod:

    kubectl create -f https://k8s.io/examples/pods/inject/pod-secret-envFrom.yaml
    
  • Di dalam shell kamu, tampilkan variabel lingkungan Container username dan password

    kubectl exec -i -t envfrom-secret -- /bin/sh -c 'echo "username: $username\npassword: $password\n"'
    

    Hasil keluarannya

    username: my-app
    password: 39528$vdg7Jb
    

Referensi

Selanjutnya

  • Pelajari lebih lanjut Secret.
  • Pelajari lebih lanjut Volume.

7 - Menjalankan

Menjalankan dan mengatur aplikasi stateless dan stateful.

7.1 - Menjalankan Aplikasi Stateless Menggunakan Deployment

Dokumen ini menunjukkan cara bagaimana cara menjalankan sebuah aplikasi menggunakan objek Deployment Kubernetes.

Tujuan

  • Membuat sebuah Deployment Nginx.
  • Menggunakan kubectl untuk mendapatkan informasi mengenai Deployment.
  • Mengubah Deployment.

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.9. Untuk melihat versi, tekan kubectl version.

Membuat dan Menjelajahi Deployment Nginx

Kamu dapat menjalankan aplikasi dengan membuat sebuah objek Deployment Kubernetes, dan kamu dapat mendeskripsikan sebuah Deployment di dalam berkas YAML. Sebagai contohnya, berkas YAML berikut mendeskripsikan sebuah Deployment yang menjalankan image Docker nginx:1.14.2:

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.7.9
          ports:
            - containerPort: 80
  1. Buatlah sebuah Deployment berdasarkan berkas YAML:

     kubectl apply -f https://k8s.io/examples/application/deployment.yaml
    
  2. Tampilkan informasi dari Deployment:

     kubectl describe deployment nginx-deployment
    

    Keluaran dari perintah tersebut akan menyerupai:

     Name:     nginx-deployment
     Namespace:    default
     CreationTimestamp:  Tue, 30 Aug 2016 18:11:37 -0700
     Labels:     app=nginx
     Annotations:    deployment.kubernetes.io/revision=1
     Selector:   app=nginx
     Replicas:   2 desired | 2 updated | 2 total | 2 available | 0 unavailable
     StrategyType:   RollingUpdate
     MinReadySeconds:  0
     RollingUpdateStrategy:  1 max unavailable, 1 max surge
     Pod Template:
       Labels:       app=nginx
       Containers:
        nginx:
         Image:              nginx:1.14.2
         Port:               80/TCP
         Environment:        <none>
         Mounts:             <none>
       Volumes:              <none>
     Conditions:
       Type          Status  Reason
       ----          ------  ------
       Available     True    MinimumReplicasAvailable
       Progressing   True    NewReplicaSetAvailable
     OldReplicaSets:   <none>
     NewReplicaSet:    nginx-deployment-1771418926 (2/2 replicas created)
     No events.
    
  3. Lihatlah daftar Pod-Pod yang dibuat oleh Deployment:

     kubectl get pods -l app=nginx
    

    Keluaran dari perintah tersebut akan menyerupai:

     NAME                                READY     STATUS    RESTARTS   AGE
     nginx-deployment-1771418926-7o5ns   1/1       Running   0          16h
     nginx-deployment-1771418926-r18az   1/1       Running   0          16h
    
  4. Tampilkan informasi mengenai Pod:

     kubectl describe pod <nama-pod>
    

    dimana <nama-pod> merupakan nama dari Pod kamu.

Mengubah Deployment

Kamu dapat mengubah Deployment dengan cara mengaplikasikan berkas YAML yang baru. Berkas YAML ini memberikan spesifikasi Deployment untuk menggunakan Nginx versi 1.16.1.

apiVersion: apps/v1 # untuk versi sebelum 1.9.0 gunakan apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1 # Memperbarui versi nginx dari 1.14.2 ke 1.16.1
        ports:
        - containerPort: 80
  1. Terapkan berkas YAML yang baru:

      kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml
    
  2. Perhatikan bahwa Deployment membuat Pod-Pod dengan nama baru dan menghapus Pod-Pod lama:

      kubectl get pods -l app=nginx
    

Meningkatkan Jumlah Aplikasi dengan Meningkatkan Ukuran Replika

Kamu dapat meningkatkan jumlah Pod di dalam Deployment dengan menerapkan berkas YAML baru. Berkas YAML ini akan meningkatkan jumlah replika menjadi 4, yang nantinya memberikan spesifikasi agar Deployment memiliki 4 buah Pod.

apiVersion: apps/v1 # untuk versi sebelum 1.9.0 gunakan apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 4 # Memperbarui replica dari 2 menjadi 4
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1
        ports:
        - containerPort: 80
  1. Terapkan berkas YAML:

     kubectl apply -f https://k8s.io/examples/application/deployment-scale.yaml
    
  2. Verifikasi Deployment kamu saat ini yang memiliki empat Pod:

     kubectl get pods -l app=nginx
    

    Keluaran dari perintah tersebut akan menyerupai:

     NAME                               READY     STATUS    RESTARTS   AGE
     nginx-deployment-148880595-4zdqq   1/1       Running   0          25s
     nginx-deployment-148880595-6zgi1   1/1       Running   0          25s
     nginx-deployment-148880595-fxcez   1/1       Running   0          2m
     nginx-deployment-148880595-rwovn   1/1       Running   0          2m
    

Menghapus Deployment

Menghapus Deployment dengan nama:

kubectl delete deployment nginx-deployment

Cara Lama Menggunakan: ReplicationController

Cara yang dianjurkan untuk membuat aplikasi dengan replika adalah dengan menggunakan Deployment, yang nantinya akan menggunakan ReplicaSet. Sebelum Deployment dan ReplicaSet ditambahkan ke Kubernetes, aplikasi dengan replika dikonfigurasi menggunakan ReplicationController.

Selanjutnya

7.2 - Menghapus Paksa Pod StatefulSet

Laman ini menjelaskan bagaimana cara menghapus Pod yang menjadi bagian dari sebuah stateful set, dan menjelaskan pertimbangan yang harus diperhatikan saat melakukannya.

Sebelum kamu memulai

  • Ini merupakan tugas yang cukup rumit dan memiliki potensi melanggar beberapa properti yang melekat dari StatefulSet.
  • Sebelum melanjutkan, pastikan kamu paham dengan pertimbangan yang disebutkan di bawah ini.

Pertimbangan StatefulSet

Pada operasi normal dari StatefulSet, tidak pernah ada kebutuhan untuk menghapus paksa sebuah Pod StatefulSet. Controller StatefulSet bertanggung jawab terhadap pembuatan, penyekalaan dan penghapusan terhadap anggota dari StatefulSet. Controller akan berusaha menjaga agar jumlah Pod yang ditentukan dari 0 hingga N-1 hidup dan siap sedia. StatefulSet memastikan bahwa, pada waktu kapanpun, akan ada minimal satu Pod dengan identitas yang telah ditetapkan berjalan pada klaster. Hal ini direferensikan sebagai semantik at most one yang disediakan StatefulSet.

Penghapusan paksa secara manual harus dilakukan dengan hati-hati, karena hal tersebut berpotensi melanggar semantik at most one yang melekat pada StatefulSet. StatefulSet dapat digunakan untuk menjalankan aplikasi terklaster dan terdistribusi yang membutuhkan identitas jaringan dan penyimpanan yang stabil dan tetap. Aplikasi-aplikasi ini biasanya memiliki konfigurasi yang tergantung dengan sejumlah anggota dengan identitas yang tetap. Memiliki banyak anggota dengan identitas yang sama berpotensi menimbulkan kerusakan dan kehilangan data (contohnya skenario split brain pada sistem berbasis kuorum).

Menghapus Pod

Kamu dapat melakukan penghapusan Pod secara graceful dengan perintah berikut:

kubectl delete pods <pod>

Agar perintah di atas mengarah ke terminasi secara graceful, Pod tidak boleh menspesifikasikan pod.Spec.TerminationGracePeriodSeconds dengan nilai 0. Praktik untuk mengatur nilai pod.Spec.TerminationGracePeriodSeconds menjadi 0 detik merupakan hal yang tidak aman dan sangat tidak disarankan untuk Pod StatefulSet. Penghapusan secara graceful itu aman dan akan memastikan bahwa Pod akan mati secara gracefully sebelum kubelet menghapus nama dari apiserver.

Kubernetes (versi 1.5 atau lebih baru) tidak akan menghapus Pod hanya karena Node tidak dapat dijangkau. Pod yang berjalan pada Node yang tidak dapat dijangkau akan memasuki keadaan 'Terminating' atau 'Unknown' setelah waktu habis. Pod juga dapat memasuki keadaan ini saat pengguna berusaha melakukan penghapusan secara graceful terhadap Pod pada Node yang tidak dapat dijangkau. Cara yang hanya dapat dilakukan untuk menghapus Pod pada keadaan tersebut dari apiserver adalah:

  • Objek Node telah dihapus (baik oleh kamu, atau oleh Controller Node).
  • Kubelet pada Node yang tidak responsif akan menanggapi, lalu mematikan Pod dan menghapusnya dari apiserver.
  • Penghapusan paksa Pod oleh pengguna.

Praktik terbaik yang direkomendasikan adalah menggunakan pendekatan pertama atau kedua. Jika sebuah Node telah terkonfirmasi mati (contohnya terputus dari jaringan secara permanen, dimatikan, dll), maka objek Node dihapus. Jika Node mengalami partisi jaringan, maka coba selesaikan masalah ini atau menunggu masalah itu terselesaikan. Saat partisi terselesaikan, kubelet akan menyelesaikan penghapusan Pod serta membebaskan namanya dari apiserver.

Normalnya, sistem akan menyelesaikan penghapusan saat Pod tidak lagi berjalan pada Node, atau Node telah dihapus oleh administrator. Kamu dapat mengabaikan hal ini dengan menghapus paksa Pod.

Penghapusan Paksa

Penghapusan paksa tidak menunggu konfirmasi dari kubelet bahwa Pod telah diterminasi. Terlepas dari apakah penghapusan paksa sukses mematikan sebuah Pod, namanya akan segera dibebaskan dari apiserver. Hal ini berakibat controller StatefulSet akan membuat Pod pengganti dengan identitas yang sama; ini dapat menimbulkan duplikasi terhadap Pod apabila ternyata Pod tersebut masih berjalan, dan jika Pod tersebut masih dapat berkomunikasi dengan anggota Statefulset lainnya, hal ini berakibat terjadi pelanggaran semantik at most one dari StatefulSet yang telah dijamin.

Saat kamu menghapus paksa sebuah Pod StatefulSet, berarti kamu menjamin bahwa Pod tersebut tidak akan pernah lagi berkomunikasi dengan Pod lain pada StatefulSet dan namanya dapat dibebaskan secara aman untuk pembuatan penggantinya.

Jika kamu ingin menghapus paksa Pod dengan menggunakan kubectl versi >= 1.5, lakukan perintah berikut:

kubectl delete pods <pod> --grace-period=0 --force

Jika kamu menggunakan kubectl <= 1.4, kamu harus menghilangkan pilihan --force dan gunakan:

kubectl delete pods <pod> --grace-period=0

Jika setelah perintah ini dijalankan dan Pod tetap berada pada kondisi Unknown, gunakan perintah berikut untuk menghapus Pod dari klaster:

kubectl patch pod <pod> -p '{"metadata":{"finalizers":null}}'

Selalu jalankan penghapusan paksa Pod StatefulSet dengan hati-hati dan penuh pemahaman terhadap risiko yang dapat timbul.

Selanjutnya

Pelajari lebih lanjut debugging StatefulSet.

7.3 - HorizontalPodAutoscaler

HorizontalPodAutoscaler secara otomatis akan memperbanyak jumlah Pod di dalam ReplicationController, Deployment, ReplicaSet ataupun StatefulSet berdasarkan hasil observasi penggunaan CPU(atau, dengan metrik khusus, pada beberapa aplikasi yang menyediakan metrik). Perlu dicatat bahwa HorizontalPodAutoscale tidak dapat diterapkan pada objek yang tidak dapat diperbanyak, seperti DeamonSets.

HorizontalPodAutoscaler diimplementasikan sebagai Kubernetes API resource dan sebuah controller. Resource tersebut akan menentukan perilaku dari controller-nya. Kontroler akan mengubah jumlah replika pada ReplicationController atau pada Deployment untuk menyesuaikan dengan hasil observasi rata-rata penggunaan CPU sesuai dengan yang ditentukan oleh pengguna.

Bagaimana cara kerja HorizontalPodAutoscaler?

Diagram HorizontalPodAutoscaler

HorizontalPodAutoscaler diimplementasikan sebagai sebuah loop kontrol, yang secara berkala dikontrol oleh flag --horizontal-pod-autoscaler-sync-period pada controller manager (dengan nilai bawaan 15 detik).

Dalam setiap periode, controller manager melakukan kueri penggunaan sumber daya dan membandingkan dengan metrik yang dispesifikasikan pada HorizontalPodAutoscaler. Controller manager mendapat metrik dari sumber daya metrik API (untuk metrik per Pod) atau dari API metrik khusus (untuk semua metrik lainnya).

  • Untuk metrik per Pod (seperti CPU), controller mengambil metrik dari sumber daya metrik API untuk setiap Pod yang ditargetkan oleh HorizontalPodAutoscaler. Kemudian, jika nilai target penggunaan ditentukan, maka controller akan menghitung nilai penggunaan sebagai persentasi dari pengguaan sumber daya dari Container pada masing-masing Pod. Jika target nilai mentah (raw value) ditentukan, maka nilai metrik mentah (raw metric) akan digunakan secara langsung. Controller kemudian mengambil nilai rata-rata penggunaan atau nilai mentah (tergantung dengan tipe target yang ditentukan) dari semua Pod yang ditargetkan dan menghasilkan perbandingan yang digunakan untuk menentukan jumlah replika yang akan diperbanyak.

    Perlu dicatat bahwa jika beberapa Container pada Pod tidak memiliki nilai resource request, penggunaan CPU pada Pod tersebut tidak akan ditentukan dan autoscaler tidak akan melakukan tindakan apapun untuk metrik tersebut. Perhatikan pada bagian detail algoritma di bawah ini untuk informasi lebih lanjut mengenai cara kerja algoritma autoscale.

  • Untuk metrik khusus per Pod, controller bekerja sama seperti sumber daya metrik per Pod, kecuali Pod bekerja dengan nilai mentah, bukan dengan nilai utilisasi (utilization values).

  • Untuk objek metrik dan metrik eksternal, sebuah metrik diambil, dimana metrik tersebut menggambarkan objek tersebut. Metrik ini dibandingkan dengan nilai target untuk menghasilkan perbandingan seperti di atas. Pada API autoscaling/v2beta2, nilai perbandingan dapat secara opsional dibagi dengan jumlah Pod sebelum perbandingan dibuat.

Pada normalnya, HorizontalPodAutoscaler mengambil metrik dari serangkaian API yang sudah diagregat (custom.metric.k8s.io, dan external.metrics.k8s.io). API metrics.k8s.io biasanya disediakan oleh metric-server, dimana metric-server dijalankan secara terpisah. Perhatikan metrics-server sebagai petunjuk. HorizontalPodAutoscaler juga mengambil metrik dari Heapster secara langsung.

Perhatikan Dukungan untuk API metrik untuk lebih detail.

Autoscaler mengkases controller yang dapat diperbanyak (seperti ReplicationController, Deployment, dan ReplicaSet) dengan menggunakan scale sub-resource. Untuk lebih detail mengenai scale sub-resource dapat ditemukan di sini.

Detail Algoritma

Dari sudut pandang paling sederhana, controller HorizontalPodAutoscaler mengoperasikan perbandingan metrik yang diinginkan dengan kedaan metrik sekarang.

desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]

Sebagai contoh, jika nilai metrik sekarang adalah 200m dan nilai metrik yang diinginkan adalah 100m, jumlah replika akan ditambah dua kali lipat, karena 200.0 / 100.0 == 2.0. Jika nilai metrik sekarang adalah 50m, maka jumlah replika akan dikurangi setengah, karena 50.0 / 100.0 == 0.5. Kita tetap memperbanyak replika (scale) jika nilai perbandingan mendekati 1.0 (dalam toleransi yang dapat dikonfigurasi secata global, dari flag --horizontal-pod-autoscaler-tolerance dengan nilai bawaan 0.1.

Ketika targetAverageValue (nilai target rata-rata) atau targetAverageUtilization (target penggunaan rata-rata) ditentukan, currentMetricValue (nilai metrik sekaraang) dihitung dengan mengambil rata-rata dari metrik dari semua Pod yang ditargetkan oleh HorizontalPodAutoscaler. Sebelum mengecek toleransi dan menentukan nilai akhir, kita mengambil kesiapan Pod dan metrik yang hilang sebagai pertimbangan.

Semua Pod yang memiliki waktu penghapusan (Pod dalam proses penutupan) dan semua Pod yang mengalami kegagalan akan dibuang.

Jika ada metrik yang hilang dari Pod, maka Pod akan dievaluasi nanti. Pod dengan nilai metrik yang hilang akan digunakan untuk menyesuaikan jumlah akhir Pod yang akan diperbanyak atau dikurangi.

Ketika scaling dilakukan karena CPU, jika terdapat Pod yang akan siap (dengan kata lain Pod tersebut sedang dalam tahap inisialisasi) atau metrik terakhir dari Pod adalah metrik sebelum Pod dalam keadaan siap, maka Pod tersebut juga akan dievaluasi nantinya.

Akibat keterbatasan teknis, controller HorizontalPodAutoscaler tidak dapat menentukan dengan tepat kapan pertama kali Pod akan dalam keadaan siap ketika menentukan apakah metrik CPU tertentu perlu dibuang. Sebaliknya, HorizontalPodAutoscaler mempertimbangkan sebuah Pod "tidak dalam keadaan siap" jika Pod tersebut dalam keadaan tidak siap dan dalam transisi ke status tidak siap dalam waktu singkat, rentang waktu dapat dikonfigurasi, sejak Pod tersebut dijalankan. Rentang waktu tersebut dapat dikonfigurasi dengan flag --horizontal-pod-autoscaler-initial-readiness-delay dan waktu bawaannya adalah 30 detik. Ketika suatu Pod sudah dalam keadaan siap, Pod tersebut mempertimbangkan untuk siap menjadi yang pertama jika itu terjadi dalam waktu yang lebih lama, rentang waktu dapat dikonfigurasi, sejak Pod tersebut dijalankan. Rentang waktu tersebut dapat dikonfigurasi dengan flag --horizontal-pod-autoscaler-cpu-initialization-period dan nilai bawaannya adalah 5 menit.

Skala perbandingan dasar currentMetricValue / desiredMetricValue dihitung menggunakan Pod yang tersisa yang belum disisihkan atau dibuang dari kondisi di atas.

Jika terdapat metrik yang hilang, kita menghitung ulang rata-rata dengan lebih konservatif, dengan asumsi Pod mengkonsumsi 100% dari nilai yang diharapkan jika jumlahnya dikurangi (scale down) dan 0% jika jumlahnya diperbanyak (scale up). Ini akan mengurangi besarnya kemungkinan untuk scale.

Selanjutnya, jika terdapat Pod dalam keadaan tidak siap, dan kita akan memperbanyak replikas (scale up) tanpa memperhitungkan metrik yang hilang atau Pod yang tidak dalam keadaan siap, kita secara konservatif mengasumsikan Pod yang tidak dalam keadaan siap mengkonsumsi 0% dari metrik yang diharapkan, akhirnya meredam jumlah replika yang diperbanyak (scale up).

Seteleh memperhitungkan Pod yang tidak dalam keadaan siap dan metrik yang hilang, kita menghitung ulang menggunakan perbandingan. Jika perbandingan yang baru membalikkan arah scale-nya atau masih di dalam toleransi, kita akan melakukan scale dengan tepat. Jika tidak, kita menggunakan perbandingan yang baru untuk memperbanyak atau mengurangi jumlah replika.

Perlu dicatat bahwa nilai asli untuk rata-rata penggunaan dilaporkan kembali melalui status HorizontalPodAutoscaler, tanpa memperhitungkan Pod yang tidak dalam keadaan siap atau metrik yang hilang, bahkan ketika perbandingan yang baru digunakan.

Jika beberapa metrik ditentukan pada sebuah HorizontalPodAutoscaler, perhitungan dilakukan untuk setiap metrik dan nilai replika terbesar yang diharapkan akan dipilih. Jika terdapat metrik yang tidak dapat diubah menjadi jumlah replika yang diharapkan (contohnya terdapat kesalahan ketika mengambil metrik dari API metrik) dan pengurangan replika disarankan dari metrik yang dapat diambil, maka scaling akan diabaikan. Ini berarti HorizontalPodAutoscaler masih mampu untuk memperbanyak replika jika satu atau lebih metrik memberikan sebuah desiredReplicas lebih besar dari nilai yang sekarang.

Pada akhirnya, sebelum HorizontalPodAutoscaler memperbanyak target, rekomendasi scaling akan dicatat. Controller mempertimbangkan semua rekomendasi dalam rentang waktu yang dapat dikonfigurasi untuk memilih rekomendasi tertinggi. Nilai ini dapat dikonfigurasi menggunakan flag --horizontal-pod-autoscaler-downscale-stabilization, dengan nilai bawaan 5 menit. Ini berarti pengurangan replika akan terjadi secara bertahap, untuk mengurangi dampak dari perubahan nilai metrik yang cepat.

Objek API

HorizontalPodAutoscaler adalah sebuah API dalam grup autoscaling pada Kubernetes. Versi stabil, yang hanya mendukung untuk autoscale CPU, dapat ditemukan pada versi API autoscaling/v1.

Versi beta, yang mendukung untuk scaling berdasarkan memori dan metrik khusus, dapat ditemukan pada autoscaling/v2beta2. Field yang baru diperkenalkan pada autoscaling/v2beta2 adalah preserved sebagai anotasi ketika menggunakan autoscaling/v1.

Ketika kamu membuat sebuah HorizontalPodAutoscaler, pastikan nama yang ditentukan adalah valid nama subdomain DNS. Untuk lebih detail tentang objek API ini dapat ditemukan di Objek HorizontalPodAutoscaler.

Dukungan untuk HorizontalPodAutoscaler pada kubectl

Seperti sumber daya API lainnya, HorizontalPodAutoscaler didukung secara bawaan oleh kubectl. Kita dapat membuat autoscaler yang baru dengan menggunakan perintah kubectl create. Kita dapat melihat daftar autoscaler dengan perintah kubectl get hpa dan melihat deskripsi detailnya dengan perintah kubectl describe hpa. Akhirnya, kita dapat menghapus autoscaler meggunakan perintah kubectl delete hpa.

Sebagai tambahan, terdapat sebuah perintah khusus kubectl autoscaler untuk mempermudah pembuatan HorizontalPodAutoscaler. Sebagai contoh, mengeksekusi kubectl autoscaler rs foo --min=2 --max=5 --cpu-percent=80 akan membuat sebuah autoscaler untuk ReplicaSet foo, dengan target pengguaan CPU 80% dan jumlah replika antara 2 sampai dengan 5. Dokumentasi lebih detail tentang kubectl autoscaler dapat ditemukan di sini.

Autoscaling ketika Rolling Update

Saat ini, dimungkinkan untuk melakukan rolling update menggunakan objek Deployment, yang akan mengatur ReplicaSet untuk kamu. HorizontalPodAutoscaler hanya mendukung pendekatan terakhir: HorizontalPodAutoscaler terikat dengan objek Deployment, yang mengatur seberapa besar dari objek Deployment tersebut, dan Deployment bertugas untuk mengatur besar dari ReplicaSet.

HorizontalPodAutoscaler tidak bekerja dengan rolling update yang menggunakan manipulasi pada ReplicationContoller secara langsung, dengan kata lain kamu tidak bisa mengikat HorizontalPodAutoscaler dengan ReplicationController dan melakukan rolling update. Alasan HorizontalPodAutoscaler tidak bekerja ketika rolling update membuat ReplicationController yang baru adalah HorizontalPodAutoscaler tidak akan terikat dengan ReplicationController yang baru tersebut.

Dukungan untuk Cooldown / Penundaan

Ketika mengolah scaleing dari sebuah grup replika menggunakan HorizonalPodAutoscaler, jumlah replika dimungkinkan tetap berubah secara sering disebabkan oleh perubahan dinamis dari metrik yang dievaluasi. Hal ini sering disebut dengan thrashing.

Mulai dari versi 1.6, operator klaster dapat mengatasi masalah ini dengan mengatur konfigurasi HorizontalPodAutoscaler global sebagai flag kube-controller-manager.

Mulai dari versi 1.12, sebuah algoritma pembaruan baru menghilangkan kebutuhan terhadap penundaan memperbanyak replika (upscale).

  • --horizontal-pod-autoscaler-downscale-stabilization: Nilai untuk opsi ini adalah sebuah durasi yang menentukan berapa lama autoscaler menunggu sebelum operasi pengurangan replika (downscale) yang lain dilakukan seteleh operasi sekarang selesai. Nilai bawaannya adalah 5 menit (5m0s).

Dukungan untuk Beberapa Metrik

Kubernetes versi 1.6 menambah dukungan untuk scaling berdasarkan beberapa metrik. Kamu dapat menggunakan API versi autoscaling/v2beta2 untuk menentukan beberapa metrik yang akan digunakan HorizontalPodAutoscaler untuk menambah atau mengurangi jumlah replika. Kemudian, controller HorizontalPodAutoscaler akan mengevaluasi setiap metrik dan menyarankan jenis scaling yang baru berdasarkan metrik tersebut. Jumlah replika terbanyak akan digunakan untuk scale yang baru.

Dukungan untuk Metrik Khusus

Kubernetes versi 1.6 menambah dukungan untuk menggunakan metrik khusus pada HorizontalPodAutoscaler. Kamu dapat menambahkan metrik khusus untuk HorizontalPodAutoscaler pada API versi autoscaling/v2beta2. Kubernetes kemudian memanggil API metrik khusus untuk mengambil nilai dari metrik khusus.

Lihat Dukungan untuk API metrik untuk kubutuhannya.

Dukungan untuk API metrik

Secara standar, controller HorizontalPodAutoscaler mengambil metrik dari beberapa API. Untuk dapat mengakses API ini, administrator klaster harus memastikan bahwa:

  • API Later Pengumpulan diaktifkan.

  • API berikut ini terdaftar:

    • Untuk metrik sumber daya, ini adalah API metrics.k8s.io, pada umumnya disediakan oleh metrics-server. API tersebut dapat diaktifkan sebagai addon atau tambahan pada klaster.

    • Untuk metrik khusus, ini adalah API custom.metrics.k8s.io. API ini disediakan oleh API adaptor server yang disediakan oleh vendor yang memberi solusi untuk metrik. Cek dengan pipeline metrikmu atau daftar solusi yang sudah diketahui. Jika kamu ingin membuat sendiri, perhatikan boilerplate berikut untuk memulai.

    • Untuk metrik eksternal, ini adalah API external.metrics.k8s.io. API ini mungkin disediakan oleh penyedia metrik khusus diatas.

  • Nilai dari --horizontal-pod-autoscaler-use-rest-clients adalah true atau tidak ada. Ubah nilai tersebut menjadi false untuk mengubah ke autoscaling berdasarkan Heapster, dimana ini sudah tidak didukung lagi.

Untuk informasi lebih lanjut mengenai metrik-metrik ini dan bagaimana perbedaan setiap metrik, perhatikan proposal desain untuk HPA V2, custom.metrics.k8s.io dan external.metrics.k8s.io.

Untuk contoh bagaimana menggunakan metrik-metrik ini, perhatikan panduan penggunaan metrik khusus dan panduan penggunaan metrik eksternal.

Dukungan untuk Perilaku Scaling yang dapat Dikonfigurasi

Mulai dari versi v1.18, API v2beta2 mengizinkan perilaku scaling dapat dikonfigurasi melalui field behavior pada HorizontalPodAutoscaler. Perilaku scaling up dan scaling down ditentukan terpisah pada field slaceUp dan field scaleDown, dibawah dari field behavior. Sebuah stabilisator dapat ditentukan untuk kedua arah scale untuk mencegah perubahan replika yang terlalu berbeda pada target scaling. Menentukan scaling policies akan mengontrol perubahan replika ketika scaling.

Scaling Policies

Satu atau lebih scaling policies dapat ditentukan pada field behavior. Ketika beberapa policies ditentukan, policy yang mengizinkan scale terbesar akan dipilih secara default. Contoh berikut menunjukkan perilaku ketika mengurangi replika:

behavior:
  scaleDown:
    policies:
    - type: Pods
      value: 4
      periodSeconds: 60
    - type: Percent
      value: 10
      periodSeconds: 60

Ketika jumlah Pod lebih besar dari 40, policy kedua akan digunakan untuk scaling down. Misalnya, jika terdapat 80 replika dan target sudah di scale down ke 10 replika, 8 replika akan dikurangi pada tahapan pertama. Pada iterasi berikutnya, ketika jumlah replika adalah 72, 10% dari Pod adalah 7.2 tetapi akan dibulatkan menjadi 8. Dalam setiap iterasi pada controller autoscaler jumlah Pod yang akan diubah akan dihitung ulang berdarkan jumlah replika sekarang. Ketika jumlah replika dibawah 40, policy pertama (Pods) akan digunakan dan 4 replika akan dikurangi dalam satu waktu.

periodSeconds menunjukkan berapa lama waktu pada iterasi terkhir untuk menunjukkan policy mana yang akan digunakan. Policy pertama mengizinkan maksimal 4 replika di scale down dalam satu menit. Policy kedua mengixinkan maksimal 10% dari total replika sekarang di scale down dalam satu menit.

Pemilihan policy dapat diubah dengan menentukannya pada field selectPolicy untuk sebuah arah scale (baik scale up ataupun scale down). Dengan menentukan nilai Min, HorizontalPodAutoscaler akan memilih policy yang mengizinkan pergantian replika paling sedikit. Dengan menuntukan nilai Disable, akan menghentikan scaling pada arah scale tersebut.

Jendela Stabilisasi

Jendela stabilisasi digunakan untuk membatasi perubahan replika yang terlalu drastis ketika metrik yang digunakan untuk scaling tetap berubah-ubah. Jendela stabilisasi digunakan oleh algoritma autoscaling untuk memperhitungkan jumlah replika yang diharapkan dari scaling sebelumnya untuk mencengah *scaling. Berikut adalah contoh penggunaan jendela stabilisasi pada scaleDown.

scaleDown:
  stabilizationWindowSeconds: 300

Ketika metrik menandakan bahwa replika pada target akan dikurangi, algoritma akan memperhatikan jumlah replika yang diharapkan sebelumnya dan menggunakan nilai terbesar dari interval yang ditentukan. Pada contoh diatas, semua jumlah replika yang diharapkan pada 5 menit yang lalu akan dipertimbangkan.

Perilaku Standar

Untuk menggunakan scaling khusus, tidak semua field perlu ditentukan. Hanta nilai yang perlu diubah saja yang ditentukan. Nilai khusus ini akan digabungkan dengan nilai standar. Berikut adalah nilai standar perilaku pada algoritma yang digunakan HorizontalPodAutoscaler.

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
    - type: Pods
      value: 4
      periodSeconds: 15
    selectPolicy: Max

Untuk scaleDown, nilai dari jendela stabilisasi adalah 300 detik (atau nilai dari flag --horizontal-pod-autoscaler-downscale-stabilization jika ditentukan). Hanya terdapat satu policy, yaitu mengizinkan menghapus 100% dari replika yang berjalan, artinya target replikasi di scale ke jumlah replika minimum. Untuk scaleUp, tidak terdapat jendela stabilisasi. Jika metrik menunjukkan bahwa replika pada target perlu diperbanyak, maka replika akan diperbanyak di secara langsung. Untuk scaleUp terdapat dua policy, yaitu empat Pod atau 100% dari replika yang berjalan akan ditambahkan setiap 15 detik sampai HorizontalPodAutoscaler dalam keadaan stabil.

Contoh: Mengubah Jendela Stabiliasi pada field scaleDown

Untuk membuat jendela stabilisai untuk pengurangan replika selama satu menit, perilaku berikut ditambahkan pada HorizontalPodAutoscaler.

behavior:
  scaleDown:
    stabilizationWindowSeconds: 60

Contoh: Membatasi nilai scale down

Untuk membatasi total berapa Pod yang akan dihapus, 10% setiap menut, perilaku berikut ditambahkan pada HorizontalPodAutoscaler.

behavior:
  scaleDown:
    policies:
    - type: Percent
      value: 10
      periodSeconds: 60

Untuk mengizinkan penghapusan 5 Pod terakhir, policy lain dapat ditambahkan.

behavior:
  scaleDown:
    policies:
    - type: Percent
      value: 10
      periodSeconds: 60
    - type: Pods
      value: 5
      periodSeconds: 60
    selectPolicy: Max

Contoh: menonakfitkan scale down

Nilai Disable pada selectPolicy akan menonaktifkan scaling pada arah yang ditentukan. Untuk mencegah pengurangan replika dapat menggunakan policy berikut.

behavior:
  scaleDown:
    selectPolicy: Disabled

Selanjutnya

7.4 - Panduan HorizontalPodAutoscaler

HorizontalPodAutoscaler secara otomatis akan memperbanyak jumlah Pod di dalam ReplicationController, Deployment, ReplicaSet ataupun StatefulSet berdasarkan hasil observasi penggunaan CPU (atau, dengan metrik khusus, pada beberapa aplikasi yang menyediakan metrik).

Laman ini memandu kamu dengan contoh pengaktifan HorizontalPodAutoscaler untuk server php-apache. Untuk informasi lebih lanjut tentang perilaku HorizontalPodAutoscaler, lihat Petunjuk pengguna HorizontalPodAutoscaler.

Contoh dibawah ini membutuhkan klaster Kubernetes dan kubectl di versi 1.2 atau yang lebih baru yang sedang berjalan. Server metrik sebagai pemantauan perlu diluncurkan di dalam sebuah klaster untuk menyediakan metrik melalui metrik API sumber daya, karena HorizontalPodAutoscaler menggunakan API ini untuk mengumpulkan metrik. Petunjuk untuk menerapkan server metrik ada di repositori GitHub dari server metrik, jika kamu mengikuti petunjuk memulai panduan GCE, metrik-pemantauan server akan diaktifkan secara default

Untuk menentukan beberapa metrik sumber daya untuk HorizontalPodAutoscaler, kamu harus memiliki klaster Kubernetes dan kubectl di versi 1.6 atau yang lebih baru. Selanjutnya, untuk menggunakan metrik khusus, klaster kamu harus dapat berkomunikasi dengan server API yang menyediakan API metrik khusus. Terakhir, untuk menggunakan metrik yang tidak terkait dengan objek Kubernetes apa pun, kamu harus memiliki klaster Kubernetes pada versi 1.10 atau yang lebih baru, dan kamu harus dapat berkomunikasi dengan server API yang menyediakan API metrik eksternal. Lihat Panduan pengguna HorizontalPodAutoscaler untuk detail lebih lanjut.

Menjalankan & mengekspos server php-apache

Untuk mendemonstrasikan HorizontalPodAutoscaler kita akan menggunakan image Docker khusus berdasarkan image php-apache. Dockerfile memiliki konten berikut:

FROM php:5-apache
ADD index.php /var/www/html/index.php
RUN chmod a+rx index.php

Bagian ini mendefinisikan laman index.php yang melakukan beberapa komputasi intensif CPU:

<?php
  $x = 0.0001;
  for ($i = 0; $i <= 1000000; $i++) {
    $x += sqrt($x);
  }
  echo "OK!";
?>

Pertama, kita akan memulai Deployment yang menjalankan image dan mengeksposnya sebagai Service menggunakan konfigurasi berikut:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  selector:
    matchLabels:
      run: php-apache
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  labels:
    run: php-apache
spec:
  ports:
  - port: 80
  selector:
    run: php-apache

Jalankan perintah berikut:

kubectl apply -f https://k8s.io/examples/application/php-apache.yaml
deployment.apps/php-apache created
service/php-apache created

Membuat HorizontalPodAutoscaler

Sekarang server sudah berjalan, selanjutnya kita akan membuat autoscaler menggunakan kubectl autoscale. Perintah berikut akan membuat HorizontalPodAutoscaler yang mengelola antara 1 dan 10 replika Pod yang dikontrol oleh Deployment php-apache yang kita buat pada langkah pertama instruksi ini. Secara kasar, HPA akan menambah dan mengurangi jumlah replika (melalui Deployment) untuk mempertahankan pemakaian CPU rata-rata di semua Pod sebesar 50% (karena setiap Pod meminta 200 mili-core menurut kubectl run), ini berarti penggunaan CPU rata-rata adalah 100 mili-core). Lihat ini untuk detail lebih lanjut tentang algoritmanya.

kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled

Kita dapat memeriksa status autoscaler saat ini dengan menjalankan:

kubectl get hpa
NAME         REFERENCE                     TARGET    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   0% / 50%  1         10        1          18s

Harap dicatat bahwa konsumsi CPU saat ini adalah 0% karena kita tidak mengirimkan permintaan apa pun ke server (kolom TARGET menunjukkan nilai rata-rata di semua Pod yang dikontrol oleh Deployment yang sesuai).

Menambahkan beban

Sekarang, kita akan melihat bagaimana autoscaler bereaksi terhadap peningkatan beban. Kita akan memulai sebuah Container, dan mengirimkan perulangan kueri tak terbatas ke Service php-apache (jalankan di terminal yang berbeda):

kubectl run -it --rm load-generator --image=busybox /bin/sh

Hit enter for command prompt

while true; do wget -q -O- http://php-apache; done

Dalam satu menit atau lebih, kita akan melihat beban CPU yang lebih tinggi dengan menjalankan:

kubectl get hpa
NAME         REFERENCE                     TARGET      MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   305% / 50%  1         10        1          3m

Di sini, konsumsi CPU meningkat hingga 305% dari permintaan. Hasilnya, Deployment mengubah ukurannya menjadi 7 replika:

kubectl get deployment php-apache
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   7/7      7           7           19m

Menghentikan beban

Kita akan menyudahi contoh dengan menghentikan beban pengguna.

Di terminal tempat kita membuat Container dengan image busybox, hentikan pembangkitan beban dengan mengetik <Ctrl> + C.

Kemudian kita akan memverifikasi status hasil (setelah satu menit atau lebih):

kubectl get hpa
NAME         REFERENCE                     TARGET       MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache/scale   0% / 50%     1         10        1          11m
kubectl get deployment php-apache
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   1/1     1            1           27m

Di sini penggunaan CPU turun menjadi 0, sehingga HPA secara otomatis melakukan penyekalaan jumlah replika kembali menjadi 1.

Penyekalaan otomatis pada metrik multipel dan metrik kustom

Kamu dapat memperkenalkan metrik tambahan untuk digunakan saat melakukan penyekalaan otomatis pada Deployment php-apache dengan menggunakan versi API autoscaling / v2beta2.

Pertama, dapatkan YAML HorizontalPodAutoscaler kamu dalam bentuk autoscaling / v2beta2:

kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml

Buka berkas /tmp/hpa-v2.yaml di editor, dan kamu akan melihat YAML yang terlihat seperti ini:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
      current:
        averageUtilization: 0
        averageValue: 0

Perhatikan bahwa kolom targetCPUUtilizationPercentage telah diganti dengan himpunan yang disebut metrics. Metrik penggunaan CPU adalah resource metric, merepresentasikan sebagai persentase sumber daya ditentukan pada Container Pod. Perhatikan bahwa kamu dapat menentukan metrik sumber daya selain CPU. Secara bawaan, satu-satunya metrik sumber daya lain yang didukung adalah memori. Sumber daya ini tidak mengubah nama dari klaster ke klaster, dan harus selalu tersedia, selama API metrics.k8s.io tersedia.

Kamu juga dapat menentukan metrik sumber daya dalam nilai secara langsung, bukan sebagai persentase dari nilai yang diminta, dengan menggunakan target.type dari AverageValue sebagai ganti Utilization, dan menyetel field target.averageValue yang sesuai, bukan target.averageUtilization.

Ada dua jenis metrik lainnya, keduanya dianggap sebagai metrik khusus: metrik Pod dan metrik objek. Metrik ini memungkinkan untuk memiliki nama yang spesifik untuk klaster, dan membutuhkan lebih banyak pengaturan pemantauan klaster lanjutan.

Jenis metrik alternatif yang pertama adalah metrik Pod. Metrik ini mendeskripsikan Pod, dan dirata-ratakan bersama di seluruh Pod dan dibandingkan dengan nilai target untuk menentukan jumlah replika. Mereka bekerja seperti metrik sumber daya, kecuali bahwa mereka hanya mendukung jenis target dari AverageValue.

Metrik Pod ditentukan menggunakan blok metrik seperti ini:

type: Pods
pods:
  metric:
    name: packets-per-second
  target:
    type: AverageValue
    averageValue: 1k

Jenis metrik alternatif kedua adalah metrik objek. Metrik ini mendeskripsikan perbedaan objek di Namespace yang sama, bukan mendeskripsikan Pod. Metriknya belum tentu diambil dari objek; mereka hanya mendeskripsikannya. Metrik objek mendukung jenis target baik Value dan AverageValue. Dengan Value, target dibandingkan langsung dengan yang dikembalikan metrik dari API. Dengan AverageValue, nilai yang dikembalikan dari API metrik khusus dibagi dengan jumlah Pod sebelum dibandingkan dengan target. Contoh berikut adalah YAML representasi dari metrik requests-per-second.

type: Object
object:
  metric:
    name: requests-per-second
  describedObject:
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    name: main-route
  target:
    type: Value
    value: 2k

Jika kamu memberikan beberapa blok metrik seperti itu, HorizontalPodAutoscaler akan mempertimbangkan setiap metrik secara bergantian. HorizontalPodAutoscaler akan menghitung jumlah replika yang diusulkan untuk setiap metrik, lalu memilih satu dengan jumlah replika tertinggi.

Misalnya, jika sistem pemantauan kamu mengumpulkan metrik tentang lalu lintas jaringan, kamu dapat memperbarui definisi di atas menggunakan kubectl edit agar terlihat seperti ini:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
  - type: Pods
    pods:
      metric:
        name: packets-per-second
      target:
        type: AverageValue
        averageValue: 1k
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        name: main-route
      target:
        type: Value
        value: 10k
status:
  observedGeneration: 1
  lastScaleTime: <some-time>
  currentReplicas: 1
  desiredReplicas: 1
  currentMetrics:
  - type: Resource
    resource:
      name: cpu
    current:
      averageUtilization: 0
      averageValue: 0
  - type: Object
    object:
      metric:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        name: main-route
      current:
        value: 10k

Kemudian, HorizontalPodAutoscaler kamu akan mencoba memastikan bahwa setiap Pod mengonsumsi kira-kira 50% dari CPU yang diminta, melayani 1000 paket per detik, dan semua Pod berada di belakang Ingress rute utama melayani total 10.000 permintaan per detik.

Penyekalaan otomatis pada metrik yang lebih spesifik

Banyak pipeline metrik memungkinkan kamu mendeskripsikan metrik baik berdasarkan nama atau kumpulan tambahan deskriptor yang disebut labels. Untuk semua jenis metrik non-sumber daya (Pod, objek, dan eksternal, dijelaskan seperti dibawah), kamu dapat menentukan pemilih label tambahan yang diteruskan ke pipa metrik kamu. Misalnya, jika kamu mengumpulkan metrik http_requests dengan label verb , kamu dapat menentukan blok metrik berikut untuk diskalakan hanya pada permintaan GET:

type: Object
object:
  metric:
    name: http_requests
    selector: {matchLabels: {verb: GET}}

Selector ini menggunakan sintaksis yang sama dengan selector lengkap label Kubernetes. Pipa pemantauan menentukan cara mengecilkan beberapa seri menjadi satu nilai, jika nama dan pemilih cocok dengan beberapa seri. Selektor bersifat aditif, dan tidak dapat memilih metrik yang mendeskripsikan objek yang bukan objek target (target pod dalam kasus tipe Pod, dan objek yang dijelaskan dalam kasus tipe Objek).

Penyekalaan otomatis pada metrik yang tidak terkait dengan objek Kubernetes

Aplikasi yang berjalan di Kubernetes mungkin perlu melakukan penyekalaan otomatis berdasarkan metrik yang tidak memiliki hubungan yang jelas dengan objek apa pun di klaster Kubernetes, seperti metrik yang mendeskripsikan layanan yang dihosting tanpa korelasi langsung dengan namespace Kubernetes. Di Kubernetes 1.10 dan yang lebih baru, kamu dapat menangani kasus penggunaan ini dengan metrik eksternal.

Menggunakan metrik eksternal membutuhkan pengetahuan tentang sistem pemantauanmu; penyiapannya mirip dengan yang diperlukan saat menggunakan metrik khusus. Metrik eksternal memungkinkan kamu menskalakan klaster kamu secara otomatis berdasarkan metrik apa pun yang tersedia di sistem pemantauanmu. Cukup berikan blok metric dengan name dan selector (pemilih), seperti di atas, dan gunakan jenis metrik External, bukan Object. Jika beberapa series cocok dengan metricSelector, jumlah dari nilai mereka akan digunakan oleh HorizontalPodAutoscaler. Metrik eksternal mendukung jenis target Value dan AverageValue, yang berfungsi persis sama seperti saat kamu menggunakan tipe Object.

Misalnya, jika aplikasi kamu memproses tugas dari layanan antrian yang dihosting, kamu dapat menambahkan bagian berikut ke manifes HorizontalPodAutoscaler untuk menentukan bahwa kamu memerlukan satu pekerja per 30 tugas yang belum diselesaikan.

- type: External
  external:
    metric:
      name: queue_messages_ready
      selector: "queue=worker_tasks"
    target:
      type: AverageValue
      averageValue: 30

Jika memungkinkan, lebih baik menggunakan target metrik khusus daripada metrik eksternal, karena lebih mudah bagi administrator klaster untuk mengamankan API metrik khusus. API metrik eksternal berpotensi memungkinkan akses ke metrik apa pun, jadi administrator klaster harus berhati-hati saat mengeksposnya.

Lampiran: Kondisi Status Horizontal Pod Autoscaler

Saat menggunakan bentuk autoscaling/v2beta2 dari HorizontalPodAutoscaler, kamu akan dapat melihat status condition yang ditetapkan oleh Kubernetes pada HorizontalPodAutoscaler. Status condition ini menunjukkan apakah HorizontalPodAutoscaler dapat melakukan penyekalaan atau tidak, dan apakah saat ini dibatasi atau tidak.

Kondisi muncul pada field status.conditions. Untuk melihat kondisi yang memengaruhi HorizontalPodAutoscaler, kita bisa menggunakan kubectl description hpa:

kubectl describe hpa cm-test
Name:                           cm-test
Namespace:                      prom
Labels:                         <none>
Annotations:                    <none>
CreationTimestamp:              Fri, 16 Jun 2017 18:09:22 +0000
Reference:                      ReplicationController/cm-test
Metrics:                        ( current / target )
  "http_requests" on pods:      66m / 500m
Min replicas:                   1
Max replicas:                   4
ReplicationController pods:     1 current / 1 desired
Conditions:
  Type                  Status  Reason                  Message
  ----                  ------  ------                  -------
  AbleToScale           True    ReadyForNewScale        the last scale time was sufficiently old as to warrant a new scale
  ScalingActive         True    ValidMetricFound        the HPA was able to successfully calculate a replica count from pods metric http_requests
  ScalingLimited        False   DesiredWithinRange      the desired replica count is within the acceptable range
Events:

Untuk HorizontalPodAutoscaler ini, kita dapat melihat beberapa kondisi yang menandakan dalam keadaan sehat. Yang pertama, AbleToScale, menunjukkan apakah HPA dapat mengambil dan memperbarui skala atau tidak, serta apakah kondisi terkait backoff akan mencegah penyekalaan atau tidak. Yang kedua, ScalingActive, menunjukkan apakah HPA diaktifkan atau tidak (yaitu jumlah replika target bukan nol) dan mampu menghitung skala yang diinginkan. Jika False, biasanya menunjukkan masalah dengan pengambilan metrik. Terakhir, kondisi terakhir, ScalingLimited, menunjukkan bahwa skala yang diinginkan telah dibatasi oleh maksimum atau minimum HorizontalPodAutoscaler. Ini adalah indikasi bahwa kamu mungkin ingin menaikkan atau menurunkan batasan jumlah replika minimum atau maksimum pada HorizontalPodAutoscaler kamu.

Lampiran: Kuantitas

Semua metrik di HorizontalPodAutoscaler dan metrik API ditentukan menggunakan notasi bilangan bulat khusus yang dikenal di Kubernetes sebagai kuantitas. Misalnya, kuantitas 10500m akan ditulis sebagai 10.5 dalam notasi desimal. Metrik API akan menampilkan bilangan bulat tanpa sufiks jika memungkinkan, dan secara umum akan mengembalikan kuantitas dalam satuan mili. Ini berarti kamu mungkin melihat nilai metrik berfluktuasi antara 1 dan 1500m, atau 1 dan 1,5 ketika ditulis dalam notasi desimal.

Lampiran: Skenario lain yang memungkinkan

Membuat autoscaler secara deklaratif

Daripada menggunakan perintah kubectl autoscale untuk membuat HorizontalPodAutoscaler secara imperatif, kita dapat menggunakan berkas berikut untuk membuatnya secara deklaratif:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

Kita akan membuat autoscaler dengan menjalankan perintah berikut:

kubectl create -f https://k8s.io/examples/application/hpa/php-apache.yaml
horizontalpodautoscaler.autoscaling/php-apache created

8 - Mengakes Aplikasi-aplikasi di sebuah Klaster

8.1 - Antarmuka Pengguna Berbasis Web (Dashboard)

Dashboard adalah antarmuka pengguna Kubernetes. Kamu dapat menggunakan Dashboard untuk men-deploy aplikasi yang sudah dikontainerisasi ke klaster Kubernetes, memecahkan masalah pada aplikasi kamu, dan mengatur sumber daya klaster. Kamu dapat menggunakan Dashboard untuk melihat ringkasan dari aplikasi yang sedang berjalan di klaster kamu, dan juga membuat atau mengedit objek individu sumber daya Kubernetes (seperti Deployment, Job, DaemonSet, dll.). Sebagai contoh, kamu dapat mengembangkan sebuah Deployment, menginisiasi sebuah pembaruan bertahap (rolling update), memulai kembali sebuah Pod atau men-deploy aplikasi baru menggunakan sebuah deploy wizard.

Dashboard juga menyediakan informasi tentang status dari sumber daya Kubernetes di klaster kamu dan kesalahan apapun yang mungkin telah terjadi..

Antarmuka Pengguna Dashboard Kubernetes

Men-deploy Antarmuka Pengguna Dashboard

Antarmuka Dashboard tidak ter-deploy secara bawaan. Untuk men-deploy-nya, kamu dapat menjalankan perintah berikut:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml

Mengakses Antarmuka Dashboard

Untuk melindungi data klaster kamu, pen-deploy-an Dashboard menggunakan sebuah konfigurasi RBAC yang minimal secara bawaan. Saat ini, Dashboard hanya mendukung otentikasi dengan Bearer Token. Untuk membuat token untuk demo, kamu dapat mengikuti petunjuk kita untuk membuat sebuah contoh pengguna.

Proksi antarmuka baris perintah (CLI)

Kamu dapat mengakses Dashboard menggunakan perkakas CLI kubectl dengan menjalankan perintah berikut:

kubectl proxy

Kubectl akan membuat Dashboard tersedia di http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/.

Antarmuka pengguna berbasis web tersebut hanya dapat di akses dari mesin dimana perintah tersebut dijalankan. Lihat kubectl proxy --help untuk lebih lanjut.

Tampilan selamat datang

Ketika kamu mengakses Dashboard di klaster yang kosong, kamu akan melihat laman selamat datang. Laman ini berisi tautan ke dokumen ini serta tombol untuk men-deploy aplikasi pertama kamu. Selain itu, kamu dapat melihat aplikasi-aplikasi sistem mana saja yang berjalan secara bawaan di Namespace kube-system dari klaster kamu, misalnya Dashboard itu sendiri.

Kubernetes Dashboard welcome page

Men-deploy aplikasi yang sudah dikontainerisasi

Dashboard memungkinkan kamu untuk membuat dan men-deploy aplikasi yang sudah dikontainerisasi sebagai Deployment dan Service opsional dengan sebuah wizard sederhana. Kamu secara manual dapat menentukan detail aplikasi, atau mengunggah sebuah berkas YAML atau JSON yang berisi konfigurasi aplikasi.

Tekan tombol CREATE di pojok kanan atas di laman apapun untuk memulai.

Menentukan detail aplikasi

Deploy wizard meminta kamu untuk menyediakan informasi sebagai berikut:

  • App name (wajib): Nama dari aplikasi kamu. Sebuah label dengan nama tersebut akan ditambahkan ke Deployment dan Service, jika ada, akan di-deploy.

    Nama aplikasi harus unik di dalam Namespace Kubernetes yang kamu pilih. Nama tersebut harus dimulai dengan huruf kecil, dan diakhiri dengan huruf kecil atau angka, dan hanya berisi huruf kecil, angka dan tanda hubung (-). Nama tersebut juga dibatasi hanya 24 karakter. Spasi di depan dan belakang nama tersebut diabaikan.

  • Container image (wajib): Tautan publik dari sebuah image kontainer Docker pada registry apapun, atau sebuah image privat (biasanya di-hosting di Google Container Registry atau Docker Hub). Spesifikasi image kontainer tersebut harus diakhiri dengan titik dua.

  • Number of pods (wajib): Berapa banyak Pod yang kamu inginkan untuk men-deploy aplikasimu. Nilainya haruslah sebuah bilangan bulat positif.

    Sebuah Deployment akan terbuat untuk mempertahankan jumlah Pod di klaster kamu.

  • Service (opsional): Untuk beberapa aplikasi (misalnya aplikasi frontend) kamu mungkin akan mengekspos sebuah Service ke alamat IP publik yang mungkin berada diluar klaster kamu(Service eksternal). Untuk Service eksternal, kamu mungkin perlu membuka lebih dari satu porta jaringan untuk mengeksposnya. Lihat lebih lanjut di sini.

    Service lainnya yang hanya dapat diakses dari dalam klaster disebut Service internal.

    Terlepas dari jenis Service, jika kamu memilih untuk membuat sebuah Service dan Container kamu berjalan di sebuah porta(arah masuk), kamu perlu menentukan dua porta. Service akan memetakan porta(arah masuk) ke porta target yang ada di sisi Container. Service akan mengarahkan ke Pod-Pod kamu yang sudah di-deploy. Protokol yang didukung adalah TCP dan UDP. Nama DNS internal untuk Service ini akan sesuai dengan nama aplikasi yang telah kamu tentukan diatas.

Jika membutuhkan, kamu dapat membuka bagian Advanced options di mana kamu dapat menyetel lebih banyak pengaturan:

  • Description: Tels yang kamu masukkan ke sini akan ditambahkan sebagai sebuah anotasi ke Deployment dan akan ditampilkan di detail aplikasi.

  • Labels: Label-label bawaan yang akan digunakan untuk aplikasi kamu adalah name dan version aplikasi. Kamu dapat menentukan label lain untuk diterapkan ke Deployment, Service (jika ada), dan Pod, seperti release, environment, tier, partition, dan track rilis.

    Contoh:

    release=1.0
    tier=frontend
    environment=pod
    track=stable
    
  • Namespace: Kubernetes mendukung beberapa klaster virtual yang berjalan di atas klaster fisik yang sama. Klaster virtual ini disebut Namespace. Mereka mengizinkan kamu untuk mempartisi sumber daya ke beberapa grup yang diberi nama secara logis.

    Dashboard menampilkan semua Namespace yang tersedia dalam sebuah daftar dropdown, dan mengizinkan kamu untuk membuat Namespace baru. Nama yang diizinkan untuk Namespace terdiri dari maksimal 63 karakter alfanumerik dan tanda hubung (-), dan tidak boleh ada huruf kapital. Nama dari Namespace tidak boleh terdiri dari angka saja. Jika nama Namespace disetel menjadi sebuah angka, misalnya 10, maka Pod tersebut akan ditaruh di Namespace default.

    Jika pembuatan Namespace berhasil, Namespace tersebut akan dipilih secara bawaan. Jika pembuatannya gagal, maka Namespace yang pertama akan terpilih.

  • Image Pull Secret: Jika kamu menggunakan image kontainer Docker yang privat, mungkin diperlukan kredensial pull secret.

    Dashboard menampilkan semua secret yang tersedia dengan daftar dropdown, dan mengizinkan kamu untuk membuat secret baru. Nama secret tersebut harus mengikuti aturan Nama DNS, misalnya new.image-pull.secret. Isi dari sebuah secret harus dienkode dalam bentuk base64 dan ditentukan dalam sebuah berkas .dockercfg. Nama kredensial dapat berisi maksimal 253 karakter.

    Jika pembuatan image pull secret berhasil, image pull secret tersebut akan terpilih secara bawaan. Jika gagal, maka tidak ada secret yang dipilih.

  • CPU requirement (cores) dan Memory requirement (MiB): Kamu dapat menentukan batasan sumber daya minimal untuk Container. Secara bawaan, Pod-Pod berjalan dengan CPU dan memori yang tak dibatasi.

  • Run command dan Run command arguments: Secara bawaan, Container-Container kamu akan menjalankan perintah entrypoint bawaan dari image Docker yang ditentukan. Kamu dapat menggunakan opsi Run command dan Run command arguments untuk mengganti bawaannya.

  • Run as priveleged: Pengaturan ini untuk menentukan sebuah proses yang berjalan dalam privileged container sepadan dengan proses yang berjalan sebagai root pada host-nya. Priveleged container dapat menggunakan kemampuan seperti memanipulasi stack jaringan dan mengakses perangkat-perangkat.

  • Environment variables: Kubernetes mengekspos Service melalui environment variable. Kamu dapat membuat environment variable atau meneruskan argumen ke perintah-perintah untuk menjalankan Container dengan nilai dari environment variable. Environment Variable dapat digunakan pada aplikasi-aplikasi untuk menemukan sebuah Service. Nilai environment variable dapat merujuk ke variabel lain menggunakan sintaksis $(VAR_NAME).

Menggungah berkas YAML atau JSON

Kubernetes mendukung pengaturan deklaratif. Dengan cara ini, semua pengaturan disimpan dalam bentuk berkas YAML atau JSON menggunakan skema sumber daya [API.

Sebagai alternatif untuk menentukan detail aplikasi di deploy wizard, kamu dapat menentukan sendiri detail aplikasi kamu dalam berkas YAML atau JSON, dan mengunggah berkas tersebut menggunakan Dashboard.

Menggunakan Dashboard

Bagian ini akan menjelaskan bagian-bagian yang ada pada Antarmuka Dashboard Kubernetes; apa saja yang mereka sediakan dan bagaimana cara menggunakanya.

Ketika ada objek Kubernetes yang sudah didefinisikan di dalam klaster, Dashboard akan menampilkanya di tampilan awalnya. Secara bawaan hanya objek-objek dalam Namespace default saja yang ditampilkan di sini dan kamu dapat menggantinya dengan selektor Namespace yang berada di menu navigasi.

Dashboard menampilkan jenis objek Kubernetes dan mengelompokanya dalam beberapa kategori menu.

Admin Overview

Untuk administrasi klaster dan Namespace, Dashboard menampilkan Node, Namespace dan PresistentVolume dan memiliki tampilan yang detail untuk objek-objek tersebut. Daftar Node berisi metrik penggunaan CPU dan memori yang dikumpulkan dari semua Node. Tampilan detail menampilkan metrik-metrik untuk sebuah Node, spesifikasinya, status, sumber daya yang dialokasikan, event-event, dan Pod-Pod yang sedang berjalan di Node tersebut.

Workloads

Menampilkan semua aplikasi yang sedang berjalan di Namespace yang dipilih. Tampilan ini menampilkan aplikasi berdasarkan jenis beban kerja (misalnya, Deployment, Replica Set, Stateful Set, dll.) dan setiap jenis beban kerja memiliki tampilanya sendiri. Daftar ini merangkum informasi yang dapat ditindaklanjuti, seperti berapa banyak Pod yang siap untuk setiap Replica Set atau penggunaan memori pada sebuah Pod.

Tampilan detail dari beban kerja menampilkan status dan informasi spesifik serta hubungan antara objek. Misalnya, Pod-Pod yang diatur oleh ReplicaSet atau, ReplicaSet-ReplicaSet baru, dan HorizontalPodAutoscaler untuk Deployment.

Services

Menampilkan sumber daya Kubernetes yang mengizinkan untuk mengekspos Service-Service ke jaringan luar dan menemukannya (service discovery) di dalam klaster. Untuk itu, tampilan dari Service dan Ingress menunjukan Pod-Pod yang ditarget oleh mereka, endpoint-endpoint internal untuk koneksi klaster, dan endpoint-endpoint eksternal untuk pengguna eksternal.

Storage

Tampilan Storage menampilkan sumber-sumber daya PersistentVolumeClaim yang digunakan oleh aplikasi untuk menyimpan data.

Config Maps dan Secrets

Menampilkan semua sumber daya Kubernetes yang digunakan untuk pengaturan aplikasi yang sedang berjalan di klaster. Pada tampilan ini kamu dapat mengedit dan mengelola objek-objek konfigurasi dan menampilkan kredensial yang tersembunyi secara bawaan.

Logs Viewer

Laman daftar dan detail Pod tertaut dengan laman penampil log (log viewer). Kamu dapat menelusuri log yang berasal dari Container-Container pada sebuah Pod.

Logs viewer

Selanjutnya

Untuk informasi lebih lanjut, lihat Laman proyek Kubernetes Dashboard.

8.2 - Mengakses Klaster

Topik ini membahas tentang berbagai cara untuk berinteraksi dengan klaster.

Mengakses untuk pertama kalinya dengan kubectl

Saat mengakses API Kubernetes untuk pertama kalinya, kami sarankan untuk menggunakan CLI Kubernetes, kubectl.

Untuk mengakses sebuah klaster, kamu perlu mengetahui lokasi klaster dan mempunyai kredensial untuk mengaksesnya. Biasanya, ini secara otomatis diatur saat kamu mengikuti Panduan persiapan, atau orang lain yang mengatur klaster dan memberikan kredensial dan lokasi kepadamu.

Periksa lokasi dan kredensial yang ada pada konfigurasi kubectl-mu melalui perintah ini:

kubectl config view

Beragam contoh menyediakan pengantar penggunaan kubectl, dan dokumentasi lengkap dapat ditemukan di kubectl manual.

Mengakses REST API secara langsung

Kubectl menangani pencarian dan autentikasi ke apiserver. Jika kamu ingin secara langsung mengakses REST API dengan klien HTTP seperti curl atau wget, atau peramban, ada beberapa cara untuk pencarian dan autentikasi:

  • Jalankan kubectl dalam mode proksi.
    • Pendekatan yang disarankan.
    • Menggunakan lokasi apiserver yang tersimpan.
    • Melakukan verifikasi identitas apiserver menggunakan sertifikat elektronik yang ditandatangani sendiri. Tidak memungkinkan adanya MITM.
    • Melakukan autentikasi ke apiserver.
    • Di masa depan, dimungkinkan dapat melakukan load-balancing dan failover yang cerdas dari sisi klien.
  • Penyediaan lokasi dan kredensial langsung ke klien http.
    • Pendekatan alternatif.
    • Bekerja dengan beberapa jenis kode klien dengan menggunakan proksi.
    • Perlu mengimpor sertifikat elektronik root ke peramban kamu untuk melindungi dari MITM.

Menggunakan kubectl proxy

Perintah berikut akan menjalankan kubectl dalam mode di mana ia bertindak sebagai proksi terbalik (reverse proxy). Hal ini menangani pencarian dan autentikasi apiserver. Jalankan seperti ini:

kubectl proxy --port=8080

Lihat kubectl proxy untuk lebih jelasnya.

Kemudian kamu dapat menjelajahi API-nya dengan curl, wget, atau peramban, ganti localhost dengan [::1] untuk IPv6, seperti ini:

curl http://localhost:8080/api/

Hasil keluarannya seperti ini:

{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.1.149:443"
    }
  ]
}

Tanpa menggunakan kubectl proxy

Gunakan kubectl describe secret... untuk mendapatkan token untuk akun servis (service account) default dengan grep/cut:

APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ")
SECRET_NAME=$(kubectl get secrets | grep ^default | cut -f1 -d ' ')
TOKEN=$(kubectl describe secret $SECRET_NAME | grep -E '^token' | cut -f2 -d':' | tr -d " ")

curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure

Hasil keluarannya seperti ini:

{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.1.149:443"
    }
  ]
}

Menggunakan jsonpath:

APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
SECRET_NAME=$(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}')
TOKEN=$(kubectl get secret $SECRET_NAME -o jsonpath='{.data.token}' | base64 --decode)

curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure

Hasil keluarannya seperti ini:

{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.1.149:443"
    }
  ]
}

Contoh di atas menggunakan flag --insecure. Hal ini membuatnya rentan terhadap serangan MITM. Ketika kubectl mengakses klaster, kubectl menggunakan sertifikat elektronik root yang tersimpan dan sertifikat elektronik klien untuk mengakses server. (Sertifikat-sertifikat elektronik tersebut diinstal di direktori ~/.kube). Karena sertifikat elektronik klaster biasanya ditandatangani sendiri, mungkin diperlukan konfigurasi khusus untuk membuat klien HTTP kamu menggunakan sertifikat elektronik root.

Pada beberapa klaster, apiserver tidak memerlukan autentikasi; mungkin apiserver tersebut meladen (serve) di localhost, atau dilindungi oleh sebuah dinding api (firewall). Tidak ada standar untuk ini. Mengonfigurasi Akses ke API menjelaskan bagaimana admin klaster dapat mengonfigurasi hal ini. Pendekatan semacam itu dapat bertentangan dengan dukungan ketersediaan tinggi (high-availability) pada masa depan.

Akses terprogram ke API

Kubernetes secara resmi mendukung pustaka (library) klien Go dan Python.

Klien Go

  • Untuk mendapatkan pustakanya, jalankan perintah berikut: go get k8s.io/client-go@kubernetes-<kubernetes-version-number>, lihat INSTALL.md untuk instruksi instalasi yang lebih detail. Lihat https://github.com/kubernetes/client-go untuk melihat versi yang didukung.
  • Tulis aplikasi dengan menggunakan klien client-go. Perhatikan bahwa client-go mendefinisikan objek APInya sendiri, jadi jika perlu, silakan impor definisi API dari client-go daripada dari repositori utama, misalnya, import "k8s.io/client-go/kubernetes".

Klien Go dapat menggunakan berkas kubeconfig yang sama dengan yang digunakan oleh CLI kubectl untuk mencari dan mengautentikasi ke apiserver. Lihat contoh ini.

Jika aplikasi ini digunakan sebagai Pod di klaster, silakan lihat bagian selanjutnya.

Klien Python

Untuk menggunakan klien Python, jalankan perintah berikut: pip install kubernetes. Lihat halaman Pustaka Klien Python untuk opsi instalasi lainnya.

Klien Python dapat menggunakan berkas kubeconfig yang sama dengan yang digunakan oleh CLI kubectl untuk mencari dan mengautentikasi ke apiserver. Lihat contoh.

Bahasa lainnya

Ada pustaka klien untuk mengakses API dari bahasa lain. Lihat dokumentasi pustaka lain untuk melihat bagaimana mereka melakukan autentikasi.

Mengakses API dari Pod

Saat mengakses API dari Pod, pencarian dan autentikasi ke apiserver agak berbeda.

Cara yang disarankan untuk menemukan apiserver di dalam Pod adalah dengan nama DNS kubernetes.default.svc, yang akan mengubah kedalam bentuk Service IP yang pada gilirannya akan dialihkan ke apiserver.

Cara yang disarankan untuk mengautentikasi ke apiserver adalah dengan kredensial akun servis. Oleh kube-system, Pod dikaitkan dengan sebuah akun servis (service account), dan sebuah kredensial (token) untuk akun servis (service account) tersebut ditempatkan ke pohon sistem berkas (file system tree) dari setiap Container di dalam Pod tersebut, di /var/run/secrets/kubernetes.io/serviceaccount/token.

Jika tersedia, bundel sertifikat elektronik ditempatkan ke pohon sistem berkas dari setiap Container di /var/run/secrets/kubernetes.io/serviceaccount/ca.crt, dan itu akan digunakan untuk memverifikasi sertifikat elektronik yang digunakan apiserver untuk meladen.

Terakhir, Namespace default yang akan digunakan untuk operasi API namespaced ditempatkan di dalam berkas /var/run/secrets/kubernetes.io/serviceaccount/namespace di dalam setiap Container.

Dari dalam Pod, cara yang disarankan untuk menghubungi API adalah:

  • Jalankan kubectl proxy pada Container sidecar di dalam Pod, atau sebagai proses background di dalam Container. Perintah tersebut memproksi API Kubernetes pada antarmuka localhost Pod tersebut, sehingga proses lain dalam Container apa pun milik Pod dapat mengaksesnya.
  • Gunakan pustaka klien Go, dan buatlah sebuah klien menggunakan fungsi rest.InClusterConfig() dan kubernetes.NewForConfig(). Mereka menangani pencarian dan autentikasi ke apiserver. contoh

Pada setiap kasus, kredensial Pod digunakan untuk berkomunikasi secara aman dengan apiserver.

Mengakses servis yang berjalan di klaster

Bagian sebelumnya menjelaskan tentang menghubungi server API Kubernetes. Bagian ini menjelaskan tentang menghubungi servis lain yang berjalan di klaster Kubernetes. Di Kubernetes, semua Node, Pod, dan Service memiliki IP sendiri. Dalam banyak kasus, IP Node, IP Pod, dan beberapa IP Service pada sebuah klaster tidak dapat dirutekan, sehingga mereka tidak terjangkau dari mesin di luar klaster, seperti mesin desktop kamu.

Cara untuk terhubung

Kamu memiliki beberapa opsi untuk menghubungi Node, Pod, dan Service dari luar klaster:

  • Mengakses Service melalui IP publik.
    • Gunakan Service dengan tipe NodePort atau LoadBalancer untuk membuat Service dapat dijangkau di luar klaster. Lihat dokumentasi Service dan perintah kubectl expose.
    • Bergantung pada lingkungan klaster kamu, hal ini mungkin hanya mengekspos Service ke jaringan perusahaan kamu, atau mungkin mengeksposnya ke internet. Pikirkan apakah Service yang diekspos aman atau tidak. Apakah layanan di balik Service tersebut melakukan autentikasinya sendiri?
    • Tempatkan Pod di belakang Service. Untuk mengakses satu Pod tertentu dari sekumpulan replika, misalnya untuk pengawakutuan (debugging), letakkan label unik di Pod dan buat Service baru yang memilih label ini.
    • Pada kebanyakan kasus, pengembang aplikasi tidak perlu langsung mengakses Node melalui IP Node mereka.
  • Akses Service, Node, atau Pod menggunakan Verb Proxy.
    • Apakah autentikasi dan otorisasi apiserver dilakukan sebelum mengakses Service jarak jauh. Gunakan ini jika Service tersebut tidak cukup aman untuk diekspos ke internet, atau untuk mendapatkan akses ke porta (port) pada IP Node, atau untuk pengawakutuan.
    • Proksi dapat menyebabkan masalah untuk beberapa aplikasi web.
    • Hanya bekerja pada HTTP/HTTPS.
    • Dijelaskan di sini.
  • Akses dari Node atau Pod di klaster.
    • Jalankan Pod, kemudian hubungkan ke sebuah shell di dalamnya menggunakan kubectl exec. Hubungi Node, Pod, dan Service lain dari shell itu.
    • Beberapa klaster memungkinkan kamu untuk melakukan SSH ke sebuah Node di dalam klaster. Dari sana, kamu mungkin dapat mengakses Service-Service klaster. Hal ini merupakan metode yang tidak standar, dan akan bekerja pada beberapa klaster tetapi tidak pada yang lain. Peramban dan perkakas lain mungkin diinstal atau tidak. DNS Klaster mungkin tidak berfungsi.

Menemukan Service bawaan (builtin)

Biasanya, ada beberapa Service yang dimulai pada sebuah klaster oleh kube-system. Dapatkan daftarnya dengan perintah kubectl cluster-info:

kubectl cluster-info

Keluarannya mirip seperti ini:

Kubernetes master is running at https://104.197.5.247
elasticsearch-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy
kibana-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kibana-logging/proxy
kube-dns is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kube-dns/proxy
grafana is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
heapster is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy

Ini menunjukkan URL proxy-verb untuk mengakses setiap Service. Misalnya, klaster ini mempunyai pencatatan log pada level klaster (cluster-level logging) yang aktif (menggunakan Elasticsearch), yang dapat dicapai di https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/ jika kredensial yang sesuai diberikan. Pencatatan log dapat pula dicapai dengan sebuah proksi kubectl, misalnya di: http://localhost:8080/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/. (Lihat di atas untuk panduan bagaimana cara meneruskan kredensial atau menggunakan kubectl proxy.)

Membuat URL proksi apiserver secara manual

Seperti disebutkan di atas, kamu menggunakan perintah kubectl cluster-info untuk mendapatkan URL proksi suatu Service. Untuk membuat URL proksi yang memuat endpoint-endpoint Service, sufiks, dan parameter, kamu cukup menambahkan ke URL proksi Service: http://alamat_kubernetes_master/api/v1/namespaces/nama_namespace/services/nama_servis[:nama_porta]/proxy

Jika kamu belum menentukan nama untuk porta kamu, kamu tidak perlu memasukan nama_porta di URL.

Secara bawaan, server API memproksi ke Service kamu menggunakan HTTP. Untuk menggunakan HTTPS, awali nama Service dengan https:: http://alamat_kubernetes_master/api/v1/namespaces/nama_namespace/services/https:nama_servis:[nama_porta]/proxy

Format yang didukung untuk segmen nama URL adalah:

  • <nama_servis> - Memproksi ke porta bawaan atau porta tanpa nama menggunakan HTTP
  • <nama_servis>:<nama_porta> - Memproksi ke porta yang telah ditentukan menggunakan HTTP
  • https:<nama_servis>: - Memproksi ke porta bawaan atau porta tanpa nama menggunakan HTTPS (perhatikan tanda adanya titik dua)
  • https:<nama_servis>:<nama_porta> - proksi ke porta yang telah ditentukan menggunakan https
Contoh
  • Untuk mengakses endpoint Service Elasticsearch _search?q=user:kimchy, kamu dapat menggunakan: http://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_search?q=user:kimchy
  • Untuk mengakses informasi kesehatan klaster Elasticsearch _cluster/health?pretty=true, kamu dapat menggunakan: https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_cluster/health?pretty=true
{
  "cluster_name" : "kubernetes_logging",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 5,
  "active_shards" : 5,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 5
}

Menggunakan peramban web untuk mengakses Service yang berjalan di klaster

Kamu mungkin dapat memasukkan URL proksi apiserver ke bilah alamat peramban. Namun:

  • Peramban web biasanya tidak dapat menerima token, jadi kamu mungkin perlu menggunakan autentikasi dasar/basic auth (kata sandi). Apiserver dapat dikonfigurasi untuk menerima autentikasi dasar, tetapi klaster kamu mungkin belum dikonfigurasi untuk menerima autentikasi dasar.
  • Beberapa aplikasi web mungkin tidak berfungsi, terutama yang memiliki javascript pada sisi klien yang digunakan untuk membuat URL sedemikian sehingga ia tidak mengetahui adanya prefiks jalur (path) proksi (/proxy).

Meminta pengalihan

Kemampuan pengalihan telah usang (deprecated) dan dihapus. Silakan gunakan proksi (lihat di bawah) sebagai gantinya.

Begitu Banyaknya Proksi

Ada beberapa proksi berbeda yang mungkin kamu temui saat menggunakan Kubernetes:

  1. Proksi kubectl:

    • berjalan di desktop pengguna atau di Pod
    • memproksi dari sebuah alamat localhost ke apiserver Kubernetes
    • dari klien ke proksi menggunakan HTTP
    • dari proksi ke apiserver menggunakan HTTPS
    • menemukan apiserver-nya
    • menambahkan header-header autentikasi
  2. Proksi apiserver:

    • merupakan sebuah bastion yang dibangun ke dalam apiserver
    • menghubungkan pengguna di luar klaster ke IP klaster yang mungkin tidak dapat dijangkau
    • berjalan dalam proses apiserver
    • dari klien ke proksi menggunakan HTTPS (atau HTTP jika apiserver dikonfigurasi)
    • dari proksi ke target dapat menggunakan HTTP atau HTTPS seperti yang dipilih oleh proksi menggunakan informasi yang tersedia
    • dapat digunakan untuk menjangkau Node, Pod, atau Service
    • melakukan load balancing saat digunakan untuk menjangkau sebuah Service
  3. kube-proxy:

    • berjalan di setiap Node
    • memproksi UDP dan TCP
    • tidak mengerti HTTP
    • menyediakan load balancing
    • hanya digunakan untuk menjangkau Service
  4. Sebuah Proksi/Load-balancer di depan apiserver:

    • keberadaan dan implementasi bervariasi dari satu klaster ke klaster lainnya (mis. nginx)
    • terletak di antara semua klien dan satu atau lebih apiserver
    • bertindak sebagai load balancer jika terdapat beberapa apiserver.
  5. Cloud Load Balancer pada Service eksternal:

    • disediakan oleh beberapa penyedia layanan cloud (mis. AWS ELB, Google Cloud Load Balancer)
    • dibuat secara otomatis ketika Service Kubernetes memiliki tipe LoadBalancer
    • hanya menggunakan UDP/TCP
    • implementasi bervariasi berdasarkan penyedia layanan cloud.

Pengguna Kubernetes biasanya tidak perlu khawatir tentang apa pun selain dua jenis pertama. Admin klaster biasanya akan memastikan bahwa tipe yang terakhir telah diatur dengan benar.

8.3 - Mengkonfigurasi Akses ke Banyak Klaster

Halaman ini menunjukkan bagaimana mengkonfigurasi akses ke banyak klaster dengan menggunakan berkas (file) konfigurasi. Setelah semua klaster, pengguna, dan konteks didefinisikan di satu atau lebih berkas konfigurasi, kamu akan dengan cepat berpindah antar klaster dengan menggunakan perintah kubectl config use-context.

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 klaster, pengguna, dan konteks

Misalkan kamu memiliki dua klaster, satu untuk pekerjaan pengembangan dan satu untuk pekerjaan eksperimen (scratch). Di klaster pengembangan, pengembang frontend kamu bekerja di sebuah Namespace bernama frontend, dan pengembang penyimpanan kamu bekerja di sebuah Namespace bernama storage. Di klaster scratch kamu, pengembang bekerja di Namespace default, atau mereka membuat Namespace tambahan sesuai keinginan mereka. Akses ke klaster development membutuhkan autentikasi dengan sertifikat. Akses ke klaster scratch membutuhkan autentikasi dengan nama pengguna dan kata sandi.

Buat sebuah direktori bernama config-exercise. Di direktori config-exercise kamu, buat sebuah berkas bernama config-demo dengan konten ini:

apiVersion: v1
kind: Config
preferences: {}

clusters:
- cluster:
  name: development
- cluster:
  name: scratch

users:
- name: developer
- name: experimenter

contexts:
- context:
  name: dev-frontend
- context:
  name: dev-storage
- context:
  name: exp-scratch

Berkas konfigurasi di atas mendeskripsikan semua klaster, pengguna, dan konteks. Berkas config-demo kamu memiliki kerangka kerja untuk mendeskripsikan dua klaster, dua pengguna, dan tiga konteks.

Buka direktori config-exercise kamu. Masukkan perintah-perintah berikut untuk menambahkan detail ke berkas konfigurasi kamu:

kubectl config --kubeconfig=config-demo set-cluster development --server=https://1.2.3.4 --certificate-authority=fake-ca-file
kubectl config --kubeconfig=config-demo set-cluster scratch --server=https://5.6.7.8 --insecure-skip-tls-verify

Tambahkan detail pengguna ke berkas konfigurasi kamu:

kubectl config --kubeconfig=config-demo set-credentials developer --client-certificate=fake-cert-file --client-key=fake-key-seefile
kubectl config --kubeconfig=config-demo set-credentials experimenter --username=exp --password=some-password

Tambahkan detail konteks ke berkas konfigurasi kamu:

kubectl config --kubeconfig=config-demo set-context dev-frontend --cluster=development --namespace=frontend --user=developer
kubectl config --kubeconfig=config-demo set-context dev-storage --cluster=development --namespace=storage --user=developer
kubectl config --kubeconfig=config-demo set-context exp-scratch --cluster=scratch --namespace=default --user=experimenter

Buka berkas config-demo kamu untuk melihat detail-detail yang telah ditambah. Sebagai alternatif dari membuka berkas config-demo, kamu bisa menggunakan perintah config view.

kubectl config --kubeconfig=config-demo view

Keluaran akan menampilkan dua klaster, dua pengguna, dan tiga konteks:

apiVersion: v1
clusters:
- cluster:
    certificate-authority: fake-ca-file
    server: https://1.2.3.4
  name: development
- cluster:
    insecure-skip-tls-verify: true
    server: https://5.6.7.8
  name: scratch
contexts:
- context:
    cluster: development
    namespace: frontend
    user: developer
  name: dev-frontend
- context:
    cluster: development
    namespace: storage
    user: developer
  name: dev-storage
- context:
    cluster: scratch
    namespace: default
    user: experimenter
  name: exp-scratch
current-context: ""
kind: Config
preferences: {}
users:
- name: developer
  user:
    client-certificate: fake-cert-file
    client-key: fake-key-file
- name: experimenter
  user:
    password: some-password
    username: exp

fake-ca-file, fake-cert-file, dan fake-key-file di atas adalah placeholder untuk nama jalur (pathname) dari berkas-berkas sertifikat. Kamu harus menggantinya menjadi nama jalur sebenarnya dari berkas-berkas sertifikat di dalam lingkungan (environment) kamu.

Terkadang kamu mungkin ingin menggunakan data yang disandikan Base64 yang langsung dimasukkan di berkas konfigurasi daripada menggunakan berkas sertifikat yang terpisah. Dalam kasus ini, kamu perlu menambahkan akhiran -data ke kunci. Contoh, certificate-authority-data, client-certificate-data, dan client-key-data.

Setiap konteks memiliki tiga bagian: klaster, pengguna, dan Namespace. Sebagai contoh, konteks dev-frontend menyatakan, "Gunakan kredensial dari pengguna developer untuk mengakses Namespace frontend di klaster development.

Mengatur konteks yang digunakan:

kubectl config --kubeconfig=config-demo use-context dev-frontend

Sekarang kapanpun kamu memasukkan perintah kubectl, aksi tersebut akan diterapkan untuk klaster, dan Namespace yang terdaftar pada konteks dev-frontend. Dan perintah tersebut akan menggunakan kredensial dari pengguna yang terdaftar pada konteks dev-frontend.

Untuk melihat hanya informasi konfigurasi yang berkaitan dengan konteks saat ini, gunakan --minify flag.

kubectl config --kubeconfig=config-demo view --minify

Output menunjukkan informasi konfigurasi yang berkaitan dengan konteks dev-frontend:

apiVersion: v1
clusters:
- cluster:
    certificate-authority: fake-ca-file
    server: https://1.2.3.4
  name: development
contexts:
- context:
    cluster: development
    namespace: frontend
    user: developer
  name: dev-frontend
current-context: dev-frontend
kind: Config
preferences: {}
users:
- name: developer
  user:
    client-certificate: fake-cert-file
    client-key: fake-key-file

Sekarang apabila kamu ingin bekerja sebentar di klaster eksperimen.

Ubah konteks saat ini menjadi exp-scratch:

kubectl config --kubeconfig=config-demo use-context exp-scratch

Sekarang, setiap perintah kubectl yang diberikan akan berlaku untuk Namespace default dari klaster scratch. Dan perintah akan menggunakan kredensial dari pengguna yang terdaftar di konteks exp-scratch.

Untuk melihat konfigurasi yang berkaitan dengan konteks saat ini, exp-scratch.

kubectl config --kubeconfig=config-demo view --minify

Akhirnya, misalkan kamu ingin bekerja sebentar di Namespace storage pada klaster development.

Ubah konteks saat ini menjadi dev-storage:

kubectl config --kubeconfig=config-demo use-context dev-storage

Untuk melihat konfigurasi yang berkaitan dengan konteks baru saat ini, dev-storage.

kubectl config --kubeconfig=config-demo view --minify

Membuat sebuah berkas konfigurasi kedua

Di direktori config-exercise kamu, buat sebuah berkas bernama config-demo-2 dengan konten ini:

apiVersion: v1
kind: Config
preferences: {}

contexts:
- context:
    cluster: development
    namespace: ramp
    user: developer
  name: dev-ramp-up

Berkas konfigurasi di atas mendefinisikan sebuah konteks baru bernama dev-ramp-up.

Mengatur variabel lingkungan KUBECONFIG

Lihat apakah kamu sudah memiliki sebuah variabel lingkungan bernama KUBECONFIG. Jika iya, simpan nilai saat ini dari variabel lingkungan KUBECONFIG kamu, sehingga kamu dapat mengembalikannya nanti. Sebagai contohL

Linux

export KUBECONFIG_SAVED=$KUBECONFIG

Windows PowerShell

$Env:KUBECONFIG_SAVED=$ENV:KUBECONFIG

Variabel lingkungan KUBECONFIG adalah sebuah daftar dari jalur-jalur (beragam path) menuju berkas konfigurasi. Daftar ini dibatasi oleh tanda titik dua untuk Linux dan Mac, dan tanda titik koma untuk Windows. Jika kamu memiliki sebuah variabel lingkungan KUBECONFIG, biasakan diri kamu dengan berkas-berkas konfigurasi yang ada pada daftar.

Tambahkan sementara dua jalur ke variabel lingkungan KUBECONFIG kamu. Sebagai contoh:

Linux

export KUBECONFIG=$KUBECONFIG:config-demo:config-demo-2

Windows PowerShell

$Env:KUBECONFIG=("config-demo;config-demo-2")

Di direktori config-exercise kamu, masukan perintah ini:

kubectl config view

Keluaran menunjukkan informasi gabungan dari semua berkas yang terdaftar dalam variabel lingkungan KUBECONFIG kamu. Secara khusus, perhatikan bahwa informasi gabungan tersebut memiliki konteks dev-ramp-up, konteks dari berkas config-demo-2, dan tiga konteks dari berkas config-demo:

contexts:
- context:
    cluster: development
    namespace: frontend
    user: developer
  name: dev-frontend
- context:
    cluster: development
    namespace: ramp
    user: developer
  name: dev-ramp-up
- context:
    cluster: development
    namespace: storage
    user: developer
  name: dev-storage
- context:
    cluster: scratch
    namespace: default
    user: experimenter
  name: exp-scratch

Untuk informasi lebih tentang bagaimana berkas Kubeconfig tergabung, lihat Mengatur Akses Cluster Menggunakan Berkas Kubeconfig

Jelajahi direktori $HOME/.kube

Jika kamu sudah memiliki sebuah klaster, dan kamu bisa menggunakan kubectl untuk berinteraksi dengan klaster kamu, kemudian kamu mungkin memiliki sebuah berkas bernama config di direktori $HOME/.kube.

Buka $HOME/.kube, dan lihat berkas-berkas apa saja yang ada. Biasanya ada berkas bernama config. Mungkin juga ada berkas-berkas konfigurasi lain di direktori ini. Biasakan diri anda dengan konten-konten yang ada di berkas-berkas tersebut.

Tambahkan $HOME/.kube/config ke variabel lingkungan KUBECONFIG kamu

Jika kamu memiliki sebuah berkas $HOME/.kube/config, dan belum terdaftar dalam variabel lingungan KUBECONFIG kamu, tambahkan berkas tersebut ke variabel lingkungan KUBECONFIG kamu sekarang. Sebagai contoh:

Linux

export KUBECONFIG=$KUBECONFIG:$HOME/.kube/config

Windows Powershell

$Env:KUBECONFIG=($Env:KUBECONFIG;$HOME/.kube/config)

Lihat gabungan informasi konfigurasi dari semua berkas yang sekarang tergabung dalam variabel lingkungan KUBECONFIG kamu. Di direktori config-exercise kamu, masukkan perintah:

kubectl config view

Membersihkan

Kembalikan variabel lingkungan KUBECONFIG kamu ke nilai asilnya. Sebagai contoh:

Linux

export KUBECONFIG=$KUBECONFIG_SAVED

Windows PowerShell

$Env:KUBECONFIG=$ENV:KUBECONFIG_SAVED

Selanjutnya

8.4 - Menggunakan Port Forwarding untuk Mengakses Aplikasi di sebuah Klaster

Halaman ini menunjukkan bagaimana menggunakan kubectl port-forward untuk menghubungkan sebuah server Redis yang sedang berjalan di sebuah klaster Kubernetes. Tipe dari koneksi ini dapat berguna untuk melakukan debugging basis data.

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.

Membuat Deployment dan Service Redis

  1. Buat sebuah Deployment yang menjalankan Redis:

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-deployment.yaml
    

    Keluaran dari sebuah perintah yang sukses akan memverifikasi bahwa Deployment telah terbuat:

    deployment.apps/redis-master created
    

    Lihat status Pod untuk memeriksa apakah sudah siap:

    kubectl get pods
    

    Keluaran menampilkan Pod yang telah terbuat:

    NAME                            READY     STATUS    RESTARTS   AGE
    redis-master-765d459796-258hz   1/1       Running   0          50s
    

    Lihat status Deployment:

    kubectl get deployment
    

    Keluaran menampilkan bahwa Deployment telah terbuat:

    NAME         READY   UP-TO-DATE   AVAILABLE   AGE
    redis-master 1/1     1            1           55s
    

    Deployment secara otomatis mengatur sebuah ReplicaSet. Lihat status ReplicaSet menggunakan:

    kubectl get replicaset
    

    Keluaran menampilkan bahwa ReplicaSet telah terbuat:

    NAME                      DESIRED   CURRENT   READY     AGE
    redis-master-765d459796   1         1         1         1m
    
  2. Buat sebuah Service untuk mengekspos Redis di jaringan:

    kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-service.yaml
    

    Keluaran dari perintah yang sukses akan memverifikasi bahwa Service telah terbuat:

    service/redis-master created
    

    Lihat Service yang telah terbuat menggunakan:

    kubectl get service redis-master
    

    Keluaran menampilkan service yang telah terbuat:

    NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    redis-master   ClusterIP   10.0.0.213   <none>        6379/TCP   27s
    
  3. Periksa apakah server Redis berjalan di Pod, dan mendengarkan porta 6379:

    # Ubah redis-master-765d459796-258hz menjadi nama Pod
    kubectl get pod redis-master-765d459796-258hz --template='{{(index (index .spec.containers 0).ports 0).containerPort}}{{"\n"}}'
    

    Keluaran akan menampilkan porta dari Redis di Pod tersebut:

    6379
    

    (ini adalah porta TCP yang dialokasi untuk Redis di internet)

Meneruskan sebuah porta lokal ke sebuah porta pada Pod

  1. kubectl port-forward memungkinkan penggunaan nama sumber daya, seperti sebuah nama Pod, untuk memilih Pod yang sesuai untuk melakukan penerusan porta.

    # Ubah redis-master-765d459796-258hz menjadi nama Pod
    kubectl port-forward redis-master-765d459796-258hz 7000:6379
    

    yang sama seperti

    kubectl port-forward pods/redis-master-765d459796-258hz 7000:6379
    

    atau

    kubectl port-forward deployment/redis-master 7000:6379
    

    atau

    kubectl port-forward replicaset/redis-master 7000:6379
    

    atau

    kubectl port-forward service/redis-master 7000:6379
    

    Semua perintah di atas berfungsi. Keluarannya mirip dengan ini:

    I0710 14:43:38.274550    3655 portforward.go:225] Forwarding from 127.0.0.1:7000 -> 6379
    I0710 14:43:38.274797    3655 portforward.go:225] Forwarding from [::1]:7000 -> 6379
    
  2. Memulai antarmuka baris perintah (command line) Redis:

    redis-cli -p 7000
    
  3. Pada baris perintah di Redis, masukkan perintah ping:

    ping
    

    Sebuah permintaan ping yang sukses akan mengembalikan:

    PONG
    

Diskusi

Koneksi-koneksi yang dibuat ke porta lokal 7000 diteruskan ke porta 6379 dari Pod yang menjalankan server Redis. Dengan koneksi ini, kamu dapat menggunakan workstation lokal untuk melakukan debug basis data yang berjalan di Pod.

Selanjutnya

Belajar lebih tentang kubectl port-forward.

8.5 - Membuat Load Balancer Eksternal

Laman ini menjelaskan bagaimana membuat Load Balancer Eksternal.

Ketika membuat Service, kamu mempunyai opsi untuk tersambung dengan jaringan cloud load balancer secara otomatis. Hal ini menyediakan akses eksternal alamat IP yang dapat mengirim lalu lintas melalui porta yang tepat pada klaster Node kamu asalkan klaster kamu beroperasi pada lingkungan yang mendukung dan terkonfigurasi dengan paket penyedia cloud load balancer yang benar.

Untuk informasi mengenai penyediaan dan penggunaan sumber daya Ingress yang dapat memberikan servis URL yang dapat dijangkau secara eksternal, penyeimbang beban lalu lintas, terminasi SSL, dll., silahkan cek dokumentasi Ingress

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.

Berkas konfigurasi

Untuk membuat load balancer eksternal, tambahkan baris di bawah ini ke berkas konfigurasi Service kamu:

    type: LoadBalancer

Berkas konfigurasi kamu mungkin terlihat seperti ini:

apiVersion: v1
kind: Service
metadata:
  name: example-service
spec:
  selector:
    app: example
  ports:
    - port: 8765
      targetPort: 9376
  type: LoadBalancer

Menggunakan kubectl

Kamu dapat membuat Service dengan perintah kubectl expose dan flag --type=LoadBalancer:

kubectl expose rc example --port=8765 --target-port=9376 \
        --name=example-service --type=LoadBalancer

Perintah ini membuat Service baru dengan menggunakan pemilih yang sama dengan sumber daya yang dirujuk (dalam hal contoh di atas, ReplicationController bernama example).

Untuk informasi lebih lanjut, termasuk opsi flag, mengacu kepada referensi kubectl expose.

Menemukan alamat IP kamu

Kamu dapat menemukan alamat IP yang telah dibuat untuk Service kamu dengan mendapatkan informasi Service melalui kubectl:

kubectl describe services example-service

yang seharusnya menghasilkan keluaran seperti ini:

    Name:                   example-service
    Namespace:              default
    Labels:                 <none>
    Annotations:            <none>
    Selector:               app=example
    Type:                   LoadBalancer
    IP:                     10.67.252.103
    LoadBalancer Ingress:   192.0.2.89
    Port:                   <unnamed> 80/TCP
    NodePort:               <unnamed> 32445/TCP
    Endpoints:              10.64.0.4:80,10.64.1.5:80,10.64.2.4:80
    Session Affinity:       None
    Events:                 <none>

Alamat IP tercantum di sebelah LoadBalancer Ingress.

minikube service example-service --url

Preservasi IP sumber klien

Implementasi dari fitur ini menyebabkan sumber IP yang terlihat pada Container target bukan sebagai sumber IP asli dari klien. Untuk mengaktifkan preservasi IP klien, bidang berikut dapat dikonfigurasikan di dalam spek Service (mendukung lingkungan GCE/Google Kubernetes Engine):

  • service.spec.externalTrafficPolicy - menunjukkan jika Service menginginkan rute lalu lintas eksternal ke titik akhir node-local atau cluster-wide. Terdapat dua opsi yang tersedia: Cluster (bawaan) dan Local. Cluster mengaburkan sumber IP klien dan mungkin menyebabkan hop kedua ke Node berbeda, namun harus mempunyai penyebaran beban (load-spreading) yang baik secara keseluruhan. Local mempreservasi sumber IP client dan menghindari hop kedua LoadBalancer dan Service dengan tipe NodePort, namun resiko berpotensi penyebaran lalu lintas yang tidak merata.
  • service.spec.healthCheckNodePort - menentukan pemeriksaan kesehatan porta dari sebuah Node (angka porta numerik) untuk Service. Jika healthCheckNodePort tidak ditentukan, pengendali Service mengalokasi porta dari rentang NodePort dari klaster kamu. Kamu dapat mengonfigurasi rentangan tersebut dari pengaturan opsi barisan perintah API server, --service-node-port-range. Hal itu menggunakan nilai healthCheckNodePort pengguna spesifik jika ditentukan oleh klien. Hal itu dapat berefek hanya ketika type diset ke LoadBalancer dan externalTrafficPolicy diset ke Local.

Pengaturan externalTrafficPolicy ke Local pada berkas konfigurasi Service mengaktifkan fitur ini.

apiVersion: v1
kind: Service
metadata:
  name: example-service
spec:
  selector:
    app: example
  ports:
    - port: 8765
      targetPort: 9376
  externalTrafficPolicy: Local
  type: LoadBalancer

Pengumpul Sampah (Garbage Collector) Load Balancer

FEATURE STATE: Kubernetes v1.17 [stable]

Pada kasus biasa, sumber daya load balancer yang berkorelasi pada penyedia cloud perlu dibersihkan segera setelah Service bertipe LoadBalancer dihapus. Namun perlu diketahui bahwa terdapat kasus tepi dimana sumber daya cloud yatim piatu (orphaned) setelah Service yang berkaitan dihapus. Finalizer Protection untuk Service LoadBalancer diperkenalkan untuk mencegah hal ini terjadi. Dengan menggunakan finalizers, sebuah sumber daya Service tidak akan pernah dihapus hingga sumber daya load balancer yang berkorelasi juga dihapus.

Secara khusus, jika Service mempunyai type LoadBalancer, pengendali Service akan melekatkan finalizer bernama service.kubernetes.io/load-balancer-cleanup. Finalizer hanya akan dihapus setelah sumber daya load balancer dibersihkan. Hal ini mencegah sumber daya load balancer yang teruntai bahkan setelah kasus tepi seperti pengendali Service berhenti.

Penyedia Load Balancer Eksternal

Penting untuk dicatat bahwa jalur data untuk fungsionalitas ini disediakan oleh load balancer eksternal ke klaster Kubernetes.

Ketika Service type diset LoadBalancer, Kubernetes menyediakan fungsionalitas yang ekuivalen dengan type sebanding ClusterIP ke berbagai Pod di dalam klaster dan mengekstensinya dengan pemrograman (eksternal dari Kubernetes) load balancer dengan entri pada Pod Kubernetes. Pengendali Service Kubernetes mengotomasi pembuatan load balancer eksternal, cek kesehatan (jika dibutuhkan), dinding api (firewall) (jika dibutuhkan), dan mengambil IP eksternal yang dialokasikan oleh penyedia cloud dan mengisinya pada objek Service.

Peringatan dan and Limitasi ketika preservasi sumber IP

Load balancers GCE/AWS tidak menyediakan bobot pada kolam targetnya (target pools). Hal ini bukan merupakan isu dengan aturan kube-proxy Load balancer lama yang akan menyeimbangkan semua titik akhir dengan benar.

Dengan fungsionalitas yang baru, lalu lintas eksternal tidak menyeimbangkan beban secara merata pada seluruh Pod, namun sebaliknya menyeimbangkan secara merata pada level Node (karena GCE/AWS dan implementasi load balancer eksternal lainnya tidak mempunyai kemampuan untuk menentukan bobot setiap Node, mereka menyeimbangkan secara merata pada semua Node target, mengabaikan jumlah Pod pada tiap Node).

Namun demikian, kita dapat menyatakan bahwa NumServicePods << NumNodes atau NumServicePods >> NumNodes, distribusi yang cukup mendekati sama akan terlihat, meski tanpa bobot.

Sekali load balancer eksternal menyediakan bobot, fungsionalitas ini dapat ditambahkan pada jalur pemrograman load balancer. Pekerjaan Masa Depan: Tidak adanya dukungan untuk bobot yang disediakan untuk rilis 1.4, namun dapat ditambahkan di masa mendatang

Pod internal ke lalu lintas Pod harus berperilaku sama seperti Service ClusterIP, dengan probabilitas yang sama pada seluruh Pod.

8.6 - Membuat Daftar Semua Image Container yang Berjalan dalam Klaster

Laman ini menunjukkan cara menggunakan kubectl untuk membuat daftar semua image Container untuk Pod yang berjalan dalam sebuah klaster.

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.

Dalam latihan ini kamu akan menggunakan kubectl untuk mengambil semua Pod yang berjalan dalam sebuah klaster, dan mengubah format keluarannya untuk melihat daftar Container untuk masing-masing Pod.

Membuat daftar semua image Container pada semua Namespace

  • Silakan ambil semua Pod dalam Namespace dengan menggunakan perintah kubectl get pods --all-namespaces
  • Silakan format keluarannya agar hanya menyertakan daftar nama image dari Container dengan menggunakan perintah -o jsonpath={.items[*].spec.containers[*].image}. Perintah ini akan mem-parsing field image dari keluaran json yang dihasilkan.
    • Silakan lihat referensi jsonpath untuk informasi lebih lanjut tentang cara menggunakan jsonpath.
  • Silakan format keluaran dengan menggunakan peralatan standar: tr, sort, uniq
    • Gunakan tr untuk mengganti spasi dengan garis baru
    • Gunakan sort untuk menyortir hasil
    • Gunakan uniq untuk mengumpulkan jumlah image
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" |\
tr -s '[[:space:]]' '\n' |\
sort |\
uniq -c

Perintah di atas secara berulang akan mengembalikan semua field bernama image dari semua poin yang dikembalikan.

Sebagai pilihan, dimungkinkan juga untuk menggunakan jalur (path) absolut ke field image di dalam Pod. Hal ini memastikan field yang diambil benar bahkan ketika nama field tersebut diulangi, misalnya banyak field disebut dengan name dalam sebuah poin yang diberikan:

kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}"

Jsonpath dapat diartikan sebagai berikut:

  • .items[*]: untuk setiap nilai yang dihasilkan
  • .spec: untuk mendapatkan spesifikasi
  • .containers[*]: untuk setiap Container
  • .image: untuk mendapatkan image

Membuat daftar image Container berdasarkan Pod

Format dapat dikontrol lebih lanjut dengan menggunakan operasi range untuk melakukan iterasi untuk setiap elemen secara individual.

kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |\
sort

Membuat daftar image yang difilter berdasarkan label dari Pod

Untuk menargetkan hanya Pod yang cocok dengan label tertentu saja, gunakan tanda -l. Filter dibawah ini akan menghasilkan Pod dengan label yang cocok dengan app=nginx.

kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" -l app=nginx

Membuat daftar image Container yang difilter berdasarkan Namespace Pod

Untuk hanya menargetkan Pod pada Namespace tertentu, gunakankan tanda Namespace. Filter dibawah ini hanya menyaring Pod pada Namespace kube-system.

kubectl get pods --namespace kube-system -o jsonpath="{.items[*].spec.containers[*].image}"

Membuat daftar image Container dengan menggunakan go-template sebagai alternatif dari jsonpath

Sebagai alternatif untuk jsonpath, kubectl mendukung penggunaan go-template untuk memformat keluaran seperti berikut:

kubectl get pods --all-namespaces -o go-template --template="{{range .items}}{{range .spec.containers}}{{.image}} {{end}}{{end}}"

Selanjutnya

Referensi

9 - Pemantauan, Pencatatan, and Debugging

Mengatur pemantauan dan pencatatan untuk memecahkan masalah klaster, atau men-debug aplikasi yang terkontainerisasi.

9.1 - Introspeksi dan _Debugging_ Aplikasi

Setelah aplikasi kamu berjalan, kamu pasti perlu untuk men-debug masalah yang ada di dalamnya. Sebelumnya telah dijelaskan bagaimana kamu dapat menggunakan kubectl get pods untuk mengambil informasi status sederhana tentang Pod kamu. Namun ada sejumlah cara untuk mendapatkan lebih banyak informasi tentang aplikasi kamu.

Menggunakan kubectl describe pod untuk mengambil detil informasi Pod

Dalam contoh ini, kamu menggunakan Deployment untuk membuat dua buah Pod, yang hampir sama dengan contoh sebelumnya.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80

Buat Deployment dengan menjalankan perintah ini:

kubectl apply -f https://k8s.io/examples/application/nginx-with-request.yaml
deployment.apps/nginx-deployment created

Cek status dari Pod dengan menggunakan perintah:

kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-1006230814-6winp   1/1       Running   0          11s
nginx-deployment-1006230814-fmgu3   1/1       Running   0          11s

Kamu dapat memperoleh lebih banyak informasi tentang masing-masing Pod ini dengan menggunakan perintah kubectl describe pod. Sebagai contoh:

kubectl describe pod nginx-deployment-1006230814-6winp
Name:		nginx-deployment-1006230814-6winp
Namespace:	default
Node:		kubernetes-node-wul5/10.240.0.9
Start Time:	Thu, 24 Mar 2016 01:39:49 +0000
Labels:		app=nginx,pod-template-hash=1006230814
Annotations:    kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1956810328","uid":"14e607e7-8ba1-11e7-b5cb-fa16" ...
Status:		Running
IP:		10.244.0.6
Controllers:	ReplicaSet/nginx-deployment-1006230814
Containers:
  nginx:
    Container ID:	docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
    Image:		nginx
    Image ID:		docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
    Port:		80/TCP
    QoS Tier:
      cpu:	Guaranteed
      memory:	Guaranteed
    Limits:
      cpu:	500m
      memory:	128Mi
    Requests:
      memory:		128Mi
      cpu:		500m
    State:		Running
      Started:		Thu, 24 Mar 2016 01:39:51 +0000
    Ready:		True
    Restart Count:	0
    Environment:        <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-5kdvl (ro)
Conditions:
  Type          Status
  Initialized   True
  Ready         True
  PodScheduled  True
Volumes:
  default-token-4bcbi:
    Type:	Secret (a volume populated by a Secret)
    SecretName:	default-token-4bcbi
    Optional:   false
QoS Class:      Guaranteed
Node-Selectors: <none>
Tolerations:    <none>
Events:
  FirstSeen	LastSeen	Count	From					SubobjectPath		Type		Reason		Message
  ---------	--------	-----	----					-------------		--------	------		-------
  54s		54s		1	{default-scheduler }						Normal		Scheduled	Successfully assigned nginx-deployment-1006230814-6winp to kubernetes-node-wul5
  54s		54s		1	{kubelet kubernetes-node-wul5}	spec.containers{nginx}	Normal		Pulling		pulling image "nginx"
  53s		53s		1	{kubelet kubernetes-node-wul5}	spec.containers{nginx}	Normal		Pulled		Successfully pulled image "nginx"
  53s		53s		1	{kubelet kubernetes-node-wul5}	spec.containers{nginx}	Normal		Created		Created container with docker id 90315cc9f513
  53s		53s		1	{kubelet kubernetes-node-wul5}	spec.containers{nginx}	Normal		Started		Started container with docker id 90315cc9f513

Di sini kamu dapat melihat informasi konfigurasi tentang Container dan Pod (label, kebutuhan resource, dll.), serta informasi status tentang Container dan Pod (status, kesiapan, berapa kali restart, event, dll.) .

Keadaan (state) Container merupakan salah satu dari keadaan Waiting, Running, atau Terminated. Tergantung dari keadaannya, informasi tambahan akan diberikan - di sini kamu dapat melihat bahwa untuk Container dalam keadaan running, sistem memberi tahu kamu kapan Container tersebut mulai dijalankan.

Ready memberi tahu kepada kamu apakah Container berhasil melewati pemeriksaan kesiapan terakhir. (Dalam kasus ini, Container tidak memiliki pemeriksaan kesiapan yang dikonfigurasi; Container dianggap selalu siap jika tidak ada pemeriksaan kesiapan yang dikonfigurasi.)

Jumlah restart memberi tahu kamu berapa kali Container telah dimulai ulang; informasi ini dapat berguna untuk mendeteksi kemacetan tertutup (crash loop) dalam Container yang dikonfigurasi dengan nilai restart policy 'always.'.

Saat ini, satu-satunya kondisi yang terkait dengan Pod adalah kondisi Binary Ready, yang menunjukkan bahwa Pod tersebut dapat melayani permintaan dan harus ditambahkan ke kumpulan penyeimbang beban (load balancing) dari semua Service yang sesuai.

Terakhir, kamu melihat catatan (log) peristiwa terbaru yang terkait dengan Pod kamu. Sistem mengompresi beberapa peristiwa yang identik dengan menunjukkan kapan pertama dan terakhir kali peristiwa itu dilihat dan berapa kali peristiwa itu dilihat. "From" menunjukkan komponen yang mencatat peristiwa, "SubobjectPath" memberi tahu kamu objek mana (mis. Container dalam pod) yang dimaksud, dan "Reason" dan "Message" memberi tahu kamu apa yang sudah terjadi.

Contoh: Men-debug Pod yang Pending

Skenario umum yang bisa kamu deteksi menggunakan peristiwa (event) adalah saat kamu telah membuat Pod yang tidak muat di Node mana pun. Misalnya, karena Pod mungkin meminta lebih banyak sumber daya yang tersedia dalam Node mana pun, atau mungkin Pod menentukan label selector yang tidak sesuai dengan Node mana pun. Katakanlah kamu sebelumnya membuat Deployment dengan 5 replika (bukan 2) dan meminta 600 millicore, bukan 500, pada klaster dengan empat Node di mana setiap mesin (virtual) memiliki 1 CPU. Sehingga salah satu Pod tidak akan bisa dijadwalkan. (Perhatikan bahwa Pod addon seperti fluentd, skydns, dll., yang berjalan di setiap Node pada klaster, tidak bisa dijadwalkan jika kamu meminta sebanyak 1000 millicore.)

kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
nginx-deployment-1006230814-6winp   1/1       Running   0          7m
nginx-deployment-1006230814-fmgu3   1/1       Running   0          7m
nginx-deployment-1370807587-6ekbw   1/1       Running   0          1m
nginx-deployment-1370807587-fg172   0/1       Pending   0          1m
nginx-deployment-1370807587-fz9sd   0/1       Pending   0          1m

Untuk mencari sebab kenapa Pod nginx-deployment-1370807587-fz9sd tidak berjalan, kamu dapat menggunakan kubectl describe pod pada Pod yang pending dan melihat setiap peristiwa yang terjadi di dalamnya:

kubectl describe pod nginx-deployment-1370807587-fz9sd
  Name:		nginx-deployment-1370807587-fz9sd
  Namespace:	default
  Node:		/
  Labels:		app=nginx,pod-template-hash=1370807587
  Status:		Pending
  IP:
  Controllers:	ReplicaSet/nginx-deployment-1370807587
  Containers:
    nginx:
      Image:	nginx
      Port:	80/TCP
      QoS Tier:
        memory:	Guaranteed
        cpu:	Guaranteed
      Limits:
        cpu:	1
        memory:	128Mi
      Requests:
        cpu:	1
        memory:	128Mi
      Environment Variables:
  Volumes:
    default-token-4bcbi:
      Type:	Secret (a volume populated by a Secret)
      SecretName:	default-token-4bcbi
  Events:
    FirstSeen	LastSeen	Count	From			        SubobjectPath	Type		Reason			    Message
    ---------	--------	-----	----			        -------------	--------	------			    -------
    1m		    48s		    7	    {default-scheduler }			        Warning		FailedScheduling	pod (nginx-deployment-1370807587-fz9sd) failed to fit in any node
  fit failure on node (kubernetes-node-6ta5): Node didn't have enough resource: CPU, requested: 1000, used: 1420, capacity: 2000
  fit failure on node (kubernetes-node-wul5): Node didn't have enough resource: CPU, requested: 1000, used: 1100, capacity: 2000

Di sini kamu dapat melihat peristiwa yang dibuat oleh penjadwal yang mengatakan bahwa Pod gagal dijadwalkan karena alasan FailedScheduling (dan mungkin karena sebab yang lainnya). Pesan tersebut memberi tahu kamu bahwa tidak ada cukup sumber daya untuk Pod pada salah satu Node.

Untuk memperbaiki situasi ini, kamu dapat menggunakan kubectl scale untuk memperbarui Deployment kamu untuk menentukan empat replika atau yang lebih kecil. (Atau kamu bisa membiarkan satu Pod tertunda, dimana hal ini tidak berbahaya.)

Peristiwa seperti yang kamu lihat di bagian akhir keluaran dari perintah kubectl description pod akan tetap ada dalam etcd dan memberikan informasi tingkat tinggi tentang apa yang terjadi pada klaster. Untuk melihat daftar semua peristiwa kamu dapat menggunakan perintah

kubectl get events

tetapi kamu harus ingat bahwa peristiwa bersifat Namespace. Artinya, jika kamu tertarik dengan peristiwa untuk beberapa objek dalam Namespace (misalnya, apa yang terjadi dengan Pod pada Namespace my-namespace), kamu perlu secara eksplisit menyebutkan Namespace tersebut pada perintah:

kubectl get events --namespace=my-namespace

Untuk melihat peristiwa dari semua Namespace, kamu dapat menggunakan argumen --all-namespaces.

Sebagai tambahan dari perintah kubectl describe pod, cara lain untuk mendapatkan informasi tambahan tentang sebuah Pod (selain yang disediakan oleh kubectl get pod) adalah dengan meneruskan flag format keluaran -o yaml ke perintah kubectl get pod. Ini akan memberikan kamu lebih banyak informasi dalam format YAML daripada kubectl describe pod--semua informasi dasar yang dimiliki sistem tentang Pod. Di sini kamu akan melihat hal-hal seperti anotasi (yang merupakan metadata nilai kunci tanpa batasan label, yang digunakan secara internal oleh komponen sistem Kubernetes), kebijakan mulai ulang, porta, dan volume.

kubectl get pod nginx-deployment-1006230814-6winp -o yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubernetes.io/created-by: |
      {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1006230814","uid":"4c84c175-f161-11e5-9a78-42010af00005","apiVersion":"extensions","resourceVersion":"133434"}}      
  creationTimestamp: 2016-03-24T01:39:50Z
  generateName: nginx-deployment-1006230814-
  labels:
    app: nginx
    pod-template-hash: "1006230814"
  name: nginx-deployment-1006230814-6winp
  namespace: default
  resourceVersion: "133447"
  uid: 4c879808-f161-11e5-9a78-42010af00005
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: nginx
    ports:
    - containerPort: 80
      protocol: TCP
    resources:
      limits:
        cpu: 500m
        memory: 128Mi
      requests:
        cpu: 500m
        memory: 128Mi
    terminationMessagePath: /dev/termination-log
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-4bcbi
      readOnly: true
  dnsPolicy: ClusterFirst
  nodeName: kubernetes-node-wul5
  restartPolicy: Always
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  volumes:
  - name: default-token-4bcbi
    secret:
      secretName: default-token-4bcbi
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: 2016-03-24T01:39:51Z
    status: "True"
    type: Ready
  containerStatuses:
  - containerID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
    image: nginx
    imageID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
    lastState: {}
    name: nginx
    ready: true
    restartCount: 0
    state:
      running:
        startedAt: 2016-03-24T01:39:51Z
  hostIP: 10.240.0.9
  phase: Running
  podIP: 10.244.0.6
  startTime: 2016-03-24T01:39:49Z

Contoh: Men-debug Node yang mati/tidak terjangkau (down/unreachable)

Terkadang saat men-debug melihat status sebuah Node akan sangat berguna - misalnya, karena kamu telah melihat perilaku aneh dari sebuah Pod yang sedang berjalan pada Node tersebut, atau untuk mencari tahu mengapa sebuah Pod tidak dapat dijadwalkan ke dalam Node tersebut. Seperti pada Pod, kamu dapat menggunakan perintah kubectl description node dan kubectl get node -o yaml untuk mengambil informasi mendetil tentang Node. Misalnya, disini kamu akan melihat jika sebuah Node sedang mati (terputus dari jaringan, atau kubelet mati dan tidak mau restart, dll.). Perhatikan peristiwa yang menunjukkan Node tersebut NotReady, dan juga perhatikan bahwa Pod tidak lagi berjalan (mereka akan dikeluarkan setelah lima menit berstatus NotReady).

kubectl get nodes
NAME                     STATUS       ROLES     AGE     VERSION
kubernetes-node-861h     NotReady     <none>    1h      v1.13.0
kubernetes-node-bols     Ready        <none>    1h      v1.13.0
kubernetes-node-st6x     Ready        <none>    1h      v1.13.0
kubernetes-node-unaj     Ready        <none>    1h      v1.13.0
kubectl describe node kubernetes-node-861h
Name:			kubernetes-node-861h
Role
Labels:		 kubernetes.io/arch=amd64
           kubernetes.io/os=linux
           kubernetes.io/hostname=kubernetes-node-861h
Annotations:        node.alpha.kubernetes.io/ttl=0
                    volumes.kubernetes.io/controller-managed-attach-detach=true
Taints:             <none>
CreationTimestamp:	Mon, 04 Sep 2017 17:13:23 +0800
Phase:
Conditions:
  Type		Status		LastHeartbeatTime			LastTransitionTime			Reason					Message
  ----    ------    -----------------     ------------------      ------          -------
  OutOfDisk             Unknown         Fri, 08 Sep 2017 16:04:28 +0800         Fri, 08 Sep 2017 16:20:58 +0800         NodeStatusUnknown       Kubelet stopped posting node status.
  MemoryPressure        Unknown         Fri, 08 Sep 2017 16:04:28 +0800         Fri, 08 Sep 2017 16:20:58 +0800         NodeStatusUnknown       Kubelet stopped posting node status.
  DiskPressure          Unknown         Fri, 08 Sep 2017 16:04:28 +0800         Fri, 08 Sep 2017 16:20:58 +0800         NodeStatusUnknown       Kubelet stopped posting node status.
  Ready                 Unknown         Fri, 08 Sep 2017 16:04:28 +0800         Fri, 08 Sep 2017 16:20:58 +0800         NodeStatusUnknown       Kubelet stopped posting node status.
Addresses:	10.240.115.55,104.197.0.26
Capacity:
 cpu:           2
 hugePages:     0
 memory:        4046788Ki
 pods:          110
Allocatable:
 cpu:           1500m
 hugePages:     0
 memory:        1479263Ki
 pods:          110
System Info:
 Machine ID:                    8e025a21a4254e11b028584d9d8b12c4
 System UUID:                   349075D1-D169-4F25-9F2A-E886850C47E3
 Boot ID:                       5cd18b37-c5bd-4658-94e0-e436d3f110e0
 Kernel Version:                4.4.0-31-generic
 OS Image:                      Debian GNU/Linux 8 (jessie)
 Operating System:              linux
 Architecture:                  amd64
 Container Runtime Version:     docker://1.12.5
 Kubelet Version:               v1.6.9+a3d1dfa6f4335
 Kube-Proxy Version:            v1.6.9+a3d1dfa6f4335
ExternalID:                     15233045891481496305
Non-terminated Pods:            (9 in total)
  Namespace                     Name                                            CPU Requests    CPU Limits      Memory Requests Memory Limits
  ---------                     ----                                            ------------    ----------      --------------- -------------
......
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  CPU Requests  CPU Limits      Memory Requests         Memory Limits
  ------------  ----------      ---------------         -------------
  900m (60%)    2200m (146%)    1009286400 (66%)        5681286400 (375%)
Events:         <none>
kubectl get node kubernetes-node-861h -o yaml
apiVersion: v1
kind: Node
metadata:
  creationTimestamp: 2015-07-10T21:32:29Z
  labels:
    kubernetes.io/hostname: kubernetes-node-861h
  name: kubernetes-node-861h
  resourceVersion: "757"
  uid: 2a69374e-274b-11e5-a234-42010af0d969
spec:
  externalID: "15233045891481496305"
  podCIDR: 10.244.0.0/24
  providerID: gce://striped-torus-760/us-central1-b/kubernetes-node-861h
status:
  addresses:
  - address: 10.240.115.55
    type: InternalIP
  - address: 104.197.0.26
    type: ExternalIP
  capacity:
    cpu: "1"
    memory: 3800808Ki
    pods: "100"
  conditions:
  - lastHeartbeatTime: 2015-07-10T21:34:32Z
    lastTransitionTime: 2015-07-10T21:35:15Z
    reason: Kubelet stopped posting node status.
    status: Unknown
    type: Ready
  nodeInfo:
    bootID: 4e316776-b40d-4f78-a4ea-ab0d73390897
    containerRuntimeVersion: docker://Unknown
    kernelVersion: 3.16.0-0.bpo.4-amd64
    kubeProxyVersion: v0.21.1-185-gffc5a86098dc01
    kubeletVersion: v0.21.1-185-gffc5a86098dc01
    machineID: ""
    osImage: Debian GNU/Linux 7 (wheezy)
    systemUUID: ABE5F6B4-D44B-108B-C46A-24CCE16C8B6E

Selanjutnya

Pelajari tentang alat debugging tambahan, termasuk:

9.2 - Mendapatkan Shell Untuk Masuk ke Container yang Sedang Berjalan

Laman ini menunjukkan bagaimana cara menggunakan kubectl exec untuk mendapatkan shell untuk masuk ke dalam Container yang sedang 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.

Mendapatkan sebuah shell untuk masuk ke sebuah Container

Dalam latihan ini, kamu perlu membuat Pod yang hanya memiliki satu Container saja. Container tersebut menjalankan image nginx. Berikut ini adalah berkas konfigurasi untuk Pod tersebut:

apiVersion: v1
kind: Pod
metadata:
  name: shell-demo
spec:
  volumes:
  - name: shared-data
    emptyDir: {}
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html
  hostNetwork: true
  dnsPolicy: Default

Buatlah Pod tersebut:

kubectl apply -f https://k8s.io/examples/application/shell-demo.yaml

Pastikan bahwa Container dalam Pod berjalan:

kubectl get pod shell-demo

Dapatkan shell untuk masuk ke dalam Container:

kubectl exec -it shell-demo -- /bin/bash

Di dalam shell kamu, perlihatkan isi dari direktori root:

root@shell-demo:/# ls /

Di dalam shell kamu, cobalah perintah-perintah yang lainnya. Berikut beberapa contohnya:

root@shell-demo:/# ls /
root@shell-demo:/# cat /proc/mounts
root@shell-demo:/# cat /proc/1/maps
root@shell-demo:/# apt-get update
root@shell-demo:/# apt-get install -y tcpdump
root@shell-demo:/# tcpdump
root@shell-demo:/# apt-get install -y lsof
root@shell-demo:/# lsof
root@shell-demo:/# apt-get install -y procps
root@shell-demo:/# ps aux
root@shell-demo:/# ps aux | grep nginx

Lihat kembali berkas konfigurasi untuk Pod kamu. Pod memiliki volume emptyDir, dan Container melakukan pemasangan (mounting) untuk volume tersebut pada /usr/share/nginx/html.

Pada shell kamu, buatlah berkas index.html dalam direktori /usr/share/nginx/html:

root@shell-demo:/# echo Hello shell demo > /usr/share/nginx/html/index.html

Pada shell kamu, kirimkan sebuah permintaan (request) GET ke server nginx.

root@shell-demo:/# apt-get update
root@shell-demo:/# apt-get install curl
root@shell-demo:/# curl localhost

Keluarannya akan menunjukkan teks yang kamu tulis pada berkas index.html.

Hello shell demo

Setelah kamu selesai dengan shell kamu, ketiklah exit.

Menjalankan perintah individu di dalam sebuah Container

Pada jendela (window) perintah biasa, bukan pada shell kamu di dalam Container, lihatlah daftar variabel lingkungan (environment variable) pada Container yang sedang berjalan:

kubectl exec shell-demo -- env

Cobalah dengan menjalankan perintah lainnya. Berikut beberapa contohnya:

kubectl exec shell-demo ps aux
kubectl exec shell-demo ls /
kubectl exec shell-demo cat /proc/1/mounts

Membuka sebuah shell ketika sebuah Pod memiliki lebih dari satu Container

Jika sebuah Pod memiliki lebih dari satu Container, gunakanlah --container atau -c untuk menentukan Container yang dimaksud pada perintah kubectl exec. Sebagai contoh, misalkan kamu memiliki Pod yang bernama my-pod, dan Pod tersebut memiliki dua Container yang bernama main-app dan helper-app. Perintah berikut ini akan membuka sebuah shell ke Container dengan nama main-app.

kubectl exec -it my-pod --container main-app -- /bin/bash

Selanjutnya

9.3 - Perangkat untuk Memantau Sumber Daya

Untuk melukan penyekalaan aplikasi dan memberikan Service yang handal, kamu perlu memahami bagaimana aplikasi berperilaku ketika aplikasi tersebut digelar (deploy). Kamu bisa memeriksa kinerja aplikasi dalam klaster Kubernetes dengan memeriksa Container, Pod, Service, dan karakteristik klaster secara keseluruhan. Kubernetes memberikan detail informasi tentang penggunaan sumber daya dari aplikasi pada setiap level ini. Informasi ini memungkinkan kamu untuk mengevaluasi kinerja aplikasi kamu dan mengevaluasi di mana kemacetan dapat dihilangkan untuk meningkatkan kinerja secara keseluruhan.

Di Kubernetes, pemantauan aplikasi tidak bergantung pada satu solusi pemantauan saja. Pada klaster baru, kamu bisa menggunakan pipeline metrik sumber daya atau pipeline metrik penuh untuk mengumpulkan statistik pemantauan.

Pipeline Metrik Sumber Daya

Pipeline metrik sumber daya menyediakan sekumpulan metrik terbatas yang terkait dengan komponen-komponen klaster seperti controller HorizontalPodAutoscaler, begitu juga dengan utilitas kubectl top. Metrik ini dikumpulkan oleh memori yang ringan, jangka pendek, dalam metrics-server dan diekspos ke API metrics.k8s.io.

Metrics-server menemukan semua Node dalam klaster dan bertanya ke setiap kubelet dari Node tentang penggunaan CPU dan memori. Kubelet bertindak sebagai jembatan antara control plane Kubernetes dan Node, mengelola Pod dan Container yang berjalan pada sebuah mesin. Kubelet menerjemahkan setiap Pod ke Container yang menyusunnya dan mengambil masing-masing statistik penggunaan untuk setiap Container dari runtime Container melalui antarmuka runtime Container. Kubelet mengambil informasi ini dari cAdvisor yang terintegrasi untuk pengintegrasian Docker yang lama. Hal ini yang kemudian memperlihatkan statistik penggunaan sumber daya dari kumpulan Pod melalui API sumber daya metrics-server. API ini disediakan pada /metrics/resource/v1beta1 pada kubelet yang terautentikasi dan porta read-only.

Pipeline Metrik Penuh

Pipeline metrik penuh memberi kamu akses ke metrik yang lebih banyak. Kubernetes bisa menanggapi metrik ini secara otomatis dengan mengubah skala atau mengadaptasi klaster berdasarkan kondisi saat ini, dengan menggunakan mekanisme seperti HorizontalPodAutoscaler. Pipeline pemantauan mengambil metrik dari kubelet dan kemudian memgekspos ke Kubernetes melalui adaptor dengan mengimplementasikan salah satu dari API custom.metrics.k8s.io atau API external.metrics.k8s.io.

Prometheus, sebuah proyek CNCF, yang dapat secara alami memonitor Kubernetes, Node, dan Prometheus itu sendiri. Proyek pipeline metrik penuh yang bukan merupakan bagian dari CNCF berada di luar ruang lingkup dari dokumentasi Kubernetes.

10 - TLS

10.1 - Kelola Sertifikat TLS Pada Klaster

Kubernetes menyediakan API certificates.k8s.io yang memungkinkan kamu membuat sertifikat TLS yang ditandatangani oleh Otoritas Sertifikat (CA) yang kamu kendalikan. CA dan sertifikat ini bisa digunakan oleh workload untuk membangun kepercayaan.

API certificates.k8s.io menggunakan protokol yang mirip dengan konsep ACME.

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.

Mempercayai TLS dalam Klaster

Mempercayai CA khusus dari aplikasi yang berjalan sebagai Pod biasanya memerlukan beberapa tambahan konfigurasi aplikasi. Kamu harus menambahkan bundel sertifikat CA ke daftar sertifikat CA yang dipercaya klien atau server TLS. Misalnya, kamu akan melakukan ini dengan konfigurasi TLS golang dengan mengurai rantai sertifikat dan menambahkan sertifikat yang diurai ke RootCAs di struct tls.Config.

Kamu bisa mendistribusikan sertifikat CA sebagai sebuah ConfigMap yang bisa diakses oleh Pod kamu.

Meminta Sertifikat

Bagian berikut mendemonstrasikan cara membuat sertifikat TLS untuk sebuah Service kubernetes yang diakses melalui DNS.

Unduh dan Pasang CFSSL

Contoh ini menggunakan cfssl yang dapat diunduh pada https://github.com/cloudflare/cfssl/releases.

Membuat CertificateSigningRequest

Buat kunci pribadi dan CertificateSigningRequest (CSR) dengan menggunakan perintah berikut:

cat <<EOF | cfssl genkey - | cfssljson -bare server
{
  "hosts": [
    "my-svc.my-namespace.svc.cluster.local",
    "my-pod.my-namespace.pod.cluster.local",
    "192.0.2.24",
    "10.0.34.2"
  ],
  "CN": "my-pod.my-namespace.pod.cluster.local",
  "key": {
    "algo": "ecdsa",
    "size": 256
  }
}
EOF

192.0.2.24 adalah klaster IP Service, my-svc.my-namespace.svc.cluster.local adalah nama DNS Service, 10.0.34.2 adalah IP Pod dan my-pod.my-namespace.pod.cluster.local adalah nama DNS Pod. Kamu akan melihat keluaran berikut:

2017/03/21 06:48:17 [INFO] generate received request
2017/03/21 06:48:17 [INFO] received CSR
2017/03/21 06:48:17 [INFO] generating key: ecdsa-256
2017/03/21 06:48:17 [INFO] encoded CSR

Perintah ini menghasilkan dua berkas; Ini menghasilkan server.csr yang berisi permintaan sertifikasi PEM tersandi pkcs#10, dan server-key.pem yang berisi PEM kunci yang tersandi untuk sertifikat yang masih harus dibuat.

Membuat objek CertificateSigningRequest untuk dikirim ke API Kubernetes

Buat sebuah yaml CSR dan kirim ke API Server dengan menggunakan perintah berikut:

cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
  name: my-svc.my-namespace
spec:
  request: $(cat server.csr | base64 | tr -d '\n')
  usages:
  - digital signature
  - key encipherment
  - server auth
EOF

Perhatikan bahwa berkas server.csr yang dibuat pada langkah 1 merupakan base64 tersandi dan disimpan di field .spec.request. Kami juga meminta sertifikat dengan penggunaan kunci "digital signature", "key enchiperment", dan "server auth". Kami mendukung semua penggunaan kunci dan penggunaan kunci yang diperpanjang yang terdaftar di sini sehingga kamu dapat meminta sertifikat klien dan sertifikat lain menggunakan API yang sama.

CSR semestinya bisa dilihat dari API pada status Pending. Kamu bisa melihatnya dengan menjalankan:

kubectl describe csr my-svc.my-namespace
Name:                   my-svc.my-namespace
Labels:                 <none>
Annotations:            <none>
CreationTimestamp:      Tue, 21 Mar 2017 07:03:51 -0700
Requesting User:        yourname@example.com
Status:                 Pending
Subject:
        Common Name:    my-svc.my-namespace.svc.cluster.local
        Serial Number:
Subject Alternative Names:
        DNS Names:      my-svc.my-namespace.svc.cluster.local
        IP Addresses:   192.0.2.24
                        10.0.34.2
Events: <none>

Mendapatkan Persetujuan CertificateSigningRequest

Penyetujuan CertificateSigningRequest dapat dilakukan dengan otomatis atau dilakukan sekali oleh administrator klaster. Informasi lebih lanjut tentang apa yang terjadi dibahas dibawah ini.

Unduh dan Gunakan Sertifikat

Setelah CSR ditandatangani dan disetujui, kamu akan melihat:

kubectl get csr
NAME                  AGE       REQUESTOR               CONDITION
my-svc.my-namespace   10m       yourname@example.com    Approved,Issued

Kamu bisa mengundur sertifikat yang telah diterbitkan dan menyimpannya ke berkas server.crt dengan menggunakan perintah berikut:

kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
    | base64 --decode > server.crt

Sekarang kamu bisa menggunakan server.crt dan server-key.pem sebagai pasangan kunci untuk memulai server HTTPS kamu.

Penyetujuan CertificateSigningRequest

Administrator Kubernetes (dengan izin yang cukup) dapat menyetujui secara manual (atau menolak) Certificate Signing Requests dengan menggunakan perintah kubectl certificate approve dan kubectl certificate deny. Namun jika kamu bermaksud untuk menggunakan API ini secara sering, kamu dapat mempertimbangkan untuk menulis Certificate controller otomatis.

Baik itu mesin atau manusia yang menggunakan kubectl seperti di atas, peran pemberi persetujuan adalah untuk memverifikasi bahwa CSR memenuhi dua persyaratan:

  1. Subjek CSR mengontrol kunci pribadi yang digunakan untuk menandatangani CSR. Ini mengatasi ancaman pihak ketiga yang menyamar sebagai subjek resmi. Pada contoh di atas, langkah ini adalah untuk memverifikasi bahwa Pod mengontrol kunci pribadi yang digunakan untuk menghasilkan CSR.
  2. Subjek CSR berwenang untuk bertindak dalam konteks yang diminta. Ini mengatasi ancaman subjek yang tidak diinginkan bergabung dengan klaster. Dalam contoh di atas, langkah ini untuk memverifikasi bahwa Pod diizinkan berpartisipasi dalam Service yang diminta.

Jika dan hanya jika kedua persyaratan ini dipenuhi, pemberi persetujuan harus menyetujui CSR dan sebaliknya harus menolak CSR.

Peringatan tentang Izin Persetujuan

Kemampuan untuk menyetujui CSR menentukan siapa yang mempercayai siapa di dalam lingkungan kamu. Kemampuan untuk menyetujui CSR tersebut seharusnya tidak diberikan secara luas. Persyaratan tantangan yang disebutkan di bagian sebelumnya dan dampak dari mengeluarkan sertifikat khusus, harus sepenuhnya dipahami sebelum memberikan izin ini.

Catatan Untuk Administrator Klaster

Tutorial ini mengasumsikan bahwa penanda tangan diatur untuk melayani API sertifikat. Kubernetes controller manager menyediakan implementasi bawaan dari penanda tangan. Untuk mengaktifkan, berikan parameter --cluster-signed-cert-file dan --cluster-signed-key-file ke controller manager dengan path ke pasangan kunci CA kamu.

11 - Mengelola Daemon Klaster

Melakukan tugas-tugas umum untuk mengelola sebuah DaemonSet, misalnya rolling update.

11.1 - Melakukan Rollback pada DaemonSet

Laman ini memperlihatkan bagaimana caranya untuk melakukan rollback pada sebuah DaemonSet.

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 1.7. Untuk melihat versi, tekan kubectl version.

Sebelum lanjut, alangkah baiknya jika kamu telah mengetahui cara untuk melakukan rolling update pada sebuah DaemonSet.

Melakukan rollback pada DaemonSet

Langkah 1: Dapatkan nomor revisi DaemonSet yang ingin dikembalikan

Lompati langkah ini jika kamu hanya ingin kembali (rollback) ke revisi terakhir.

Perintah di bawah ini akan memperlihatkan daftar semua revisi dari DaemonSet:

kubectl rollout history daemonset <nama-daemonset>

Perintah tersebut akan menampilkan daftar revisi seperti di bawah:

daemonsets "<nama-daemonset>"
REVISION        CHANGE-CAUSE
1               ...
2               ...
...
  • Alasan perubahan (change cause) kolom di atas merupakan salinan dari anotasi kubernetes.io/change-cause yang berkaitan dengan revisi pada DaemonSet. Kamu boleh menyetel flag --record=true melalui kubectl untuk merekam perintah yang dijalankan akibat dari anotasi alasan perubahan.

Untuk melihat detail dari revisi tertentu, jalankan perintah di bawah ini:

kubectl rollout history daemonset <daemonset-name> --revision=1

Perintah tersebut memberikan detail soal nomor revisi tertentu:

daemonsets "<nama-daemonset>" with revision #1
Pod Template:
Labels:       foo=bar
Containers:
app:
 Image:        ...
 Port:         ...
 Environment:  ...
 Mounts:       ...
Volumes:      ...

Langkah 2: Rollback ke revisi tertentu

# Tentukan nomor revisi yang kamu dapatkan dari Langkah 1 melalui --to-revision
kubectl rollout undo daemonset <nama-daemonset> --to-revision=<nomor-revisi>

Jika telah berhasil, perintah tersebut akan memberikan keluaran berikut:

daemonset "<nama-daemonset>" rolled back

Langkah 3: Lihat progres pada saat rollback DaemonSet

Perintah kubectl rollout undo daemonset memberitahu server untuk memulai rollback DaemonSet. Rollback sebenarnya terjadi secara asynchronous di dalam klaster _control plane_.

Perintah di bawah ini dilakukan untuk melihat progres dari rollback:

kubectl rollout status ds/<nama-daemonset>

Ketika rollback telah selesai dilakukan, keluaran di bawah akan ditampilkan:

daemonset "<nama-daemonset>" successfully rolled out

Memahami revisi DaemonSet

Pada langkah kubectl rollout history sebelumnya, kamu telah mendapatkan daftar revisi DaemonSet. Setiap revisi disimpan di dalam sumber daya bernama ControllerRevision.

Untuk melihat apa yang disimpan pada setiap revisi, dapatkan sumber daya mentah (raw) dari revisi DaemonSet:

kubectl get controllerrevision -l <kunci-selektor-daemonset>=<nilai-selektor-daemonset>

Perintah di atas akan mengembalikan daftar ControllerRevision:

NAME                               CONTROLLER                     REVISION   AGE
<nama-daemonset>-<hash-revisi>   DaemonSet/<nama-daemonset>     1          1h
<nama-daemonset>-<hash-revisi>   DaemonSet/<nama-daemonset>     2          1h

Setiap ControllerRevision menyimpan anotasi dan templat dari sebuah revisi DaemonSet.

Perintah kubectl rollout undo mengambil ControllerRevision yang spesifik dan mengganti templat DaemonSet dengan templat yang tersimpan pada ControllerRevision. Perintah kubectl rollout undo sama seperti untuk memperbarui templat DaemonSet ke revisi sebelumnya dengan menggunakan perintah lainnya, seperti kubectl edit atau kubectl apply.

Troubleshoot