DEV Community

Rupadana
Rupadana

Posted on

Belajar Kubernetes untuk Pengguna Docker

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

  1. Kenapa Butuh Kubernetes Kalau Sudah Ada Docker
  2. Arsitektur Kubernetes (dari sudut pandang pengguna Docker)
  3. Persiapan Lab: Instalasi kind + kubectl
  4. Pod — "Container" Versi Kubernetes
  5. Deployment — Mengelola Banyak Pod
  6. Service — Networking Antar Pod
  7. ConfigMap & Secret — Ganti .env
  8. Volume & Persistent Storage
  9. Namespace — Mengelompokkan Resource
  10. Ingress — Expose ke Luar Cluster
  11. Lab Akhir: Deploy Aplikasi Full-Stack
  12. Cheat Sheet kubectl
  13. 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
Enter fullscreen mode Exit fullscreen mode

Cek instalasi:

kubectl version --client
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

3.3 Buat cluster pertama

kind create cluster --name belajar-k8s
Enter fullscreen mode Exit fullscreen mode

Kind akan membuat container Docker yang berperan sebagai Node Kubernetes. Cek dengan Docker:

docker ps   # akan terlihat container bernama belajar-k8s-control-plane
Enter fullscreen mode Exit fullscreen mode

Cek cluster dari sisi kubectl:

kubectl cluster-info
kubectl get nodes
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Jalankan dan amati:

kubectl apply -f deployment-nginx.yaml
kubectl get deployments
kubectl get pods -o wide
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Coba scaling:

kubectl scale deployment nginx-deployment --replicas=5
kubectl get pods
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f service-nginx.yaml
kubectl get svc
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 .env biasa).
  • 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"
Enter fullscreen mode Exit fullscreen mode

secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
stringData:
  DB_PASSWORD: "supersecret123"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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 create yang lalu di-attach).

pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
Enter fullscreen mode Exit fullscreen mode

Pakai di Deployment:

    spec:
      containers:
        - name: app
          image: myapp:latest
          volumeMounts:
            - mountPath: /data
              name: data-volume
      volumes:
        - name: data-volume
          persistentVolumeClaim:
            claimName: data-pvc
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f pvc.yaml
kubectl get pvc
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Secara default, kubectl bekerja di namespace default. Gunakan flag -n <namespace> atau ubah context default:

kubectl config set-context --current --namespace=dev
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Deploy semuanya sekaligus:

kubectl apply -f fullstack.yaml
kubectl get all
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

13. Langkah Selanjutnya

Setelah modul ini, urutan belajar yang disarankan:

  1. 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).
  2. Resource requests & limits — mengatur alokasi CPU/RAM per Pod, penting untuk production.
  3. Liveness & Readiness Probe — health check otomatis (mirip HEALTHCHECK di Dockerfile, tapi lebih terintegrasi dengan self-healing).
  4. Horizontal Pod Autoscaler (HPA) — auto-scaling berdasarkan CPU/memory/metrik custom.
  5. CI/CD ke Kubernetes — GitOps dengan ArgoCD/Flux, atau pipeline biasa dengan kubectl apply.
  6. 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)