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

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

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: Always

Init container

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.0
02

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

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: LoadBalancer

Headless 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: 5432
04

Ingress

Routing HTTP/HTTPS dari luar cluster ke service internal.

Manifest Ingress

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: 80
05

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: 10
yaml
# 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 file

Secret

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)

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: 80
shell
# 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

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 StorageClass
yaml
# 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-pvc
09

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

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

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