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 →