1 - Ikhtisar Kontainer

Kontainer adalah teknologi untuk mengemas kode (yang telah dikompilasi) menjadi suatu aplikasi beserta dengan dependensi-dependensi yang dibutuhkannya pada saat dijalankan. Setiap kontainer yang Anda jalankan dapat diulang; standardisasi dengan menyertakan dependensinya berarti Anda akan mendapatkan perilaku yang sama di mana pun Anda menjalankannya.

Kontainer memisahkan aplikasi dari infrastruktur host yang ada dibawahnya. Hal ini membuat penyebaran lebih mudah di lingkungan cloud atau OS yang berbeda.

Image-Image Kontainer

Kontainer image meruapakan paket perangkat lunak yang siap dijalankan, mengandung semua yang diperlukan untuk menjalankan sebuah aplikasi: kode dan setiap runtime yang dibutuhkan, library dari aplikasi dan sistem, dan nilai default untuk penganturan yang penting.

Secara desain, kontainer tidak bisa berubah: Anda tidak dapat mengubah kode dalam kontainer yang sedang berjalan. Jika Anda memiliki aplikasi yang terkontainerisasi dan ingin melakukan perubahan, maka Anda perlu membuat kontainer baru dengan menyertakan perubahannya, kemudian membuat ulang kontainer dengan memulai dari image yang sudah diubah.

Kontainer runtime

Kontainer runtime adalah perangkat lunak yang bertanggung jawab untuk menjalankan kontainer. Kubernetes mendukung beberapa kontainer runtime: Docker, containerd, CRI-O, dan semua implementasi dari Kubernetes CRI (Container Runtime Interface).

Selanjutnya

2 - Image

Kamu membuat Docker image dan mengunduhnya ke sebuah registri sebelum digunakan di dalam Kubernetes Pod.

Properti image dari sebuah Container mendukung sintaksis yang sama seperti perintah docker, termasuk registri privat dan tag.

Memperbarui Image

Kebijakan pull default adalah IfNotPresent yang membuat Kubelet tidak lagi mengunduh (pull) sebuah image jika sudah ada terlebih dahulu. Jika kamu ingin agar selalu diunduh, kamu bisa melakukan salah satu dari berikut:

  • mengatur imagePullPolicy dari Container menjadi Always.
  • buang imagePullPolicy dan gunakan :latest tag untuk image yang digunakan.
  • buang imagePullPolicy dan juga tag untuk image.
  • aktifkan AlwaysPullImages admission controller.

Harap diingat kamu sebaiknya hindari penggunaan tag :latest, lihat panduan konfigurasi untuk informasi lebih lanjut.

Membuat Image Multi-arsitektur dengan Manifest

Docker CLI saat ini mendukung perintah docker manifest dengan anak perintah create, annotate, dan push. Perintah-perintah ini dapat digunakan untuk membuat (build) dan mengunggah (push) manifes. Kamu dapat menggunakan perintah docker manifest inspect untuk membaca manifes.

Lihat dokumentasi docker di sini: https://docs.docker.com/edge/engine/reference/commandline/manifest/

Lihat contoh-contoh bagaimana kami menggunakan ini untuk proses build harness: https://cs.k8s.io/?q=docker%20manifest%20(create%7Cpush%7Cannotate)&i=nope&files=&repos=

Perintah-perintah ini bergantung pada Docker CLI, dan diimplementasi hanya di sisi CLI. Kamu harus mengubah $HOME/.docker/config.json dan mengatur key experimental untuk mengaktifkan atau cukup dengan mengatur DOCKER_CLI_EXPERIMENTAL variabel environment menjadi enabled ketika memanggil perintah-perintah CLI.

Catatan: Gunakan Docker 18.06 ke atas, versi-versi di bawahnya memiliki bug ataupun tidak mendukung perintah eksperimental. Contohnya https://github.com/docker/cli/issues/1135 yang menyebabkan masalah di bawah containerd.

Kalau kamu terkena masalah ketika mengunggah manifes-manifes yang rusak, cukup bersihkan manifes-manifes yang lama di $HOME/.docker/manifests untuk memulai dari awal.

Untuk Kubernetes, kami biasanya menggunakan image-image dengan sufiks -$(ARCH). Untuk kompatibilitas (backward compatibility), lakukan generate image-image yang lama dengan sufiks. Idenya adalah men-generate, misalnya pause image yang memiliki manifes untuk semua arsitektur dan misalnya pause-amd64 yang punya kompatibilitas terhadap konfigurasi-konfigurasi lama atau berkas-berkas YAML yang bisa saja punya image-image bersufiks yang di-hardcode.

Menggunakan Registri Privat (Private Registry)

Biasanya kita memerlukan key untuk membaca image-image yang tersedia pada suatu registri privat. Kredensial ini dapat disediakan melalui beberapa cara:

  • Menggunakan Google Container Registry
    • per-klaster
    • konfigurasi secara otomatis pada Google Compute Engine atau Google Kubernetes Engine
    • semua Pod dapat membaca registri privat yang ada di dalam proyek
  • Menggunakan Amazon Elastic Container Registry (ECR)
    • menggunakan IAM role dan policy untuk mengontrol akses ke repositori ECR
    • secara otomatis refresh kredensial login ECR
  • Menggunakan Oracle Cloud Infrastructure Registry (OCIR)
    • menggunakan IAM role dan policy untuk mengontrol akses ke repositori OCIR
  • Menggunakan Azure Container Registry (ACR)
  • Menggunakan IBM Cloud Container Registry
    • menggunakan IAM role dan policy untuk memberikan akses ke IBM Cloud Container Registry
  • Konfigurasi Node untuk otentikasi registri privat
    • semua Pod dapat membaca registri privat manapun
    • memerlukan konfigurasi Node oleh admin klaster
  • Pra-unduh image
    • semua Pod dapat menggunakan image apapun yang di-cached di dalam sebuah Node
    • memerlukan akses root ke dalam semua Node untuk pengaturannya
  • Mengatur ImagePullSecrets dalam sebuah Pod
    • hanya Pod-Pod yang menyediakan key sendiri yang dapat mengakses registri privat

Masing-masing opsi dijelaskan lebih lanjut di bawah ini.

Menggunakan Google Container Registry

Kubernetes memiliki dukungan native untuk Google Container Registry (GCR), ketika dijalankan pada Google Compute Engine (GCE). Jika kamu menjalankan klaster pada GCE atau Google Kubernetes Engine, cukup gunakan nama panjang image (misalnya gcr.io/my_project/image:tag).

Semua Pod di dalam klaster akan memiliki akses baca image di registri ini.

Kubelet akan melakukan otentikasi GCR menggunakan service account yang dimiliki instance Google. Service acccount pada instance akan memiliki sebuah https://www.googleapis.com/auth/devstorage.read_only, sehingga dapat mengunduh dari GCR di proyek yang sama, tapi tidak untuk unggah.

Menggunakan Amazon Elastic Container Registry

Kubernetes memiliki dukungan native untuk Amazon Elastic Container Registry, ketika Node adalah AWS EC2 instance.

Cukup gunakan nama panjang image (misalnya ACCOUNT.dkr.ecr.REGION.amazonaws.com/imagename:tag) di dalam definisi Pod.

Semua pengguna klaster yang dapat membuat Pod akan bisa menjalankan Pod yang dapat menggunakan image-image di dalam registri ECR.

Kubelet akan mengambil dan secara periodik memperbarui kredensial ECR, yang memerlukan permission sebagai berikut:

  • ecr:GetAuthorizationToken
  • ecr:BatchCheckLayerAvailability
  • ecr:GetDownloadUrlForLayer
  • ecr:GetRepositoryPolicy
  • ecr:DescribeRepositories
  • ecr:ListImages
  • ecr:BatchGetImage

Persyaratan:

  • Kamu harus menggunakan versi kubelet v1.2.0 atau lebih (misal jalankan /usr/bin/kubelet --version=true).
  • Jika Node yang kamu miliki ada di region A dan registri kamu ada di region yang berbeda misalnya B, kamu perlu versi v1.3.0 atau lebih.
  • ECR harus tersedia di region kamu.

Cara troubleshoot:

  • Verifikasi semua persyaratan di atas.
  • Dapatkan kredensial $REGION (misalnya us-west-2) pada workstation kamu. Lakukan SSH ke dalam host dan jalankan Docker secara manual menggunakan kredensial tersebut. Apakah berhasil?
  • Tambahkan verbositas level log kubelet paling tidak 3 dan periksa log kubelet (misal journalctl -u kubelet) di baris-baris yang seperti ini:
    • aws_credentials.go:109] unable to get ECR credentials from cache, checking ECR API
    • aws_credentials.go:116] Got ECR credentials from ECR API for <AWS account ID for ECR>.dkr.ecr.<AWS region>.amazonaws.com

Menggunakan Azure Container Registry (ACR)

Ketika menggunakan Azure Container Registry kamu dapat melakukan otentikasi menggunakan pengguna admin maupun sebuah service principal. Untuk keduanya, otentikasi dilakukan melalui proses otentikasi Docker standar. Instruksi-instruksi ini menggunakan perangkat azure-cli.

Kamu pertama perlu membuat sebuah registri dan men-generate kredensial, dokumentasi yang lengkap tentang hal ini dapat dilihat pada dokumentasi Azure container registry.

Setelah kamu membuat registri, kamu akan menggunakan kredensial berikut untuk login:

  • DOCKER_USER : service principal, atau pengguna admin
  • DOCKER_PASSWORD: kata sandi dari service principal, atau kata sandi dari pengguna admin
  • DOCKER_REGISTRY_SERVER: ${some-registry-name}.azurecr.io
  • DOCKER_EMAIL: ${some-email-address}

Ketika kamu sudah memiliki variabel-variabel di atas, kamu dapat mengkonfigurasi sebuah Kubernetes Secret dan menggunakannya untuk deploy sebuah Pod.

Menggunakan IBM Cloud Container Registry

IBM Cloud Container Registry menyediakan sebuah registri image privat yang multi-tenant, dapat kamu gunakan untuk menyimpan dan membagikan image-image secara aman. Secara default, image-image di dalam registri privat kamu akan dipindai (scan) oleh Vulnerability Advisor terintegrasi untuk deteksi isu keamanan dan kerentanan (vulnerability) yang berpotensi. Para pengguna di dalam akun IBM Cloud kamu dapat mengakses image, atau kamu dapat menggunakan IAM role dan policy untuk memberikan akses ke namespace di IBM Cloud Container Registry.

Untuk instalasi plugin CLI di IBM Cloud Containerr Registry dan membuat sebuah namespace untuk image-image kamu, lihat Mulai dengan IBM Cloud Container Registry.

Jika kamu menggunakan akun dan wilayah (region) yang sama, kamu dapat melakukan deploy image-image yang disimpan di dalam IBM Cloud Container Registry ke dalam namespace default dari klaster IBM Cloud Kubernetes Service yang kamu miliki tanpa konfigurasi tambahan, lihat Membuat kontainer dari image. Untuk opsi konfigurasi lainnya, lihat Bagaimana cara mengotorasi klaster untuk mengunduh image dari sebuah registri.

Konfigurasi Node untuk Otentikasi ke sebuah Registri Privat

Catatan: Jika kamu jalan di Google Kubernetes Engine, akan ada .dockercfg pada setiap Node dengan kredensial untuk Google Container Registry. Kamu tidak bisa menggunakan cara ini.
Catatan: Jika kamu jalan di AWS EC2 dan menggunakan EC2 Container Registry (ECR), kubelet pada setiap Node akan dapat mengatur dan memperbarui kredensial login ECR. Kamu tidak bisa menggunakan cara ini.
Catatan: Cara ini cocok jika kamu dapat mengontrol konfigurasi Node. Cara ini tidak akan bekerja dengan baik pada GCE, dan penyedia layanan cloud lainnya yang tidak melakukan penggantian Node secara otomatis.
Catatan: Kubernetes pada saat ini hanya mendukung bagian auths dan HttpHeaders dari konfigurasi docker. Hal ini berarti bantuan kredensial (credHelpers atau credsStore) tidak didukung.

Docker menyimpan key untuk registri privat pada $HOME/.dockercfg atau berkas $HOME/.docker/config.json. Jika kamu menempatkan berkas yang sama pada daftar jalur pencarian (search path) berikut, kubelet menggunakannya sebagai penyedia kredensial saat mengunduh image.

  • {--root-dir:-/var/lib/kubelet}/config.json
  • {cwd of kubelet}/config.json
  • ${HOME}/.docker/config.json
  • /.docker/config.json
  • {--root-dir:-/var/lib/kubelet}/.dockercfg
  • {cwd of kubelet}/.dockercfg
  • ${HOME}/.dockercfg
  • /.dockercfg
Catatan: Kamu mungkin harus mengatur HOME=/root secara eksplisit pada berkas environment kamu untuk kubelet.

Berikut langkah-langkah yang direkomendasikan untuk mengkonfigurasi Node kamu supaya bisa menggunakan registri privat. Pada contoh ini, coba jalankan pada desktop/laptop kamu:

  1. Jalankan docker login [server] untuk setiap set kredensial yang ingin kamu gunakan. Ini akan memperbarui $HOME/.docker/config.json.
  2. Lihat $HOME/.docker/config.json menggunakan editor untuk memastikan sudah berisi kredensial yang ingin kamu gunakan.
  3. Dapatkan daftar Node, contohnya:
    • jika kamu ingin mendapatkan nama: nodes=$(kubectl get nodes -o jsonpath='{range.items[*].metadata}{.name} {end}')
    • jika kamu ingin mendapatkan IP: nodes=$(kubectl get nodes -o jsonpath='{range .items[*].status.addresses[?(@.type=="ExternalIP")]}{.address} {end}')
  4. Salin .docker/config.json yang ada di lokal kamu pada salah satu jalur pencarian di atas.
    • contohnya: for n in $nodes; do scp ~/.docker/config.json root@$n:/var/lib/kubelet/config.json; done

Verifikasi dengana membuat sebuah Pod yanag menggunakan image privat, contohnya:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: private-image-test-1
spec:
  containers:
    - name: uses-private-image
      image: $PRIVATE_IMAGE_NAME
      imagePullPolicy: Always
      command: [ "echo", "SUCCESS" ]
EOF
pod/private-image-test-1 created

Jika semuanya berjalan dengan baik, maka setelah beberapa lama, kamu dapat menjalankan:

kubectl logs private-image-test-1

dan lihat pada keluaran perintah:

SUCCESS

Jika kamu mencurigai ada perintah yang gagal, kamu dapat menjalankan:

kubectl describe pods/private-image-test-1 | grep 'Failed'

Pada kasus gagal, keluarannya mirip seperti:

  Fri, 26 Jun 2015 15:36:13 -0700    Fri, 26 Jun 2015 15:39:13 -0700    19    {kubelet node-i2hq}    spec.containers{uses-private-image}    failed        Failed to pull image "user/privaterepo:v1": Error: image user/privaterepo:v1 not found

Kamu harus memastikan semua Node di dalam klaster memiliki .docker/config.json yang sama. Jika tidak, Pod-Pod akan jalan pada beberapa Node saja dan gagal di Node lainnya. Contohnya, jika kamu menggunakan Node autoscaling, maka setiap templat instance perlu untuk mempunyai .docker/config.json atau mount sebuah penyimpanan yang berisi berkas tersebut.

Semua Pod memiliki akses baca (read) untuk image-image di registri privat manapun ketika key registri privat ditambahkan pada .docker/config.json.

Image Pra-unduh

Catatan: Jika kamu jalan di Google Kubernetes Engine, maka akan ada .dockercfg pada setiap Node dengan kredensial untuk Google Container Registry. Kamu dapat menggunakan cara ini.
Catatan: Cara ini cocok jika kamu dapat mengontrol konfigurasi Node. Cara ini tidak akan bisa berjalan dengan baik pada GCE, dan penyedia cloud lainnya yang tidak menggantikan Node secara otomatis.

Secara default, kubelet akan mencoba untuk mengunduh setiap image dari registri yang dispesifikasikan. Hanya saja, jika properti imagePullPolicy diatur menjadi IfNotPresent atau Never, maka sebuah image lokal digunakan.

Jika kamu ingin memanfaatkan image pra-unduh sebagai pengganti untuk otentikasi registri, kamu harus memastikan semua Node di dalam klaster memiliki image pra-unduh yang sama.

Cara ini bisa digunakan untuk memuat image tertentu untuk kecepatan atau sebagai alternatif untuk otentikasi untuk sebuah registri privat.

Semua Pod akan mendapatkan akses baca ke image pra-unduh manapun.

Tentukan ImagePullSecrets pada sebuah Pod

Catatan: Cara ini merupakan cara yang direkomendasikan saat ini untuk Google Kubernetes Engine, GCE, dan penyedia cloud lainnya yang secara otomatis dapat membuat Node.

Kubernetes mendukung penentuan key registri pada sebuah Pod.

Membuat sebuah Secret dengan Docker Config

Jalankan perintah berikut, ganti nilai huruf besar dengan yang tepat:

kubectl create secret docker-registry <name> --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL

Jika kamu sudah memiliki berkas kredensial Docker, daripada menggunakan perintah di atas, kamu dapat mengimpor berkas kredensial sebagai Kubernetes Secret. Membuat sebuah Secret berbasiskan pada kredensial Docker yang sudah ada menjelaskan bagaimana mengatur ini. Cara ini berguna khususnya jika kamu menggunakan beberapa registri kontainer privat, perintah kubectl create secret docker-registry akan membuat sebuah Secret yang akan hanya bekerja menggunakan satu registri privat.

Catatan: Pod-Pod hanya dapat mengacu pada imagePullSecrets di dalam namespace, sehingga proses ini perlu untuk diselesaikan satu kali setiap namespace.

Mengacu pada imagePullSecrets di dalam sebuah Pod

Sekarang, kamu dapat membuat Pod yang mengacu pada Secret dengan menambahkan bagian imagePullSecrets untuk sebuah definisi Pod.

cat <<EOF > pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: awesomeapps
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: myregistrykey
EOF

cat <<EOF >> ./kustomization.yaml
resources:
- pod.yaml
EOF

Cara ini perlu untuk diselesaikan untuk setiap Pod yang mengguunakan registri privat.

Hanya saja, mengatur field ini dapat diotomasi dengan mengatur imagePullSecrets di dalam sumber daya serviceAccount. Periksa Tambahan ImagePullSecrets untuk sebuah Service Account untuk instruksi yang lebih detail.

Kamu dapat menggunakan cara ini bersama .docker/config.json pada setiap Node. Kredensial-kredensial akan dapat di-merged. Cara ini akan dapat bekerja pada Google Kubernetes Engine.

Kasus-Kasus Penggunaan (Use Case)

Ada beberapa solusi untuk konfigurasi registri privat. Berikut beberapa kasus penggunaan dan solusi yang disarankan.

  1. Klaster yang hanya menjalankan image non-proprietary (misalnya open-source). Tidak perlu unutuk menyembunyikan image.
    • Gunakan image publik pada Docker hub.
      • Tidak ada konfigurasi yang diperlukan.
      • Pada GCE/Google Kubernetes Engine, sebuah mirror lokal digunakan secara otomatis untuk meningkatkan kecepatan dan ketersediaan.
  2. Klaster yang menjalankan image proprietary yang seharusnya disembunyikan dari luar perusahaan, tetapi bisa terlihat oleh pengguna klaster.
    • Gunakan sebuah privat registri Docker yang hosted.
      • Bisa saja di-host pada Docker Hub, atau lainnya.
      • Konfigurasi .docker/config.json secara manual pada setiap Node seperti dijelaskan di atas.
    • Atau, jalankan sebuah registri privat internal di belakang firewall kamu dengan akses baca terbuka.
      • Tidak ada konfigurasi Kubernetes yang diperlukan.
    • Atau, ketika pada GCE/Google Kubernetes Engine, menggunakan Google Container Registry yang ada di proyek.
      • Hal ini bisa bekerja baik dengan autoscaling klaster dibandingkan konfigurasi Node manual.
    • Atau, pada sebuah klaster dimana mengubah konfigurasi Node tidak nyaman, gunakan imagePullSecrets.
  3. Klaster dengan image proprietary, beberapa memerlukan akses kontrol yang lebih ketat.
    • Pastikan AlwaysPullImages admission controller aktif. Sebaliknya, semua Pod berpotensi memiliki akses ke semua image.
    • Pindahkan data sensitif pada sumber daya "Secret", daripada mengemasnya menjadi sebuah image.
  4. Sebuah klaster multi-tenant dimana setiap tenant memerlukan registri privatnya masing-masing.
    • Pastikan AlwaysPullImages admission controller aktif. Sebaliknya, semua Pod dari semua tenant berpotensi memiliki akses pada semua image.
    • Jalankan sebuah registri privat dimana otorisasi diperlukan.
    • Men-generate kredensial registri uuntuk setiap tenant, masukkan ke dalam secret uuntuk setiap namespace tenant.
    • Tenant menambahkan secret pada imagePullSecrets uuntuk setiap namespace.

Jika kamu memiliki akses pada beberapa registri, kamu dapat membuat satu secret untuk setiap registri. Kubelet akan melakukan merge imagePullSecrets manapun menjadi sebuah virtual .docker/config.json.

3 - Kontainer Environment

Laman ini menjelaskan berbagai resource yang tersedia di dalam Kontainer pada suatu environment.

Environment Kontainer

Environment Kontainer pada Kubernetes menyediakan beberapa resource penting yang tersedia di dalam Kontainer:

  • Sebuah Filesystem, yang merupakan kombinasi antara image dan satu atau banyak volumes.
  • Informasi tentang Kontainer tersebut.
  • Informasi tentang objek-objek lain di dalam klaster.

Informasi tentang Kontainer

Hostname sebuah Kontainer merupakan nama dari Pod dimana Kontainer dijalankan. Informasi ini tersedia melalui perintah hostname atau panggilan (function call) gethostname pada libc.

Nama Pod dan namespace tersedia sebagai variabel environment melalui API downward.

Variabel environment yang ditulis pengguna dalam Pod definition juga tersedia di dalam Kontainer, seperti halnya variabel environment yang ditentukan secara statis di dalam image Docker.

Informasi tentang Klaster

Daftar semua Service yang dijalankan ketika suatu Kontainer dibuat, tersedia di dalam Kontainer tersebut sebagai variabel environment. Variabel-variabel environment tersebut sesuai dengan sintaksis links dari Docker.

Untuk suatu Service bernama foo yang terkait dengan Kontainer bernama bar, variabel-variabel di bawah ini tersedia:

FOO_SERVICE_HOST=<host dimana service dijalankan>
FOO_SERVICE_PORT=<port dimana service dijalankan>

Semua Service memiliki alamat-alamat IP yang bisa didapatkan di dalam Kontainer melalui DNS, jika addon DNS diaktifkan. 

Selanjutnya

4 - Runtime Class

FEATURE STATE: Kubernetes v1.14 [beta]

Laman ini menjelaskan tentang resource RuntimeClass dan proses pemilihan runtime.

Peringatan: RuntimeClass memiliki breaking change untuk pembaruan ke beta pada v1.14. Jika kamu menggunakan RuntimeClass sebelum v1.14, lihat Memperbarui RuntimeClass dari Alpha ke Beta.

Runtime Class

RuntimeClass merupakan sebuah fitur untuk memilih konfigurasi runtime kontainer. Konfigurasi tersebut digunakan untuk menjalankan kontainer-kontainer milik suatu Pod.

Persiapan

Pastikan gerbang fitur (feature gate) RuntimeClass sudah aktif (secara default sudah aktif). Lihat Gerbang Fitur untuk lebih jelasnya soal pengaktifan gerbang fitur. Gerbang fitur RuntimeClass ini harus aktif pada semua apiserver dan kubelet.

  1. Lakukan konfigurasi pada implementasi CRI untuk setiap node (tergantung runtime yang dipilih)
  2. Buat resource RuntimeClass yang terkait

1. Lakukan konfigurasi pada implementasi CRI untuk setiap node

Pilihan konfigurasi yang tersedia melalui RuntimeClass tergantung pada implementasi Container Runtime Interface (CRI). Lihat bagian (di bawah ini) soal bagaimana melakukan konfigurasi untuk implementasi CRI yang kamu miliki.

Catatan: Untuk saat ini, RuntimeClass berasumsi bahwa semua node di dalam klaster punya konfigurasi yang sama (homogen). Jika ada node yang punya konfigurasi berbeda dari yang lain (heterogen), maka perbedaan ini harus diatur secara independen di luar RuntimeClass melalui fitur scheduling (lihat Menempatkan Pod pada Node).

Seluruh konfigurasi memiliki nama handler yang terkait, dijadikan referensi oleh RuntimeClass. Nama handler harus berupa valid label 1123 DNS (alfanumerik + karakter -).

2. Buat resource RuntimeClass yang terkait

Masing-masing konfigurasi pada langkah no.1 punya nama handler yang merepresentasikan konfigurasi-konfigurasi tersebut. Untuk masing-masing handler, buatlah sebuah objek RuntimeClass terkait.

Resource RuntimeClass saat ini hanya memiliki 2 field yang penting: nama RuntimeClass tersebut (metadata.name) dan handler (handler). Definisi objek tersebut terlihat seperti ini:

apiVersion: node.k8s.io/v1beta1  # RuntimeClass didefinisikan pada grup API node.k8s.io
kind: RuntimeClass
metadata:
  name: myclass  # Nama dari RuntimeClass yang nantinya akan dijadikan referensi
  # RuntimeClass merupakan resource tanpa namespace
handler: myconfiguration  # Nama dari konfigurasi CRI terkait
Catatan: Sangat disarankan untuk hanya memperbolehkan admin klaster melakukan operasi write pada RuntimeClass. Biasanya ini sudah jadi default. Lihat Ikhtisar Autorisasi untuk penjelasan lebih jauh.

Penggunaan

Ketika RuntimeClass sudah dikonfigurasi pada klaster, penggunaannya sangatlah mudah. Kamu bisa tentukan runtimeClassName di dalam spec sebuah Pod, sebagai contoh:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  runtimeClassName: myclass
  # ...

Kubelet akan mendapat instruksi untuk menggunakan RuntimeClass dengan nama yang sudah ditentukan tersebut untuk menjalankan Pod ini. Jika RuntimeClass dengan nama tersebut tidak ditemukan, atau CRI tidak dapat menjalankan handler yang terkait, maka Pod akan memasuki tahap Failed. Lihat event untuk mengetahui pesan error yang terkait.

Jika tidak ada runtimeClassName yang ditentukan di dalam Pod, maka RuntimeHandler yang default akan digunakan. Untuk kasus ini, perilaku klaster akan seperti saat fitur RuntimeClass dinonaktifkan.

Konfigurasi CRI

Lihat instalasi CRI untuk lebih detail mengenai pengaturan runtime CRI.

dockershim

Built-in dockershim CRI yang dimiliki Kubernetes tidak mendukung handler runtime.

containerd

Handler runtime diatur melalui konfigurasi containerd pada /etc/containerd/config.toml. Handler yang valid dapat dikonfigurasi pada bagian runtime:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${HANDLER_NAME}]

Lihat dokumentasi konfigurasi containerd untuk lebih detail: https://github.com/containerd/cri/blob/master/docs/config.md

cri-o

Handler runtime dapat diatur menggunakan konfigurasi cri-o pada /etc/crio/crio.conf. Handler yang valid dapat dikonfigurasi pada tabel crio.runtime:

[crio.runtime.runtimes.${HANDLER_NAME}]
  runtime_path = "${PATH_TO_BINARY}"

Lihat dokumentasi konfigurasi cri-o untuk lebih detail: https://github.com/kubernetes-sigs/cri-o/blob/master/cmd/crio/config.go

Memperbarui RuntimeClass dari Alpha ke Beta

Fitur Beta pada RuntimeClass memiliki perubahan sebagai berikut:

  • Grup API resource node.k8s.io dan runtimeclasses.node.k8s.io telah dimigrasi ke suatu API built-in dari CustomResourceDefinition.
  • Atribut spec telah disederhakan pada definisi RuntimeClass (tidak ada lagi yang namanya RuntimeClassSpec).
  • Field runtimeHandler telah berubah nama menjadi handler.
  • Field handler sekarang bersifat wajib untuk semua versi API. Artinya, field runtimeHandler pada API Alpha juga bersifat wajib.
  • Field handler haruslah berupa label DNS valid (RFC 1123), yang artinya tidak bisa berisi karakter . (pada semua versi). Handler valid harus sesuai dengan regular expression ini: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$.

Tindakan yang diperlukan: Tindakan-tindaka berikut ini diperlukan untuk melakukan pembaruan fitur RuntimeClass dari versi alpha ke versi beta:

  • Resource RuntimeClass harus dibuat ulang setelah diperbarui ke v.1.14, dan CRD runtimeclasses.node.k8s.io harus dihapus secara manual:
    kubectl delete customresourcedefinitions.apiextensions.k8s.io runtimeclasses.node.k8s.io
    
  • Fitur Alpha pada RuntimeClass akan menjadi tidak valid, jika runtimeHandler tidak ditentukan atau kosong atau menggunakan karakter . pada handler. Ini harus dimigrasi ke handler dengan konfigurasi yang valid (lihat petunjuk di atas).

5 - Lifecyle Hook pada Kontainer

Laman ini menjelaskan bagaimana semua Kontainer yang diatur kubelet menggunakan framework lifecycle hook untuk menjalankan kode yang di-trigger oleh event selama lifecycle berlangsung.

Ikhtisar

Kubernetes menyediakan hook untuk lifecycle Kontainer. Hal ini sejalan dengan framework bahasa pemrograman pada umumnya yang memiliki hook untuk lifecycle komponen, seperti Angular contohnya. Hook tersebut digunakan Kontainer untuk selalu siap menerima event selama lifecycle dan menjalankan kode yang diimplementasi pada suatu handler, ketika hook lifecycle terkait telah dieksekusi.

Jenis-jenis hook pada Kontainer

Ada dua jenis hook yang diekspos pada Kontainer:

PostStart

Hook ini dijalankan segera setelah suatu kontainer dibuat. Hanya saja, tidak ada jaminan bahwa hook akan tereksekusi sebelum ENTRYPOINT dari kontainer. Tidak ada parameter yang diberikan pada handler.

PreStop

Hook ini akan dipanggil sesaat sebelum kontainer dimatikan, karena suatu request API atau event pengaturan, contohnya kegagalan pada liveness probe, preemption, perebutan resource, dan lainnya. Sebuah panggilan untuk hook PreStop akan gagal jika kontainer tersebut telah ada pada state terminate atau complete. Hal ini bersifat blocking, yang artinya panggilan bersifat sinkron (synchronous), harus menunggu eksekusi selesai, sebelum melakukan panggilan untuk menghapus kontainer tersebut. Tidak ada parameter yang diberikan pada handler.

Penjelasan yang lebih rinci tentang proses terminasi dapat dilihat pada Terminasi Pod.

Implementasi handler untuk hook

Kontainer dapat mengakses sebuah hook melalui implementasi dan registrasi sebuah handler untuk hook tersebut. Ada dua jenis handler untuk hook yang dapat diimplementasikan untuk Kontainer:

  • Exec - Mengeksekusi sebuah perintah tertentu, contohnya pre-stop.sh, di dalam cgroups dan namespace suatu Kontainer. Resource yang dikonsumsi oleh perintah tersebut dianggap sebagai bagian dari Kontainer.
  • HTTP - Mengeksekusi sebuah request HTTP untuk endpoint tertentu pada Kontainer tersebut.

Eksekusi handler untuk hook

Ketika manajemen hook untuk suatu lifecycle Kontainer dipanggil, sistem manajemen internal pada Kubernetes akan mengeksekusi handler di dalam Kontainer yang terdaftar untuk hook tersebut.

Panggilan handler untuk hook semuanya bersifat synchronous di dalam konteks Pod yang memiliki Kontainer tersebut. Artinya, untuk hook PostStart, Kontainer ENTRYPOINT dan hook dieksekusi secara asyncrhonous. Akan tetapi, jika hook mengambil waktu terlalu lama, atau hang, Kontainer tersebut tidak bisa sampai ke state running.

Perilaku ini mirip dengan yang terjadi pada hook PreStop. Jika hook terlalu lama atau hang saat dieksekusi, Pod tersebut tetap ada pada state Terminating dan akan dimatikan setelah terminationGracePeriodSeconds Pod selesai. Jika sebuah hook PostStart atau PreStop gagal dieksekusi, Kontainer akan dimatikan.

Para pengguna sangat disarankan membuat handler untuk hook seringan mungkin (lightweight). Biar bagaimanapun, ada beberapa kasus yang memang membutuhkan waktu lama untuk mengeksekusi suatu perintah, misalnya saat proses penyimpanan state sebelum Kontainer dimatikan.

Jaminan pengiriman hook

Proses pengiriman hook akan dilakukan paling tidak satu kali. Artinya suatu hook boleh dipanggil beberapa kali untuk event yang sama, seperti dalam PostStart atauPreStop. Namun begitu, implementasi hook masing-masing harus memastikan bagaimana menangani kasus ini dengan benar.

Pada umumnya, hanya terjadi satu proses pengiriman. Jika misalnya sebuah penerima HTTP hook mati atau tidak bisa menerima trafik, maka tidak ada usaha untuk mengirimkan kembali. Namun demikian, bisa saja terjadi dua kali proses pengiriman untuk kasus tertentu. Contohnya, jika kubelet restart saat di tengah proses pengiriman hook, hook tersebut akan dikirimkan kembali saat kubelet sudah hidup kembali.

Melakukan debug handler untuk hook

Log untuk suatu handler hook tidak terekspos pada event Pod. Jika handler gagal dieksekusi untuk alasan tertentu, handler akan melakukan broadcast sebuah event. Untuk PostStart, akan dilakukan broadcast event FailedPostStartHook, dan untuk PreStop, akan dilakukan broadcast event FailedPreStopHook. Kamu dapat melihat event-event ini dengan menjalankan perintah kubectl describe pod <pod_name>. Berikut merupakan contoh keluaran event-event setelah perintah tersebut dijalankan.

Events:
  FirstSeen  LastSeen  Count  From                                                   SubobjectPath          Type      Reason               Message
  ---------  --------  -----  ----                                                   -------------          --------  ------               -------
  1m         1m        1      {default-scheduler }                                                          Normal    Scheduled            Successfully assigned test-1730497541-cq1d2 to gke-test-cluster-default-pool-a07e5d30-siqd
  1m         1m        1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Pulling              pulling image "test:1.0"
  1m         1m        1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Created              Created container with docker id 5c6a256a2567; Security:[seccomp=unconfined]
  1m         1m        1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Pulled               Successfully pulled image "test:1.0"
  1m         1m        1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Started              Started container with docker id 5c6a256a2567
  38s        38s       1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Killing              Killing container with docker id 5c6a256a2567: PostStart handler: Error executing in Docker Container: 1
  37s        37s       1      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Normal    Killing              Killing container with docker id 8df9fdfd7054: PostStart handler: Error executing in Docker Container: 1
  38s        37s       2      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}                         Warning   FailedSync           Error syncing pod, skipping: failed to "StartContainer" for "main" with RunContainerError: "PostStart handler: Error executing in Docker Container: 1"
  1m         22s       2      {kubelet gke-test-cluster-default-pool-a07e5d30-siqd}  spec.containers{main}  Warning   FailedPostStartHook

Selanjutnya