Một vấn đề khá đơn giản mà có thể có bạn chưa để ý là khi làm việc với Kubernetes là có nhiều team chấp nhận các config network mặc định mà chưa đặt câu hỏi “Sửa chỗ nào để tốt hơn nhể?”. Với những hạ tầng phức tạp việc mặc định cho Kubernetes xử lý hết phần networking là khá chưa ổn.
Thì trong bài này tôi chia sẻ một chút kinh nghiệm về phần này cho bác nào mới chưa biết nhé.

Kubernetes đúng là cung cấp các abstraction mạnh mẽ. Nhưng bên dưới những abstraction đó là: là IP, là NAT, là DNS, là định tuyến, và quan trọng nhất, là kiểm soát truy cập. Mọi người có thực sự biết một Pod ở namespace A làm thế nào để nói chuyện với Pod ở namespace B không? Và đáng lo hơn, mọi người có biết làm thế nào để cấm chúng nói chuyện với nhau không?
Container Network Interface (CNI)
Điều đầu tiên cần nắm là Kubernetes không tự triển khai network stack. Nó hoàn toàn dựa vào một plugin bên thứ ba tuân theo chuẩn Container Network Interface (CNI).
Khi cài cluster, bạn chọn Calico, Cilium, Flannel, hay Weave Net… đó chính là CNI plugin. Lựa chọn này sẽ quyết định 3 vấn đề:
- Pod IP được cấp phát như thế nào (IP Address Management).
- Routing giữa các Node được thiết lập ra sao.
- Và quan trọng nhất: cluster có hỗ trợ NetworkPolicy API hay không.
Đừng chọn CNI chỉ vì nó phổ biến hoặc dễ cài.
- Flannel: rất đơn giản. Nó triển khai một mạng overlay (thường là VXLAN hoặc host-gw) để đóng gói gói tin Pod gửi qua lại giữa các Node. Ưu điểm: dễ cài, nhược điểm: hiệu năng kém hơn và không hỗ trợ NetworkPolicy.
- Calico hoặc Cilium: phức tạp hơn nhưng mạnh mẽ hơn. Chúng có thể dùng direct routing qua BGP hoặc eBPF thay cho overlay, cho hiệu năng cao. Và cả hai đều hỗ trợ NetworkPolicy. Đặc biệt Cilium tận dụng eBPF để kiểm soát lưu lượng ở mức kernel.
Lựa chọn CNI là một quyết định kiến trúc. Nếu cần bảo mật và micro-segmentation, hãy chọn CNI có hỗ trợ NetworkPolicy. Nếu chỉ cần lab cơ bản cho môi trường dev, Flannel có thể đủ.
IP Addressing
Trong Kubernetes có 3 loại IP chính cần phân biệt:
- Node IP: IP thật của Node (máy chủ vật lý/VM).
- Pod IP: IP mà CNI cấp cho mỗi Pod (là địa chỉ thực).
- ClusterIP (Service IP): IP ảo do kube-proxy quản lý.
Điều quan trọng: không để trùng CIDR giữa Pod/Service và hạ tầng underlying (ví dụ subnet VPC trên cloud).
Khi kube-controller-manager khởi động, nó phân bổ một Pod CIDR cho mỗi Node từ dải --cluster-cidr
.
# Ví dụ trong kube-controller-manager
--cluster-cidr=10.244.0.0/16
--node-cidr-mask-size=24
# Node 1: 10.244.0.0/24, Node 2: 10.244.1.0/24...
# Dải IP cho Service
--service-cluster-ip-range=10.96.0.0/12
- Pod IP: Pod-A gọi Pod-B là truy cập trực tiếp IP thật của Pod-B.
- Service IP: IP ảo. Khi gọi đến
10.96.0.1
, kube-proxy trên mỗi Node sẽ dùng iptables hoặc IPVS để DNAT gói tin đó sang một Pod IP thực (ví dụ10.244.1.5
).
Nếu để cluster-cidr
trùng với VPC subnet, Pod sẽ không truy cập được tài nguyên cloud (RDS, S3…). Khắc phục lỗi này thường phải rebuild cluster.
Service Types
Một lỗi phổ biến là cứ muốn public service thì dùng type: LoadBalancer
.
Nhưng dùng LoadBalancer Service bừa bãi là cách nhanh nhất để đốt chi phí.
- ClusterIP (mặc định): Chỉ truy cập trong cluster. Dùng cho 90% workload backend, DB, cache…
- NodePort: Mở một port cố định (ví dụ 30080) trên tất cả Node. Thiếu load balancing, thiếu firewall rule, không phù hợp production.
- LoadBalancer: Yêu cầu cloud provider tạo External LB gắn với Service. Dùng tiện, nhưng mỗi Service sẽ sinh một LB riêng. 20 Service = 20 LB + 20 IP Public + chi phí vận hành cao.
NetworkPolicy
Mặc định Kubernetes là flat network: mọi Pod ở mọi namespace đều có thể kết nối với nhau.
Điều đó có nghĩa: nếu Pod frontend
bị compromise, attacker có thể scan và tấn công thẳng vào Pod database
hoặc redis
trong namespace khác.
- Giải pháp: dùng NetworkPolicy (CNI phải hỗ trợ, như Calico/Cilium).
- Tư duy: Zero Trust. Bắt đầu từ deny all, rồi chỉ allow những luồng traffic cần thiết.
- Ví dụ config:
# Bước 1: CHẶN TẤT CẢ traffic đến pod role=db
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-deny-all-ingress
namespace: production
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress: [] # rỗng = chặn tất cả
---
# Bước 2: CHỈ ALLOW pod role=app vào db:5432
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-app-to-db
namespace: production
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: app
ports:
- protocol: TCP
port: 5432
Không có NetworkPolicy, cluster của bạn giống như một LAN mở. Với app quan trọng, hãy coi NetworkPolicy là firewall bắt buộc.
Kết luận
Kubernetes networking không phải phép màu. Nó là sự phối hợp của 4 thành phần rõ ràng: CNI plugin, kube-proxy, CoreDNS, NetworkPolicy.
Đừng chỉ đọc diagram. Hãy thực hành: chạy tcpdump
trong Pod, thử policy để thấy traffic bị drop, thử curl my-service.my-namespace.svc.cluster.local
để thấy DNS hoạt động. Chỉ khi đó bạn mới thực sự kiểm soát được networking trong cluster.