Ingress & load balancing — L4 vs L7 vào cluster
So sánh ClusterIP, NodePort, LoadBalancer và Ingress: chiều traffic L4/L7, host/path, TLS termination, pitfall thiếu ingress controller.
TL;DR: ClusterIP chỉ trong cluster. NodePort mở port trên mọi node → kube-proxy forward vào Service. LoadBalancer (cloud/MetalLB…) cấp IP ngoài, thường bọc NodePort/ClusterIP. Ingress là API L7 (HTTP/HTTPS host/path) — không tự listen; cần Ingress controller (nginx, Traefik, cloud…) làm reverse proxy → Service backends. TLS thường terminate tại controller. Pitfall cứng: apply Ingress YAML xanh, 0 controller → không có data path; nhầm Ingress thay Service (vẫn cần Service); nhầm L4 LB với route Host header.
Demo sprint: junior kubectl apply -f ingress.yaml, kubectl get ingress ADDRESS trống hoặc localhost, curl -H "Host: api.example.com" http://… fail. Ticket: “Ingress K8s hỏng”. Bạn hỏi: “Cluster có IngressClass / controller pod chưa? Service backend type gì? TLS secret đúng namespace?” Nhiều lab kind chưa cài controller — object API có, dataplane không. Cùng class “API xanh / effect 0” như NetworkPolicy thiếu enforce CNI.
Bài 03 chốt VIP nội bộ. Bài này so sánh bốn cửa đưa traffic (đặc biệt từ ngoài) và L7 host/path/TLS.
Bài faded: bảng so sánh worked; bạn tự chọn expose type theo scenario, và tự điền chỗ TLS terminate trước khi đối chiếu.
1. Analogy — Cửa nội bộ, chuông tầng, cổng chính, lễ tân đọc phong bì
Tiếp số tổng đài ảo = ClusterIP:
- ClusterIP — chỉ máy trong toà quay số nội bộ.
- NodePort — mỗi tầng có chuông phụ cùng số (port 30000–32767); khách biết IP máy tầng + chuông vẫn vào được dịch vụ.
- LoadBalancer — cổng chính cloud/provider gắn một số ngoài; bên trong vẫn nối tổng đài/Service.
- Ingress — lễ tân đọc phong bì HTTP: “Host
api.shop.vnpath/v1→ quầy payment-api”; nhiều shop chung một cửa chính nhờ tên trên phong bì (L7), không cần mỗi shop một cổng L4.
| Đời thường | Kubernetes |
|---|---|
| Số nội bộ toà | ClusterIP |
| Chuông phụ mỗi tầng | NodePort |
| Cổng chính + số public | LoadBalancer Service |
| Lễ tân đọc Host/path | Ingress + controller |
| Quầy thật sau lễ tân | Service → pods (bài 03) |
Service types = L4 (TCP/UDP) expose. Ingress = L7 HTTP(S) routing — luôn ngồi trên Service, không thay Endpoints.
2. Bốn kiểu expose khác nhau chỗ nào?
2.1 So sánh theo chiều traffic
| ClusterIP | NodePort | LoadBalancer | Ingress | |
|---|---|---|---|---|
| Lớp | L4 VIP | L4 | L4 (+ cloud) | L7 HTTP/HTTPS (chủ đạo) |
| Ai gọi được | Trong cluster | Biết nodeIP:nodePort | Client Internet/LAN qua LB IP | Client qua IP/DNS controller/LB |
| Object | Service | Service type: NodePort | Service type: LoadBalancer | Ingress (+ controller) |
| Ổn định bên ngoài | Không (private CIDR) | nodeIP đổi/scale node | LB IP/hostname provider | DNS → controller/LB |
| Host/path route | Không | Không | Không (thuần L4) | Có |
| TLS | App/mesh tự lo | App tự lo | Thường app hoặc LB annot | Terminate tại controller phổ biến |
| Phụ thuộc | kube-proxy/dataplane | + mở port node | + cloud controller / MetalLB | + Ingress controller |
flowchart TB
EXT["External client"] --> NP["NodePort on nodeIP"]
EXT --> LB["LoadBalancer IP"]
EXT --> ING["Ingress controller HTTP"]
NP --> SVC["Service"]
LB --> SVC
ING --> SVC
SVC --> PODS["Pods via kube-proxy path"]
INT["In-cluster client"] --> CIP["ClusterIP only"]
CIP --> PODS2.2 ClusterIP — baseline (nhắc ngắn)
Đã mổ bài 03: VIP nội bộ, DNS, kube-proxy. Không thay thế cửa Internet. Mọi Ingress/NodePort/LB cuối vẫn thường kết vào Service ClusterIP (hoặc type khác) + Endpoints.
2.3 NodePort
apiVersion: v1
kind: Service
metadata:
name: payment-api
spec:
type: NodePort
selector:
app: payment
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # optional; else allocated from range
- kube-proxy mở cùng nodePort trên mọi node (model).
- Client:
http://<any-node-ip>:30080→ DNAT/path vào backend pod (có thể pod nằm node khác). - Ops: firewall security group phải mở nodePort; node IP thay khi ASG rotate — DNS/LB phía trước thường cần.
- Không an toàn hơn vì “port lạ”: vẫn TCP expose app L4.
2.4 LoadBalancer
spec:
type: LoadBalancer
# cloud assigns status.loadBalancer.ingress hostname/ip
- Trên cloud: cloud-controller tạo LB (NLB/CLB/…) trỏ node/NodePort hoặc mode tương đương.
- On-prem: MetalLB, kube-vip… hoặc LB thủ công — không có magic chỉ vì field
LoadBalancer. - Thường tạo kèm NodePort + ClusterIP (implementation detail — đọc
kubectl get svc -o yaml). - Một Service ≈ một (hoặc pool) frontend L4 — nhiều app HTTP → nhiều LB IP hoặc gộp bằng Ingress L7.
2.5 Ingress — API + controller
Ingress resource mô tả luật HTTP:
- host
api.example.com - path
/v2→ Servicepayment-api:80 - TLS secret
api-tlscho host đó
Ingress controller (Deployment/DaemonSet + thường Service LB/NodePort):
- Watch Ingress (+ IngressClass).
- Render config (nginx.conf, Envoy…) / program dataplane.
- Nhận traffic ngoài, proxy L7 tới Service ClusterIP.
Không controller = không ai đọc object (trừ khi provider gắn default — đừng assume).
3. L7 host/path routing hoạt động thế nào?
3.1 Vì sao cần L7?
L4 chỉ thấy IP:port. Nhiều site/API chung :443:
shop.example.com→ frontend Serviceapi.example.com→ API Serviceapi.example.com/v1/payments→ payment Service
Host header / SNI (TLS) + path = chìa L7.
3.2 Ví dụ luật (minh hoạ)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /v1/payments
pathType: Prefix
backend:
service:
name: payment-api
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: api-gateway
port:
number: 80
| Field | Ý nghĩa |
|---|---|
ingressClassName | Controller nào implement (tránh nhiều controller tranh) |
host | Khớp Host / SNI |
path + pathType | Prefix / Exact / ImplementationSpecific |
backend.service | Service đã có Endpoints (bài 03) |
tls.secretName | Secret kubernetes.io/tls trong cùng namespace (thường) |
flowchart LR
C["Client Host api.example.com"] --> CTRL["Ingress controller"]
CTRL -->|"/v1/payments"| PAY["Svc payment-api"]
CTRL -->|"/"| GW["Svc api-gateway"]
PAY --> P1["Pods"]
GW --> P2["Pods"]3.3 pathType — đừng đoán
Prefix:/v1khớp/v1,/v1/…(chi tiết trailing slash theo controller — test).Exact: khớp đúng path.ImplementationSpecific: phụ thuộc controller — đọc docs controller, không portable mù.
4. TLS terminate ở đâu trên đường Ingress?
4.1 Mô hình phổ biến
- Client TLS → controller (cert trong Secret).
- Controller terminate TLS, HTTP (hoặc TLS lại) tới Service/pod.
- App pod có thể chỉ HTTP nội bộ — giảm phân tán cert (trade-off trust network nội bộ).
TLS passthrough (controller không decrypt, SNI route) là mode khác — app terminate; không mặc định mọi Ingress.
4.2 Secret
kubectl create secret tls api-tls \
--cert=fullchain.pem --key=privkey.pem \
-n <ingress-namespace-or-app-ns>
Sai namespace / sai secretName / cert không cover host → browser lỗi cert, controller log warn — không phải “Service Endpoints trống” (khác class).
4.3 Faded — terminate ở đâu?
Scenario: app container chỉ listen plain :8080, Secret TLS gắn Ingress, curl -k https://api.example.com từ ngoài OK, kubectl exec vào pod ss không thấy :443.
TLS terminate ở object nào? Gói giữa controller → Service còn encrypt không (mô hình terminate edge mặc định)?
Đáp án kỳ vọng: Terminate tại Ingress controller. Nội bộ controller→Service thường HTTP plain (trừ mTLS/re-encrypt config). Pod không listen 443 là đúng với edge terminate.
5. Traffic ngoài vào pod đi qua những hop nào?
5.1 Path ngoài → pod (HTTP)
- DNS
api.example.com→ IP LoadBalancer của controller (hoặc node/NodePort lab). - TCP 443 → pod controller.
- TLS + Host/path match → chọn backend Service.
- Controller outbound tới ClusterIP:port (hoặc pod IP tùy mode) — từ đây path bài 03 (kube-proxy → pod).
- Response ngược chuỗi.
Hai lớp LB: cloud LB (L4) tới controller replicas + kube-proxy tới app pods. Debug phải biết đang soi layer nào.
5.2 Faded — chọn expose
Chọn một primary expose cho mỗi case (ClusterIP / NodePort / LoadBalancer / Ingress). Viết lý do một câu.
(A) Service payment chỉ gọi từ order-pod trong cluster.
(B) Lab kind, một API, không DNS đa host, dev curl nodeIP.
(C) Production cloud, 12 microservice HTTP, một domain, path split, TLS Let’s Encrypt.
(D) TCP database expose (không HTTP), client ngoài VPC.
Đáp án kỳ vọng:
- (A) ClusterIP — không cần cửa ngoài.
- (B) NodePort (hoặc LB nếu kind/metallb có) — đơn giản lab.
- (C) Ingress (+ thường LB trước controller) — L7 host/path/TLS gom.
- (D) LoadBalancer hoặc NodePort L4 — Ingress HTTP-centric không phải chỗ TCP DB mặc định (có TCP route controller riêng — ngoài nhập môn).
6. Pitfall — vì sao Ingress YAML xanh mà traffic chết?
6.1 Ingress without controller
| Quan sát | Ý nghĩa |
|---|---|
kubectl get ingress có rule | Chỉ etcd/API |
ADDRESS trống mãi | Không ai gán IP / chưa controller |
| Controller pod CrashLoop | Dataplane chết |
Sai ingressClassName | Controller khác (hoặc không ai) nhận |
Verify controller:
kubectl get pods -A | grep -i ingress
kubectl get ingressclass
kubectl describe ingress shop
6.2 Nhầm Ingress với Service
- Ingress không thay Endpoints/kube-proxy.
- Backend phải là Service khỏe (bài 03 checklist).
curltrúng controller nhưng 502/503 → hay backend Service/endpoints/app — không phải “DNS domain sai” một mình.
6.3 NodePort “giấu” app
Port 3xxxx vẫn public nếu SG mở. Không thay authn. Không thay NetworkPolicy.
6.4 Một LB IP, nhiều host — kỳ vọng đúng
L4 LB một IP vẫn phục vụ nhiều Host nhờ Ingress L7. Đòi “mỗi Service một LB IP” khi đã có Ingress thường lãng phí — trừ isolation/compliance.
flowchart TD
FAIL["External HTTP fail"] --> Q1{"Controller running + IngressClass?"}
Q1 -->|No| C1["Install or fix controller"]
Q1 -->|Yes| Q2{"DNS or LB IP hits controller?"}
Q2 -->|No| C2["DNS SG NodePort LB"]
Q2 -->|Yes| Q3{"Host path TLS match?"}
Q3 -->|No| C3["Fix Ingress rules secrets"]
Q3 -->|Yes| Q4{"Service Endpoints ready?"}
Q4 -->|No| C4["Debug Service like lesson 03"]
Q4 -->|Yes| C5["App logs in pod"]📚 Deep Dive — tài liệu gốc
Spec / docs:
- Ingress — rules, TLS, IngressClass.
- Ingress controllers — bắt buộc controller.
- Service — NodePort, LoadBalancer types.
- Connecting applications — expose patterns.
Nội bộ OLHub:
- 03 — Service & kube-proxy — backend VIP path.
- 01 — Pod networking — đích cuối pod IP.
- M2 — DNAT publish — họ L4 “cửa host”.
- 05 — NetworkPolicy — hạn chế ai nói chuyện sau khi đã vào cluster.
Liên hệ các bài khác
- 03 — Service & kube-proxy — mọi cửa ngoài hạ xuống Service/Endpoints.
- 01 — Pod networking / 02 — CNI — path sau proxy tới pod.
- 05 — NetworkPolicy — micro-segment; Ingress không thay zero-trust east-west.
- M2 — Publish port DNAT — NodePort họ “chuông host”.
- 00 — Tổng quan M3 — Ingress trên pipeline capstone.
Tóm tắt
- ClusterIP nội bộ; NodePort L4 mọi node; LoadBalancer IP ngoài provider; Ingress L7 qua controller.
- Route Host/path; TLS thường terminate tại controller + Secret.
- Ingress YAML không đủ — thiếu controller = không dataplane.
- Debug ngoài→trong: DNS/LB → controller → rule/TLS → Service/Endpoints → app (tách lớp).
7. Tự kiểm tra
Q1So sánh ClusterIP, NodePort, LoadBalancer, Ingress theo: ai reach được, L4 hay L7, object Kubernetes chính. Client trong cluster gọi API nội bộ — type tối thiểu nào?▸
Q2Vì sao 'kubectl get ingress' có resource chưa chứng minh traffic HTTP vào được? Liệt kê dependency dataplane.▸
Q3Trace external HTTPS → pod qua Ingress: các hop (DNS, LB, controller, Service, kube-proxy, pod). TLS terminate điển hình ở hop nào?▸
Q4Khi nào chọn NodePort thay Ingress? Khi nào Ingress thắng nhiều LoadBalancer Service riêng cho từng HTTP app?▸
Q5pathType Prefix vs Exact — junior path /api khớp /api/v2 không? Vì sao ImplementationSpecific nguy hiểm khi đổi controller?▸
Q6502 từ Ingress controller, Service ClusterIP curl từ pod debug OK. Class lỗi nghi đâu? Ngược lại curl ClusterIP fail — nghi đâu trước controller?▸
Q7LoadBalancer Service trên bare-metal không cloud controller — external IP pending mãi. Root cause class gì? Hướng fix khái niệm (không cần tên hãng cụ thể)?▸
Bài tiếp theo: NetworkPolicy — chặn east-west có chủ đích
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên