Kubernetes
Perintah kubectl sehari-hari dan referensi manifest YAML untuk Pod, Deployment, Service, Ingress, ConfigMap, Secret, dan HPA. Fokus pada operasi produksi dan troubleshooting.
00
kubectl — Perintah Dasar
Perintah yang paling sering dipakai untuk berinteraksi dengan cluster.
Get — melihat resource
shell
kubectl get pods # daftar pod di namespace saat ini kubectl get pods -n kube-system # namespace tertentu kubectl get pods -A # semua namespace kubectl get pods -o wide # tampilkan node, IP, dll. kubectl get pods -w # watch — update otomatis kubectl get pods -l app=api # filter by label kubectl get all # pod, svc, deployment, rs di namespace ini kubectl get pod/api-7d9f5 -o yaml # output YAML lengkap
Describe — detail dan event
describe menampilkan Events di bagian bawah — sangat berguna untuk debug pod yang tidak mau start.shell
kubectl describe pod api-7d9f5 kubectl describe deployment api kubectl describe node worker-1 kubectl describe svc api-svc
Apply dan Delete
shell
kubectl apply -f deployment.yaml # buat atau update resource dari file kubectl apply -f ./manifests/ # semua file dalam direktori kubectl apply -k ./overlays/prod/ # kustomize overlay kubectl delete -f deployment.yaml # hapus resource dari file kubectl delete pod api-7d9f5 # hapus pod (akan dibuat ulang oleh deployment) kubectl delete pod api-7d9f5 --grace-period=0 --force # hapus paksa
Exec dan logs
shell
# Logs kubectl logs api-7d9f5 # log pod kubectl logs api-7d9f5 -f # follow kubectl logs api-7d9f5 --tail=100 # 100 baris terakhir kubectl logs api-7d9f5 -c sidecar # container tertentu (jika multi-container) kubectl logs -l app=api --all-containers # semua pod dengan label app=api # Exec kubectl exec -it api-7d9f5 -- bash # shell interaktif kubectl exec -it api-7d9f5 -- sh # untuk alpine kubectl exec api-7d9f5 -- cat /etc/hosts
Port forward
port-forward berguna untuk testing lokal tanpa expose service. Tidak untuk produksi.shell
kubectl port-forward pod/api-7d9f5 8080:3000 # localhost:8080 → pod:3000 kubectl port-forward svc/api-svc 8080:80 # via service kubectl port-forward deployment/api 8080:3000 # via deployment
Context dan namespace
shell
kubectl config get-contexts # daftar context (cluster) kubectl config current-context # context aktif kubectl config use-context prod-cluster # pindah cluster kubectl config set-context --current --namespace=staging # ganti namespace default kubectl get pods -n staging # atau flag -n per perintah
01
Pod
Unit terkecil yang bisa di-deploy di Kubernetes. Biasanya dikelola lewat Deployment.
Manifest Pod dasar
yaml
apiVersion: v1
kind: Pod
metadata:
name: api
namespace: default
labels:
app: api
version: "1.0"
spec:
containers:
- name: api
image: registry.example.com/api:1.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: production
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
restartPolicy: AlwaysInit container
Init container berjalan sampai selesai sebelum container utama dimulai. Berguna untuk migrasi DB, tunggu service lain, dll.
yaml
spec:
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nc -z db-svc 5432; do echo waiting; sleep 2; done']
containers:
- name: api
image: api:1.002
Deployment
Mengelola replikasi dan rolling update pod.
Manifest Deployment
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: production
labels:
app: api
spec:
replicas: 3
selector:
matchLabels:
app: api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # pod ekstra boleh jalan saat update
maxUnavailable: 0 # tidak boleh ada pod down saat update
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: registry.example.com/api:1.2.0
ports:
- containerPort: 3000
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"Perintah Deployment
shell
# Scale kubectl scale deployment api --replicas=5 # Update image (trigger rolling update) kubectl set image deployment/api api=registry.example.com/api:1.3.0 # Status rollout kubectl rollout status deployment/api kubectl rollout history deployment/api # Rollback kubectl rollout undo deployment/api # ke versi sebelumnya kubectl rollout undo deployment/api --to-revision=2 # ke revisi tertentu # Pause dan resume rolling update kubectl rollout pause deployment/api kubectl rollout resume deployment/api
03
Service
Expose pod ke jaringan internal cluster atau ke luar.
Jenis-jenis Service
ClusterIP (default) — hanya dalam cluster. NodePort — expose ke port node. LoadBalancer — cloud load balancer. ExternalName — CNAME ke DNS eksternal.
yaml
# ClusterIP — komunikasi internal antar pod
apiVersion: v1
kind: Service
metadata:
name: api-svc
spec:
selector:
app: api # target pod dengan label app=api
ports:
- protocol: TCP
port: 80 # port service (internal cluster)
targetPort: 3000 # port container
type: ClusterIP
---
# NodePort — akses via IP node:port
apiVersion: v1
kind: Service
metadata:
name: api-nodeport
spec:
selector:
app: api
ports:
- port: 80
targetPort: 3000
nodePort: 30080 # range 30000-32767
type: NodePort
---
# LoadBalancer — cloud provider
apiVersion: v1
kind: Service
metadata:
name: api-lb
spec:
selector:
app: api
ports:
- port: 80
targetPort: 3000
type: LoadBalancerHeadless service (StatefulSet / discovery)
yaml
apiVersion: v1
kind: Service
metadata:
name: db-headless
spec:
clusterIP: None # headless — DNS mengembalikan IP pod langsung
selector:
app: db
ports:
- port: 543204
Ingress
Routing HTTP/HTTPS dari luar cluster ke service internal.
Manifest Ingress
Membutuhkan Ingress Controller yang terinstall (NGINX Ingress, Traefik, dll.). Annotations berbeda per controller.
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls # cert-manager mengisi secret ini
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 80
- path: /admin
pathType: Prefix
backend:
service:
name: admin-svc
port:
number: 8005
ConfigMap & Secret
Memisahkan konfigurasi dan kredensial dari image.
ConfigMap
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
data:
NODE_ENV: production
LOG_LEVEL: info
config.yaml: | # file config lengkap
server:
port: 3000
database:
pool_size: 10yaml
# Cara pakai di Pod:
spec:
containers:
- name: api
envFrom:
- configMapRef:
name: api-config # semua key jadi env var
volumeMounts:
- name: config-vol
mountPath: /app/config
volumes:
- name: config-vol
configMap:
name: api-config # mount sebagai fileSecret
Secret di-encode base64, bukan dienkripsi. Aktifkan Encryption at Rest di kube-apiserver untuk keamanan sesungguhnya, atau gunakan Vault / External Secrets Operator.
yaml
apiVersion: v1 kind: Secret metadata: name: db-secret type: Opaque stringData: # gunakan stringData agar tidak perlu encode manual DB_PASSWORD: supersecret DB_URL: postgres://user:supersecret@db:5432/mydb
shell
# Buat secret dari command line kubectl create secret generic db-secret --from-literal=DB_PASSWORD=supersecret --from-file=tls.crt=./server.crt --from-file=tls.key=./server.key # Secret TLS kubectl create secret tls api-tls --cert=./fullchain.pem --key=./privkey.pem
06
Namespace
Isolasi resource dalam satu cluster.
Mengelola namespace
shell
kubectl get namespaces kubectl create namespace staging kubectl delete namespace staging # Ganti namespace default untuk session ini kubectl config set-context --current --namespace=staging
ResourceQuota per namespace
yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: staging-quota
namespace: staging
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"LimitRange — default resource per pod
yaml
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: staging
spec:
limits:
- type: Container
default:
cpu: "200m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"07
Scaling & HPA
Skala manual dan otomatis berdasarkan metrics.
Manual scale
shell
kubectl scale deployment api --replicas=10 kubectl scale deployment api --replicas=0 # matikan semua pod sementara
Horizontal Pod Autoscaler (HPA)
Membutuhkan Metrics Server terinstall di cluster (
kubectl top pods harus bisa jalan).yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # scale up jika CPU rata-rata > 70%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80shell
# Buat HPA via command line kubectl autoscale deployment api --min=2 --max=10 --cpu-percent=70 kubectl get hpa kubectl describe hpa api-hpa
08
Storage — PV & PVC
Persistensi data untuk stateful workload.
PersistentVolumeClaim
Di cloud provider (GKE, EKS, AKS), PV dibuat otomatis dari StorageClass. On-premise biasanya perlu provisioner seperti Longhorn atau NFS.
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-pvc
spec:
accessModes:
- ReadWriteOnce # RWO: satu node | RWX: banyak node | ROX: banyak node read-only
resources:
requests:
storage: 10Gi
storageClassName: fast-ssd # kosongkan untuk pakai default StorageClassyaml
# Pakai PVC di Pod
spec:
containers:
- name: db
image: postgres:16
volumeMounts:
- name: db-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: db-storage
persistentVolumeClaim:
claimName: db-pvc09
Debugging & Troubleshooting
Pod tidak mau start — diagnosis cepat
shell
# Lihat status dan reason
kubectl get pod api-7d9f5
kubectl describe pod api-7d9f5 # cek bagian Events di bawah
# Lihat log (termasuk container sebelumnya jika crash loop)
kubectl logs api-7d9f5
kubectl logs api-7d9f5 --previous # log container sebelum crash
# Cek exit code
kubectl get pod api-7d9f5 -o jsonpath='{.status.containerStatuses[0].state}'Status pod — arti common state
info
Pending — Pod diterima tapi belum scheduled (cek resource/taint/affinity) ImagePullBackOff — Gagal pull image (cek nama/tag image, secret registry) CrashLoopBackOff — Container terus crash (cek log --previous) OOMKilled — Container dibunuh karena melebihi memory limit Terminating — Pod sedang dihapus (mungkin stuck finalizer) Evicted — Diusir karena node kehabisan resource
Debug dengan ephemeral container
Berguna untuk debug pod yang menggunakan distroless image (tidak ada shell). Kubernetes 1.23+.
shell
kubectl debug -it api-7d9f5 --image=nicolaka/netshoot --target=api -- bash
Resource usage
shell
kubectl top pods # CPU dan memory semua pod kubectl top pods -l app=api # filter by label kubectl top nodes # resource per node
Network debug
shell
# Jalankan pod debug sementara kubectl run netdebug --rm -it --image=nicolaka/netshoot -- bash # Di dalam pod debug: # nslookup api-svc.production.svc.cluster.local # curl http://api-svc.production.svc.cluster.local/health # wget -qO- http://api-svc/health
Cek event cluster
shell
kubectl get events --sort-by='.lastTimestamp' # semua event kubectl get events -n production --sort-by='.lastTimestamp' kubectl get events --field-selector reason=BackOff # filter reason
Dry-run dan diff
shell
# Lihat apa yang akan berubah sebelum apply kubectl diff -f deployment.yaml # Dry-run — validasi tanpa apply ke cluster kubectl apply -f deployment.yaml --dry-run=server kubectl apply -f deployment.yaml --dry-run=client # tanpa koneksi ke API server
10
Tips Manifest & kubectl
Generate manifest dari perintah
Gunakan
--dry-run=client -o yaml untuk menghasilkan skeleton manifest yang bisa diedit.shell
kubectl create deployment api --image=api:1.0 --replicas=3 --dry-run=client -o yaml > deployment.yaml kubectl create service clusterip api-svc --tcp=80:3000 --dry-run=client -o yaml > service.yaml kubectl create configmap api-config --from-literal=NODE_ENV=production --dry-run=client -o yaml > configmap.yaml kubectl create secret generic db-secret --from-literal=password=secret --dry-run=client -o yaml > secret.yaml
JSONPath dan custom columns
shell
# Ambil field spesifik
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
kubectl get pod api-7d9f5 -o jsonpath='{.status.podIP}'
# Custom columns
kubectl get pods -o custom-columns='NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName'Label dan annotasi
shell
kubectl label pod api-7d9f5 env=production kubectl label pod api-7d9f5 env- # hapus label (suffix -) kubectl annotate deployment api kubernetes.io/change-cause="update ke v1.3.0" # dicatat di rollout history