Anti-Pattern Networking #

Networking Kubernetes punya banyak detail yang mudah salah — terutama bagi yang baru migrasi dari arsitektur monolith atau VM tradisional. Kesalahan networking sering tidak langsung terlihat: service berjalan dengan baik di development tapi gagal di produksi, atau berjalan normal sampai traffic meningkat tiba-tiba. Artikel ini mengkompilasi anti-pattern yang paling sering ditemui agar kamu bisa menghindarinya sejak awal.

Anti-Pattern 1: Hardcode IP Pod #

# ANTI-PATTERN: hardcode IP Pod dalam kode atau konfigurasi
DATABASE_HOST = "10.244.1.5"   # IP Pod database

# atau dalam environment variable:
# DB_HOST=10.244.1.5
Konsekuensi:
  Pod database restart → IP berubah jadi 10.244.2.8
  Aplikasi masih coba hubungi 10.244.1.5 → Connection refused
  Service mati

  Untuk setiap Pod baru yang dibuat (rolling update, scaling):
  → IP berbeda → semua config yang hardcode IP rusak
# BENAR: gunakan Service DNS name
DATABASE_HOST = "postgres-service.production.svc.cluster.local"
# atau untuk namespace yang sama:
DATABASE_HOST = "postgres-service"

Anti-Pattern 2: Satu LoadBalancer per Service #

# ANTI-PATTERN: expose setiap microservice dengan LoadBalancer terpisah

# 20 microservice = 20 manifest seperti ini:
apiVersion: v1
kind: Service
spec:
  type: LoadBalancer   # ← setiap service = satu cloud load balancer
  selector:
    app: user-service
---
apiVersion: v1
kind: Service
spec:
  type: LoadBalancer
  selector:
    app: order-service
# ... dan seterusnya untuk 18 service lainnya
Konsekuensi:
  20 LoadBalancer Service = 20 cloud load balancer = biaya signifikan
  Setiap load balancer punya IP publik tersendiri → sulit dikelola
  TLS certificate perlu di-manage per load balancer
# BENAR: gunakan Ingress untuk routing ke banyak Service
apiVersion: networking.k8s.io/v1
kind: Ingress
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /users
        backend:
          service:
            name: user-service
      - path: /orders
        backend:
          service:
            name: order-service
  # Satu Ingress = satu LoadBalancer = jauh lebih hemat

Anti-Pattern 3: Tidak Ada Health Check Sebelum Service Aktif #

# ANTI-PATTERN: Pod langsung masuk Endpoints tanpa readiness check

spec:
  containers:
  - name: api
    image: my-api:v2
    # Tidak ada readinessProbe
    # Pod langsung masuk Endpoints Service begitu berjalan
Konsekuensi:
  Pod baru dimulai (butuh 10 detik untuk init)
  Kubernetes langsung masukkan ke Endpoints Service
  Traffic mulai dikirim ke Pod yang belum siap
  → 503 errors, connection refused, request timeout
  → Terjadi di setiap rolling update
# BENAR: readinessProbe wajib sebelum Pod masuk Endpoints
spec:
  containers:
  - name: api
    image: my-api:v2
    readinessProbe:
      httpGet:
        path: /health/ready
        port: 8080
      initialDelaySeconds: 10    # tunggu 10 detik sebelum mulai probe
      periodSeconds: 5
      failureThreshold: 3        # remove dari Endpoints setelah 3 kali gagal

Anti-Pattern 4: NodePort untuk Production Internet-Facing #

# ANTI-PATTERN: expose service produksi via NodePort langsung
spec:
  type: NodePort
  ports:
  - nodePort: 30080   # ← semua node expose port ini
Konsekuensi:
  Port 30080 terbuka di SEMUA node → attack surface besar
  Client harus tahu IP node → tidak ada abstraksi
  Jika node down, client harus switch ke IP node lain secara manual
  Tidak ada TLS termination built-in
  Port range terbatas (30000-32767) → tidak bisa pakai port 80/443
BENAR untuk internet-facing:
  → Gunakan Ingress dengan LoadBalancer Service di Ingress Controller
  → Atau LoadBalancer Service langsung (untuk service tunggal)
  → TLS termination di Ingress

NodePort masih valid untuk:
  ✓ Development/testing di lokal
  ✓ On-premise dengan external load balancer di depan
  ✓ Integrasi dengan MetalLB atau similar

Anti-Pattern 5: Default-Deny NetworkPolicy tanpa Izinkan DNS #

# ANTI-PATTERN: default-deny tanpa exception DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Egress
  # Tidak ada egress rules = semua egress ditolak termasuk DNS
Konsekuensi:
  Semua DNS query dari Pod di namespace ini gagal
  Aplikasi tidak bisa resolve nama service apapun
  Semua HTTP request ke service lain gagal dengan "connection refused"
  atau "no such host"

  Developer bingung: "Saya sudah buka port ke database, kenapa masih gagal?"
  (karena DNS tidak bisa resolve nama database)
# BENAR: selalu sertakan DNS exception
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  # WAJIB: izinkan DNS
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP
  # Tambahkan rules lain sesuai kebutuhan

Anti-Pattern 6: Service Selector yang Terlalu Luas #

# ANTI-PATTERN: selector hanya berdasarkan satu label umum
spec:
  selector:
    tier: backend   # ← semua Pod berlabel tier=backend akan masuk Service ini
Konsekuensi:
  Service A dengan selector tier=backend
  Service B juga dengan selector tier=backend
  
  Saat deploy service baru dengan label tier=backend:
  → Service A dan B keduanya me-route traffic ke Pod baru
  → Mungkin traffic ke Pod yang salah

  Atau:
  Service "api-service" dengan selector tier=backend
  Database Pod juga punya label tier=backend
  → Database masuk ke Endpoints api-service
  → Traffic mungkin dikirim ke database
# BENAR: selector yang spesifik dan unik
spec:
  selector:
    app: api-server          # spesifik ke aplikasi ini
    component: api           # untuk membedakan dari komponen lain dalam app
    # atau gunakan app.kubernetes.io/name standard labels

Anti-Pattern 7: Tidak Ada Timeout di Service-to-Service Call #

# ANTI-PATTERN: HTTP call tanpa timeout
response = requests.get("http://downstream-service/api/data")
# Jika downstream-service lambat atau tidak responsif,
# thread ini akan hang selamanya
Konsekuensi:
  Downstream service lambat → upstream service tunggu tanpa batas
  Thread pool upstream habis → upstream tidak bisa terima request baru
  → Cascading failure: satu service lambat membuat seluruh chain gagal
  → Di Kubernetes, ini sering terlihat sebagai request yang timeout
    di sisi client tapi Pod terlihat "Running" dan "Ready"
# BENAR: selalu set timeout yang eksplisit
response = requests.get(
    "http://downstream-service/api/data",
    timeout=(3.05, 30)   # (connect timeout, read timeout)
)

# Dan implementasikan circuit breaker untuk resilience lebih baik
# (via library seperti tenacity, pybreaker, atau via service mesh)

Ringkasan #

  • Jangan hardcode IP Pod — gunakan Service DNS name; IP Pod berubah setiap kali Pod restart atau update; DNS name stabil selama Service ada.
  • Satu Ingress untuk banyak Service — bukan satu LoadBalancer per service; Ingress jauh lebih hemat biaya dan lebih mudah dikelola untuk banyak service.
  • readinessProbe wajib sebelum terima traffic — tanpa readiness probe, Pod baru masuk Endpoints sebelum siap dan menyebabkan error saat rolling update.
  • Default-deny egress harus sertakan DNS exception — lupa membuka port 53 adalah penyebab paling umum “aplikasi tidak bisa connect ke apapun” setelah NetworkPolicy diterapkan.
  • Selector Service harus spesifik — selector yang terlalu luas bisa memasukkan Pod yang salah ke Service; gunakan kombinasi label yang unik untuk setiap service.
  • Selalu set timeout di service-to-service call — tanpa timeout, satu service lambat bisa menyebabkan cascading failure yang mematikan seluruh chain service.

← Sebelumnya: Network Troubleshooting   Berikutnya: ConfigMap →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact