Tampilan
Kenapa penting
Di M13–M14 kamu sudah memecah sistem menjadi beberapa service dan menjalankannya dengan Docker Compose. Compose nyaman di laptop, tetapi di production pertanyaannya berubah: siapa yang menyalakan ulang container saat crash jam 3 pagi? Bagaimana menambah replika saat promo flash sale? Bagaimana merilis versi baru tanpa downtime, lalu mundur cepat kalau ada bug? Kubernetes (sering disingkat K8s) menjawab semua itu dan sudah menjadi platform standar di banyak perusahaan. Sebagai backend engineer, kamu mungkin tidak mengelola cluster-nya, tetapi kamu pasti menulis manifest, membaca status Pod, dan men-debug deployment yang gagal. Bab ini memberi fondasi itu.
Konsep inti
Kenapa orkestrasi?
Menjalankan satu container itu mudah. Menjalankan puluhan container di banyak mesin dengan kebutuhan berikut, itu yang sulit:
| Kebutuhan | Tanpa orkestrator | Dengan Kubernetes |
|---|---|---|
| Container crash | Restart manual / skrip buatan | Otomatis dibuat ulang |
| Menambah kapasitas | SSH ke server, docker run lagi | Ubah replicas, atau autoscaling |
| Penempatan di mesin | Kamu pilih sendiri | Scheduler memilih node yang cukup sumber |
| Menemukan alamat service | IP ditulis manual | Nama DNS stabil lewat Service |
| Rilis versi baru | Matikan lalu nyalakan (downtime) | Rolling update + rollback |
Kunci cara berpikir Kubernetes adalah desired state: kamu menyatakan "harus ada 3 replika order-service versi 1.4.0", lalu controller di dalam cluster terus-menerus membandingkan kondisi nyata dengan keinginan itu dan memperbaiki selisihnya (disebut reconciliation loop).
Arsitektur: control plane dan node
text
┌─────────────── Control plane ───────────────┐
kubectl ───► │ kube-apiserver ── etcd (penyimpanan state) │
│ kube-scheduler kube-controller-manager │
└──────────────────────┬──────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
┌────▼─────┐ ┌────▼─────┐ ┌────▼─────┐
│ Node 1 │ │ Node 2 │ │ Node 3 │
│ kubelet │ │ kubelet │ │ kubelet │
│ runtime │ │ runtime │ │ runtime │
│ [Pod][Pod]│ │ [Pod] │ │ [Pod][Pod]│
└──────────┘ └──────────┘ └──────────┘- kube-apiserver — pintu masuk semua perintah;
kubectlhanya klien HTTP ke sini. - etcd — database key-value yang menyimpan seluruh state cluster.
- kube-scheduler — memutuskan Pod baru ditempatkan di node mana.
- kube-controller-manager — menjalankan controller (Deployment, ReplicaSet, dll.) yang melakukan reconciliation.
- kubelet — agen di setiap node; menerima daftar Pod untuk node itu dan memastikan container-nya berjalan lewat container runtime (mis. containerd).
Pod, ReplicaSet, Deployment
Pod adalah unit terkecil yang dijadwalkan: satu atau beberapa container yang berbagi IP dan volume. Biasanya satu Pod berisi satu container aplikasi. Pod bersifat sementara — bila mati, ia diganti Pod baru dengan nama dan IP berbeda.
ReplicaSet menjaga agar jumlah Pod dengan label tertentu selalu sesuai replicas. Kamu hampir tidak pernah membuatnya langsung.
Deployment mengelola ReplicaSet dan menambahkan kemampuan rilis: saat image berubah, Deployment membuat ReplicaSet baru lalu memindahkan replika sedikit demi sedikit (rolling update), dan menyimpan riwayat untuk rollback.
text
Deployment order-service
└── ReplicaSet order-service-7d9f8c (image 1.4.0, replicas 3)
├── Pod order-service-7d9f8c-abc12
├── Pod order-service-7d9f8c-def34
└── Pod order-service-7d9f8c-ghi56Hubungan antar-objek diikat oleh label (pasangan kunci–nilai di metadata) dan selector (filter label). Ini konsep yang paling sering membuat pemula tersandung.
Service: alamat stabil untuk Pod yang berganti-ganti
Karena IP Pod berubah, klien butuh alamat tetap. Service memberi IP virtual dan nama DNS (mis. order-service.shop.svc.cluster.local, atau cukup order-service dari namespace yang sama), lalu meneruskan trafik ke Pod yang cocok dengan selector-nya — hanya Pod yang ready.
| Tipe | Bisa diakses dari | Kapan dipakai |
|---|---|---|
ClusterIP | Dalam cluster saja | Default; komunikasi antar-service |
NodePort | <IP-node>:<port 30000–32767> | Uji coba, cluster lokal |
LoadBalancer | IP publik dari cloud provider | Membuka satu service ke internet di cloud |
Namespace
Namespace membagi cluster secara logis — mis. shop-dev dan shop-staging, atau per tim. Nama objek cukup unik per namespace, dan kuota/akses bisa diatur per namespace. Namespace bukan batas keamanan jaringan secara otomatis; tanpa NetworkPolicy, Pod antar-namespace tetap bisa saling memanggil.
Ingress dan Gateway API sekilas
Membuat satu LoadBalancer per service itu mahal. Ingress memungkinkan satu titik masuk HTTP yang merutekan berdasarkan host/path (/api/orders → order-service), dijalankan oleh ingress controller. Penerusnya adalah Gateway API (Gateway, HTTPRoute) yang lebih ekspresif dan memisahkan peran tim platform dan tim aplikasi; proyek baru sebaiknya melirik Gateway API. Di microservices, peran ini sering bersinggungan dengan API gateway yang kamu pelajari di M14.
Manifest deklaratif dan kubectl
Semua objek ditulis sebagai YAML dengan empat bagian utama: apiVersion, kind, metadata, spec. File ini disimpan di Git dan di-apply:
bash
kubectl apply -f k8s/ # buat/perbarui sesuai file (idempotent)
kubectl get pods -n shop -o wide # daftar Pod + node + IP
kubectl describe pod order-service-7d9f8c-abc12 -n shop # detail + Events
kubectl logs deploy/order-service -n shop -f # log (ikuti) dari salah satu Pod
kubectl logs order-service-7d9f8c-abc12 -n shop --previous # log container yang crash
kubectl port-forward svc/order-service 8080:80 -n shop # akses lokal tanpa expose
kubectl rollout status deploy/order-service -n shop # tunggu rilis selesai
kubectl rollout undo deploy/order-service -n shop # kembali ke versi sebelumnyaCluster lokal dengan kind
kind (Kubernetes in Docker) menjalankan node Kubernetes sebagai container Docker — cocok untuk belajar dan CI.
bash
kind create cluster --name jalur
kubectl cluster-info --context kind-jalur
# image buatan lokal harus dimuat ke node kind (tidak ada registry bersama)
kind load docker-image order-service:1.4.0 --name jalur
kind delete cluster --name jalurContoh di dunia backend
Manifest untuk order-service (Spring Boot, port 8080) di namespace shop. Simpan sebagai k8s/order-service.yaml:
yaml
# Potongan — belum termasuk konfigurasi, secret, dan probe (dibahas di bab berikutnya)
apiVersion: v1
kind: Namespace
metadata:
name: shop
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: shop
labels:
app: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service # HARUS cocok dengan label template di bawah
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0 # jangan kurangi kapasitas saat rilis
maxSurge: 1 # boleh tambah 1 Pod sementara
template:
metadata:
labels:
app: order-service
version: "1.4.0"
spec:
containers:
- name: app
image: order-service:1.4.0 # tag tetap, bukan latest
ports:
- name: http
containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: shop
spec:
type: ClusterIP
selector:
app: order-service
ports:
- name: http
port: 80 # port yang dipanggil klien: http://order-service
targetPort: http # diteruskan ke containerPort bernama "http"Alur kerjanya di cluster kind:
bash
docker build -t order-service:1.4.0 .
kind load docker-image order-service:1.4.0 --name jalur
kubectl apply -f k8s/order-service.yaml
kubectl rollout status deploy/order-service -n shop
kubectl get pods -n shop --show-labels
kubectl port-forward svc/order-service 8080:80 -n shop
curl http://localhost:8080/api/orders/42Dari service lain di namespace shop, misalnya checkout-service, cukup panggil http://order-service/api/orders/42 — DNS cluster yang menyelesaikannya, dan Service membagi beban ke tiga Pod. Saat merilis 1.5.0, ubah tag image di manifest, kubectl apply lagi, dan pantau rollout status; bila error rate naik, kubectl rollout undo mengembalikan ReplicaSet lama dalam hitungan detik.
Pertanyaan interview
1. Apa beda Pod, ReplicaSet, dan Deployment?
Pod adalah unit terkecil yang berisi container dan bersifat sementara. ReplicaSet memastikan jumlah Pod berlabel tertentu sesuai replicas. Deployment mengelola ReplicaSet dan menambah strategi rilis (rolling update), riwayat revisi, dan rollback. Dalam praktik kamu menulis Deployment, bukan Pod atau ReplicaSet langsung.
2. Bagaimana sebuah Service tahu Pod mana yang harus menerima trafik?
Lewat label selector. Kubernetes memantau Pod yang labelnya cocok dengan selector Service dan dalam kondisi ready, lalu mencatat IP-nya sebagai endpoint (EndpointSlice). kube-proxy atau komponen jaringan di node meneruskan trafik ke IP virtual Service ke salah satu endpoint itu.
3. Kenapa Kubernetes disebut deklaratif dan apa untungnya?
Kamu menulis kondisi akhir yang diinginkan, bukan langkah-langkahnya. Controller terus melakukan reconciliation sehingga sistem memperbaiki diri saat Pod mati atau node hilang. Manifest bisa disimpan di Git, di-review lewat pull request, dan di-apply berulang secara idempotent — fondasi praktik GitOps.
Jebakan umum
- Label di
spec.selectorDeployment atau Service tidak cocok dengan label template Pod — Pod jalan, tapi Service tanpa endpoint. - Memakai tag
latest: tidak jelas versi mana yang berjalan, rollback tidak bermakna, dan node bisa memakai image cache yang berbeda. - Menyimpan atau memanggil IP Pod secara langsung; IP berubah setiap Pod dibuat ulang — selalu lewat nama Service.
- Lupa
kind load docker-imagesehingga Pod macet diErrImagePull/ImagePullBackOffdi cluster kind. - Lupa
-n <namespace>lalu bingung karenakubectl get podskosong (yang tampil namespacedefault). - Mengubah objek dengan
kubectl editlangsung di cluster; perubahan hilang saat manifest di Git di-apply ulang.
Ringkasan
- Kubernetes menjaga desired state lewat reconciliation: control plane (apiserver, etcd, scheduler, controller-manager) memutuskan,
kubeletdi tiap node menjalankan. - Pod bersifat sementara; Deployment → ReplicaSet → Pod mengatur jumlah replika, rolling update, dan rollback.
- Service memberi nama DNS dan IP stabil ke Pod yang cocok dengan selector;
ClusterIPuntuk internal,NodePort/LoadBalanceruntuk akses luar, Ingress/Gateway API untuk routing HTTP. - Namespace membagi cluster secara logis, bukan otomatis mengisolasi jaringan.
- Tulis manifest di Git,
kubectl apply, lalu debug denganget,describe,logs --previous,port-forward, danrollout.