Target pembaca: kamu sudah terbiasa dengan docker run, docker build, docker-compose, dan paham konsep image, container, volume, serta network di Docker. Modul ini membangun pemahaman Kubernetes (K8s) di atas fondasi itu, bukan mengulang dari nol.
Format: teori singkat → analogi ke Docker → praktik langsung di komputer kamu.
Daftar Isi
- Kenapa Butuh Kubernetes Kalau Sudah Ada Docker
- Arsitektur Kubernetes (dari sudut pandang pengguna Docker)
- Persiapan Lab: Instalasi kind + kubectl
- Pod — "Container" Versi Kubernetes
- Deployment — Mengelola Banyak Pod
- Service — Networking Antar Pod
- ConfigMap & Secret — Ganti .env
- Volume & Persistent Storage
- Namespace — Mengelompokkan Resource
- Ingress — Expose ke Luar Cluster
- Lab Akhir: Deploy Aplikasi Full-Stack
- Cheat Sheet kubectl
- Langkah Selanjutnya
1. Kenapa Butuh Kubernetes Kalau Sudah Ada Docker
Dengan Docker (atau docker-compose), kamu menjalankan container di satu mesin. Itu bagus untuk development, tapi di production biasanya kamu butuh:
- Container berjalan di banyak mesin/server (cluster), bukan cuma satu.
- Kalau satu container mati, ada yang otomatis menyalakan ulang.
- Kalau traffic naik, container otomatis digandakan (scaling).
- Deploy versi baru tanpa downtime (rolling update).
- Load balancing otomatis antar banyak instance container.
Docker Compose bisa menjalankan banyak container di satu mesin. Kubernetes melakukan hal serupa tapi di banyak mesin sekaligus, dengan otomatisasi self-healing dan scaling bawaan. Anggap saja: Docker membuat dan menjalankan container satu-satu, Kubernetes mengorkestrasi ribuan container di banyak mesin agar tetap sesuai kondisi yang kamu inginkan.
Konsep kuncinya adalah declarative & desired state: kamu bilang ke Kubernetes "saya mau 3 replika container ini selalu berjalan", lalu Kubernetes yang bekerja terus-menerus memastikan kondisi itu tercapai — beda dengan docker run yang sifatnya imperatif (perintah sekali jalan).
2. Arsitektur Kubernetes (dari Sudut Pandang Pengguna Docker)
| Docker | Kubernetes | Penjelasan |
|---|---|---|
| Docker Engine di 1 mesin | Cluster (banyak mesin/Node) | Kumpulan mesin yang dikelola bareng |
| — | Control Plane | "Otak" cluster: menerima perintah, menjaga desired state |
| Mesin tempat container jalan | Node (Worker) | Mesin yang benar-benar menjalankan container |
docker run |
Pod | Unit terkecil yang bisa di-deploy (bungkus 1+ container) |
docker-compose.yml |
YAML manifest | File deklaratif untuk describe resource |
| Docker CLI | kubectl | CLI untuk bicara ke cluster |
docker network |
Service | Networking & load balancing antar Pod |
.env file / docker run -e
|
ConfigMap / Secret | Konfigurasi & data sensitif |
docker volume |
PersistentVolume | Penyimpanan data yang persisten |
Komponen Control Plane yang penting untuk diketahui (tidak perlu dihafal detail, cukup paham perannya):
-
kube-apiserver — pintu masuk semua perintah (yang diketuk
kubectl). - etcd — database yang menyimpan seluruh state cluster.
- kube-scheduler — menentukan Pod baru dijalankan di Node mana.
- kube-controller-manager — "pengawas" yang terus mencocokkan kondisi aktual dengan desired state (misal: kalau Pod mati, ia yang minta dibuat lagi).
Di sisi Node ada kubelet (agen yang menjalankan Pod, mirip peran Docker Engine) dan kube-proxy (mengatur networking).
3. Persiapan Lab: Instalasi kind + kubectl
Kita pakai kind (Kubernetes IN Docker) — cluster Kubernetes yang jalan sebagai container Docker di laptop kamu. Cocok karena kamu sudah punya Docker terinstal.
3.1 Instal kubectl
# macOS
brew install kubectl
# Linux
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl && sudo mv kubectl /usr/local/bin/
# Windows (PowerShell, via choco)
choco install kubernetes-cli
Cek instalasi:
kubectl version --client
3.2 Instal kind
# macOS
brew install kind
# Linux
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind
3.3 Buat cluster pertama
kind create cluster --name belajar-k8s
Kind akan membuat container Docker yang berperan sebagai Node Kubernetes. Cek dengan Docker:
docker ps # akan terlihat container bernama belajar-k8s-control-plane
Cek cluster dari sisi kubectl:
kubectl cluster-info
kubectl get nodes
Kalau muncul 1 node dengan status Ready, lab kamu siap.
4. Pod — "Container" Versi Kubernetes
Analogi Docker: docker run nginx menjalankan satu container. Di Kubernetes, unit terkecil yang dijalankan bukan container langsung, tapi Pod — pembungkus di sekitar satu atau lebih container yang selalu di-deploy bersama, berbagi network (satu IP) dan bisa berbagi volume.
Kamu jarang membuat Pod secara manual di production (nanti pakai Deployment), tapi penting paham dasarnya dulu.
pod-nginx.yaml:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx-demo
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
Jalankan:
kubectl apply -f pod-nginx.yaml
kubectl get pods
kubectl describe pod nginx-pod
kubectl logs nginx-pod
kubectl exec -it nginx-pod -- /bin/bash
Perhatikan kubectl logs dan kubectl exec — persis seperti docker logs dan docker exec, hanya targetnya Pod, bukan container Docker langsung.
Hapus Pod:
kubectl delete -f pod-nginx.yaml
Catatan penting: kalau Pod ini mati (crash), tidak ada yang menyalakannya kembali secara otomatis karena ia berdiri sendiri (bare Pod). Untuk self-healing, kita butuh Deployment.
5. Deployment — Mengelola Banyak Pod
Deployment adalah objek yang mengelola sekumpulan Pod identik (lewat ReplicaSet di baliknya), menjamin jumlah replika sesuai keinginan, melakukan restart otomatis kalau Pod mati, dan mendukung rolling update.
Analogi Docker: mirip docker-compose up --scale web=3 tapi dengan self-healing dan rolling update bawaan, berjalan lintas banyak Node.
deployment-nginx.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
Jalankan dan amati:
kubectl apply -f deployment-nginx.yaml
kubectl get deployments
kubectl get pods -o wide
Coba self-healing: hapus salah satu Pod secara manual, lalu lihat Kubernetes otomatis membuat penggantinya.
kubectl delete pod <nama-salah-satu-pod>
kubectl get pods -w # -w = watch, lihat pod baru muncul otomatis
Coba scaling:
kubectl scale deployment nginx-deployment --replicas=5
kubectl get pods
Coba rolling update (ganti versi image tanpa downtime):
kubectl set image deployment/nginx-deployment nginx=nginx:1.28
kubectl rollout status deployment/nginx-deployment
kubectl rollout history deployment/nginx-deployment
kubectl rollout undo deployment/nginx-deployment # rollback kalau perlu
6. Service — Networking Antar Pod
Masalah: Pod itu "fana" — bisa mati dan dibuat ulang dengan IP baru kapan saja. Kalau Pod lain mau terhubung, tidak bisa hardcode IP Pod. Di sinilah Service berperan: memberi satu alamat stabil (nama DNS + IP virtual) yang otomatis me-load-balance ke Pod-Pod yang cocok dengan label tertentu.
Analogi Docker: mirip Docker's default bridge network + DNS berbasis nama container/service di docker-compose, tapi dengan load balancing built-in ke banyak replika di banyak Node.
Jenis Service yang paling sering dipakai:
- ClusterIP (default): hanya bisa diakses dari dalam cluster.
- NodePort: expose port statis di setiap Node, bisa diakses dari luar cluster.
- LoadBalancer: minta cloud provider menyediakan load balancer eksternal (di kind, kita simulasikan lewat NodePort atau port-forward).
service-nginx.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx-demo
ports:
- port: 80 # port di dalam cluster
targetPort: 80 # port di container
nodePort: 30080 # port yang diexpose ke luar (range 30000-32767)
kubectl apply -f service-nginx.yaml
kubectl get svc
Cara paling gampang mengakses dari laptop kamu saat pakai kind adalah lewat port-forward (setara docker run -p):
kubectl port-forward service/nginx-service 8080:80
Buka http://localhost:8080 di browser — kamu akan melihat halaman default nginx, dan trafficnya di-load-balance ke salah satu dari 5 Pod tadi.
Coba lihat load balancing-nya bekerja:
# di terminal lain, panggil berkali-kali dan bandingkan hostname/IP responsnya
kubectl exec -it <nama-salah-satu-pod> -- curl -s http://nginx-service | head -5
7. ConfigMap & Secret — Ganti .env
Di Docker, kamu biasa pakai file .env atau flag -e KEY=VALUE. Di Kubernetes, itu digantikan oleh:
-
ConfigMap — untuk konfigurasi non-sensitif (mirip
.envbiasa). - Secret — untuk data sensitif (password, token), disimpan ter-encode base64 (bukan enkripsi kuat secara default, tapi terpisah aksesnya lewat RBAC).
configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
APP_DEBUG: "false"
secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
stringData:
DB_PASSWORD: "supersecret123"
Pakai keduanya di dalam Pod/Deployment sebagai environment variable — persis seperti docker run -e:
spec:
containers:
- name: app
image: myapp:latest
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secret
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl get configmap app-config -o yaml
kubectl get secret app-secret -o yaml # value akan ter-encode base64
8. Volume & Persistent Storage
Sama seperti container Docker, filesystem di dalam Pod bersifat ephemeral (hilang saat Pod mati/diganti). Untuk data yang harus bertahan, Kubernetes punya beberapa lapis abstraksi:
-
Volume — mirip
docker volume, tapi didefinisikan per-Pod. - PersistentVolume (PV) — representasi storage fisik di cluster (disediakan admin/cloud).
-
PersistentVolumeClaim (PVC) — "permintaan" storage dari aplikasi, tidak peduli implementasi fisiknya (analogi: PVC itu seperti
docker volume createyang lalu di-attach).
pvc.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Pakai di Deployment:
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- mountPath: /data
name: data-volume
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: data-pvc
kubectl apply -f pvc.yaml
kubectl get pvc
Data di /data akan tetap ada meskipun Pod-nya dihapus dan dibuat ulang, selama PVC-nya tidak dihapus — persis seperti volume Docker yang bertahan lepas dari siklus hidup container.
9. Namespace — Mengelompokkan Resource
Namespace membagi satu cluster menjadi beberapa "ruang" logis terpisah — berguna untuk memisahkan environment (dev, staging, production) atau tim, dalam satu cluster fisik yang sama. Tidak ada konsep langsung di Docker; paling dekat analoginya adalah punya beberapa project docker-compose terpisah, tapi di dalam infrastruktur yang sama.
kubectl create namespace dev
kubectl get namespaces
kubectl apply -f deployment-nginx.yaml -n dev
kubectl get pods -n dev
Secara default, kubectl bekerja di namespace default. Gunakan flag -n <namespace> atau ubah context default:
kubectl config set-context --current --namespace=dev
10. Ingress — Expose ke Luar Cluster
Kalau punya banyak Service HTTP dan ingin mengaturnya lewat satu entry point berbasis domain/path (mirip reverse proxy seperti Nginx/Traefik di depan banyak container Docker), pakai Ingress.
Contoh konsepnya (butuh Ingress Controller terpasang dulu di cluster, misalnya ingress-nginx):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
rules:
- host: app.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
Untuk kind, instalasi Ingress Controller butuh langkah tambahan (config khusus port mapping) — cukup pahami konsepnya dulu di tahap belajar ini; ini biasanya baru dipakai serius saat kamu deploy ke cluster cloud (GKE/EKS/AKS).
11. Lab Akhir: Deploy Aplikasi Full-Stack
Sekarang gabungkan semua konsep di atas dengan mendeploy aplikasi sederhana: web app + database, mirip skenario docker-compose.yml yang biasa kamu tulis.
Bayangkan docker-compose.yml versi Docker seperti ini:
services:
web:
image: myapp:latest
ports: ["8080:3000"]
environment:
- DB_HOST=db
depends_on: [db]
db:
image: postgres:16
environment:
- POSTGRES_PASSWORD=secret
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Versi Kubernetes-nya (fullstack.yaml), gabungkan semua konsep di atas dalam satu file (dipisah ---):
# --- Secret untuk password DB ---
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
POSTGRES_PASSWORD: "secret"
---
# --- Storage untuk data DB ---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-pvc
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
---
# --- Deployment Database ---
apiVersion: apps/v1
kind: Deployment
metadata:
name: db
spec:
replicas: 1
selector:
matchLabels: { app: db }
template:
metadata:
labels: { app: db }
spec:
containers:
- name: postgres
image: postgres:16
envFrom:
- secretRef: { name: db-secret }
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: db-data
volumes:
- name: db-data
persistentVolumeClaim: { claimName: db-pvc }
---
# --- Service Database (ClusterIP, hanya internal) ---
apiVersion: v1
kind: Service
metadata:
name: db
spec:
selector: { app: db }
ports:
- port: 5432
targetPort: 5432
---
# --- Deployment Web App ---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 2
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: nginx:1.27 # ganti dengan image aplikasimu
ports:
- containerPort: 80
env:
- name: DB_HOST
value: "db" # nama Service DB, resolve otomatis lewat DNS internal
---
# --- Service Web (NodePort, bisa diakses dari luar) ---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: NodePort
selector: { app: web }
ports:
- port: 80
targetPort: 80
nodePort: 30081
Deploy semuanya sekaligus:
kubectl apply -f fullstack.yaml
kubectl get all
Verifikasi:
kubectl port-forward service/web 8080:80
# buka http://localhost:8080
kubectl exec -it deploy/web -- curl -s http://db:5432 # buktikan DNS internal 'db' resolve
Poin penting yang baru saja kamu praktikkan: service discovery via DNS — di dalam cluster, Pod web bisa memanggil db cukup dengan nama Service-nya (http://db:5432), Kubernetes otomatis resolve ke IP Pod yang sesuai dan load balance kalau replikanya lebih dari satu. Ini menggantikan networking docker-compose yang kamu kenal, tapi berjalan lintas banyak Node.
Bersihkan lab:
kubectl delete -f fullstack.yaml
kind delete cluster --name belajar-k8s
12. Cheat Sheet kubectl
| Docker | Kubectl setara |
|---|---|
docker run |
kubectl apply -f pod.yaml |
docker ps |
kubectl get pods |
docker logs <container> |
kubectl logs <pod> |
docker exec -it <container> bash |
kubectl exec -it <pod> -- bash |
docker stop/rm |
kubectl delete pod <pod> |
docker inspect |
kubectl describe pod <pod> |
docker-compose up |
kubectl apply -f manifest.yaml |
docker-compose down |
kubectl delete -f manifest.yaml |
docker images |
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].image}' |
docker network ls |
kubectl get svc |
docker stats |
kubectl top pods (butuh metrics-server) |
Perintah tambahan yang sering dipakai sehari-hari:
kubectl get all # lihat semua resource di namespace aktif
kubectl get pods -o wide # detail lebih lengkap termasuk Node & IP
kubectl explain deployment.spec # dokumentasi field YAML langsung dari CLI
kubectl apply -f . # apply semua manifest di folder
kubectl diff -f fullstack.yaml # lihat perubahan sebelum apply
kubectl get events --sort-by=.lastTimestamp # debugging umum
13. Langkah Selanjutnya
Setelah modul ini, urutan belajar yang disarankan:
-
Helm — package manager untuk Kubernetes, mirip menggabungkan banyak manifest YAML jadi satu "chart" yang bisa di-versioning dan di-parameterisasi (analogi: seperti templating untuk
docker-compose.yml). - Resource requests & limits — mengatur alokasi CPU/RAM per Pod, penting untuk production.
-
Liveness & Readiness Probe — health check otomatis (mirip
HEALTHCHECKdi Dockerfile, tapi lebih terintegrasi dengan self-healing). - Horizontal Pod Autoscaler (HPA) — auto-scaling berdasarkan CPU/memory/metrik custom.
-
CI/CD ke Kubernetes — GitOps dengan ArgoCD/Flux, atau pipeline biasa dengan
kubectl apply. - Cluster managed — coba di cloud sungguhan: GKE, EKS, AKS, atau alternatif ringan seperti k3s untuk home lab.
Selamat belajar — cara terbaik menguasai ini adalah mengulang Bagian 11 dengan aplikasi Docker kamu sendiri (ganti image nginx dengan image aplikasi yang biasa kamu jalankan lewat docker-compose).
Top comments (0)