Sau bài này bạn làm được: đọc diagram mạng K8s và biết traffic đi qua đâu; chọn đúng Service type cho từng tình huống; debug “trong Pod không resolve được tên service” bằng đúng lệnh.
Ba quy tắc nền tảng của mạng K8s
Kubernetes yêu cầu:
- Mỗi Pod có IP duy nhất trong cluster (không NAT giữa Pod với Pod).
- Pod trên bất kỳ node nào cũng reach được Pod trên node khác qua Pod IP — không cần port mapping.
- Service ClusterIP cung cấp VIP ổn định trước Pool Pod.
Các CNI (Calico, Cilium, AWS VPC CNI, Flannel…) thực thi ba quy tắc này theo cách khác nhau — bạn cần biết hành vi, không cần nhớ implementation cụ thể.
Xu hướng 2025: CNI dựa trên eBPF (Cilium, Calico eBPF mode) thay thế dần kube-proxy/iptables:
- Load balancer Service xử lý trong kernel bằng XDP/tc → latency thấp hơn, scale tốt hơn ở quy mô hàng nghìn Service.
- Network policy enforce tại từng syscall, hỗ trợ L7 (HTTP method, gRPC service) mà NetworkPolicy tiêu chuẩn không làm được.
- Observability ra trực tiếp từ kernel (Hubble, Pixie) — không cần sidecar.
Nếu cluster dùng Cilium, có thể bật kubeProxyReplacement=true để bỏ hoàn toàn kube-proxy và iptables rule “Service chain” dài hàng nghìn dòng.
Kiến trúc network tổng quan
[Internet / User]
│
▼
[LoadBalancer / NodePort] ← Service type LoadBalancer hoặc NodePort
│
▼
[Ingress Controller (nginx, traefik…)] ← HTTP routing theo host/path
│
▼
[Service ClusterIP] ← VIP ổn định, DNS: my-svc.my-ns.svc.cluster.local
│ kube-proxy / eBPF forward tới Pod thực sự
▼
[Pod 1] [Pod 2] [Pod 3] ← thực tế xử lý request
10.244.0.2 10.244.1.3 10.244.2.4
Pod network (CNI)
# Xem IP của Pod
kubectl get pod my-pod -o wide
# NAME READY STATUS IP NODE
# my-pod 1/1 Running 10.244.1.15 node-2
# Ping từ Pod khác (nếu NetworkPolicy cho phép)
kubectl exec -it debug-pod -- ping 10.244.1.15
# Xem interface trong Pod
kubectl exec -it my-pod -- ip addr
kubectl exec -it my-pod -- ip route
Node có Pod CIDR riêng — CNI quản lý route giữa các node để Pod cross-node reach nhau.
Service — điểm vào ổn định
Pod IP thay đổi khi Pod restart. Service cung cấp:
- VIP (ClusterIP) không đổi.
- DNS name ổn định:
<service-name>.<namespace>.svc.cluster.local. - Load balance qua nhiều Pod (round-robin mặc định, tuỳ kube-proxy mode).
Các loại Service
| Type | Truy cập từ | Dùng khi |
|---|---|---|
| ClusterIP | Trong cluster | Service nội bộ (mặc định) |
| NodePort | Ngoài cluster qua NodeIP:NodePort (30000–32767) | Test, bare metal không có cloud LB |
| LoadBalancer | Ngoài cluster qua IP của cloud LB | Production trên cloud |
| ExternalName | DNS alias tới external host | Dùng tên K8s cho service bên ngoài |
# ClusterIP (mặc định)
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api
ports:
- port: 80 # cổng Service
targetPort: 8080 # cổng trên Pod
Ingress — HTTP routing ở tầng 7
Service chỉ làm L4 (TCP/UDP). Ingress thêm routing HTTP theo host và path:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-api
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service: { name: api-v1, port: { number: 80 } }
- path: /v2
pathType: Prefix
backend:
service: { name: api-v2, port: { number: 80 } }
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service: { name: admin, port: { number: 80 } }
pathType bắt buộc từ networking.k8s.io/v1 — bỏ qua sẽ bị API server từ chối. Ba giá trị:
Exact: khớp chính xác path.Prefix: khớp tiền tố theo từng segment (/v1khớp/v1/users, không khớp/v10).ImplementationSpecific: trả về cho controller tự diễn giải (ít dùng, giảm portability).
Ingress cần Ingress Controller cài sẵn (không có sẵn trong K8s vanilla). Phổ biến: NGINX Ingress Controller, Traefik, AWS ALB Ingress Controller.
Gateway API — thế hệ thay thế Ingress
Từ K8s 1.29 (2023) trở đi, Gateway API đã GA và là hướng phát triển chính thay cho Ingress. Điểm khác biệt:
- Phân tách role:
GatewayClass(nhà cung cấp),Gateway(infra),HTTPRoute/GRPCRoute/TCPRoute(dev định nghĩa). - Hỗ trợ gRPC, TCP, UDP, traffic split theo weight native, header-based routing.
- Mô hình extension rõ hơn, giảm dùng annotation vendor-specific.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
spec:
parentRefs:
- name: public-gateway
hostnames: ["api.example.com"]
rules:
- matches:
- path: { type: PathPrefix, value: /v1 }
backendRefs:
- name: api-v1
port: 80
weight: 90
- name: api-v1-canary
port: 80
weight: 10
Ingress vẫn tiếp tục được hỗ trợ, nhưng tính năng mới gần như chỉ được bổ sung cho Gateway API. Team đang thiết kế mới nên chọn Gateway API khi controller (Envoy Gateway, Istio, Contour, NGINX Gateway Fabric, Cilium) đã sẵn sàng.
# Xem Ingress đã tạo
kubectl get ingress -A
# Xem log Ingress Controller để debug
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller -f
CoreDNS — DNS trong cluster
# Trong Pod: /etc/resolv.conf
nameserver 10.96.0.10 # ClusterIP của kube-dns Service
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
Resolve tên service từ trong Pod:
# Tên ngắn (cùng namespace)
nslookup my-api
# Tên đầy đủ
nslookup my-api.default.svc.cluster.local
# Tên từ namespace khác
nslookup my-api.other-ns.svc.cluster.local
Debug DNS trong cluster:
# Chạy pod debug có đủ công cụ DNS + HTTP (khuyến nghị 2025)
kubectl run dnstest --image=ghcr.io/nicolaka/netshoot --rm -it --restart=Never -- bash
# Trong pod:
dig +search kubernetes.default
dig my-service.my-namespace.svc.cluster.local
nslookup my-service
Vì sao không nên dùng
busybox:1.28nữa? Bản cũ này có bugnslookuptrả sai dạng khi dùng search domain — từng phổ biến trong docs cũ.netshoothoặcregistry.k8s.io/e2e-test-images/agnhostcó bộ công cụ (dig,curl,ss,tcpdump) đầy đủ hơn.
ndots:5: nếu tên có < 5 dấu chấm, resolver thêm search domain trước khi query public DNS — có thể làm chậm external lookup. Cân nhắc giảm nếu có nhiều external DNS lookup trong app.
NetworkPolicy — firewall ở tầng Pod
Mặc định K8s cho phép tất cả Pod-to-Pod communication. NetworkPolicy thêm “whitelist”:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-from-frontend
spec:
podSelector:
matchLabels:
app: api
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 8080
Lưu ý debug: NetworkPolicy vi phạm thường cho timeout (DROP), không phải connection refused rõ ràng.
# Test từ Pod A tới Pod B
kubectl exec -it frontend-pod -- nc -vz api-pod-ip 8080
# Connection refused → Service/cổng sai
# Timeout → NetworkPolicy DROP hoặc routing sai
Tóm tắt
- Pod IP ephemeral; Service ClusterIP ổn định — luôn dùng Service để liên lạc.
- Ingress là L7 reverse proxy trong cluster — cần Controller đi kèm.
- CoreDNS là resolver nội bộ; test DNS trong Pod, không phải trên node.
- NetworkPolicy DROP → timeout; kiểm tra bằng
nctừ đúng Pod nguồn.
Câu hỏi hay gặp
Cùng my-service nhưng other-ns không resolve — sửa thế nào?
Trả lời: Tên ngắn chỉ resolve trong cùng namespace. Sang namespace khác cần my-service.other-ns.svc.cluster.local (hoặc FQDN tương đương).
NetworkPolicy deny-all ingress xong không ai vào được — làm sao cho Prometheus scrape được?
Trả lời: Thêm rule ingress cho phép traffic từ namespace monitoring (label namespaceSelector / podSelector) tới port 9090 của Pod target — deny-all chỉ để lại đúng luồng cần thiết.
Service type LoadBalancer trên cloud tạo gì? Luồng traffic?
Trả lời: Cloud controller tạo load balancer (ALB/NLB/ELB tùy annotation), gán VIP/DNS; traffic: Internet → LB → Node/Service → kube-proxy/CNI → Pod.
Bài tiếp theo (Giai đoạn III - nâng cao): Service mesh và mTLS — khi cần kiểm soát traffic east-west phức tạp hơn NetworkPolicy.
Hoặc chuyển sang Giai đoạn IV: VPC và mạng trên cloud — thiết kế hạ tầng mạng ở tầng cloud provider.