Pod networking — mỗi pod một IP, mô hình phẳng
Pod network model: mọi pod thấy nhau không NAT, container trong pod chung netns, pause container, liên hệ veth/bridge đã học.
TL;DR: Kubernetes gán mỗi pod một IP cluster-wide và coi pod như “máy logic” trên mạng phẳng: mọi pod nói chuyện với mọi pod (cùng node hay khác node) không NAT theo network model — trừ khi bạn cố ý phân đoạn bằng NetworkPolicy. Các container trong cùng pod chia sẻ một network namespace (IP, port space, localhost). Runtime thường giữ netns bằng pause/infra container “ngủ” trong khi app container join cùng ns. Dưới hood: CNI (bài sau) vẫn dựng veth + bridge hoặc route như Module 1–2 — Kubernetes không invent TCP stack mới. Pitfall số một: nhầm pod IP (ephemeral, gắn workload instance) với Service IP (VIP ổn định, kube-proxy rewrite — bài 03).
Code review: junior dán log curl 10.96.0.1:443 từ laptop “thử ClusterIP”, timeout; đồng thời bảo “pod IP 10.244.1.7 thì ping OK trong cluster, vậy Service hỏng”. Bạn hỏi: “10.96.0.1 có process listen không?” Không — đó là VIP. kubectl get pod -o wide thấy pod IP; kubectl get svc thấy ClusterIP. Hai dải, hai vai trò. Junior đang debug Service bằng thói quen “một IP = một container eth0” từ Docker. Contract K8s khác: pod IP là endpoint thật; Service IP là địa chỉ ảo được DNAT/IPVS.
Module 2 đã cho bạn netns + veth + bridge trên một host. Bài này nâng contract lên cluster: mô hình phẳng pod-to-pod, shared netns trong pod, pause container, và ranh giới với Service IP — trước khi CNI gắn mạng.
1. Analogy — Mỗi căn hộ một số máy; chung tủ điện trong căn
Nhớ M2 — Network namespaces: mỗi netns là một căn hộ với tủ mạng riêng. Kubernetes đổi đơn vị deploy:
- Một pod = một căn hộ (một netns mạng), không phải “mỗi container một căn” như Docker bridge mode cổ điển.
- Số máy căn = pod IP — unique trong cluster, gán khi pod schedule.
- Nhiều người trong cùng căn (app + sidecar + init) dùng cùng tủ điện — cùng IP, tranh port với nhau, gọi nhau bằng
localhost. - Toà nhà nhiều tầng (nhiều node): model K8s hứa mọi căn gọi được mọi căn bằng số máy thật, không phải “gọi qua số tổng đài NAT” giữa pod (NAT nằm ở cửa Service/egress — chỗ khác).
- Người gác cửa VIP (Service IP) là số ảo: chuông kêu, lính gác (kube-proxy) chuyển hướng tới căn thật — đừng tưởng VIP là eth0 của ai đó.
| Đời thường | Kubernetes |
|---|---|
| Căn hộ | Pod (một network namespace) |
| Số máy căn | Pod IP (pod.status.podIP) |
| Người trong căn | Containers (app, sidecar, init…) |
| Chuông trong căn | localhost / 127.0.0.1 giữa container cùng pod |
| Đường nối các căn (toà + giữa toà) | Pod network / CNI |
| Số tổng đài ảo | Service ClusterIP (bài 03) |
Pod = netns + IP. Container trong pod không có eth0 riêng trong model chuẩn — chúng share. Docker “mỗi container một IP trên bridge” ≠ default pod model.
2. Network model Kubernetes — ba lời hứa
Tài liệu chính thức gom networking thành vài bài toán: container-to-container trong pod, pod-to-pod, pod-to-Service, external-to-Service. Bài này khóa pod model (hai mảnh đầu).
2.1 Mỗi pod một IP cluster-wide
- Scheduler đặt pod lên node → runtime + CNI gán IP từ dải pod (CIDR do cluster/plugin cấu hình).
- IP xuất hiện ở
pod.status.podIP/podIPs(dual-stack nếu bật). - IP theo lifecycle pod: pod chết/recreate → IP mới (trừ pattern đặc biệt như một số StatefulSet + policy — đừng giả định IP cố định cho app stateless).
2.2 Pod-to-pod: flat, không NAT (model)
Theo Kubernetes network model:
- Mọi pod có thể nói chuyện với mọi pod khác (cùng node hoặc khác node).
- Giao tiếp trực tiếp, không dùng proxy hay address translation (NAT) giữa pod IP nguồn và pod IP đích — barring intentional network segmentation (NetworkPolicy, mesh, v.v.).
- Agent trên node (kubelet, daemon) nói chuyện được với pod trên cùng node.
Vì sao thiết kế vậy? Tránh “dynamic host port map” kiểu Docker publish cho mọi hop nội bộ: app bind port cố định trong pod; service discovery và config dùng IP/DNS ổn định hơn ở tầng Service, không ép mọi binary đọc “host port ngẫu nhiên”.
flowchart LR
subgraph N1["Node A"]
P1["Pod 10.244.1.7"]
P2["Pod 10.244.1.9"]
end
subgraph N2["Node B"]
P3["Pod 10.244.2.4"]
end
P1 -->|"L3 to pod IP no NAT"| P2
P1 -->|"L3 to pod IP no NAT"| P3
P2 -->|"L3 to pod IP no NAT"| P3Model ≠ “firewall luôn mở.” Default-allow full mesh cho đến khi NetworkPolicy (bài 05) hoặc plugin enforce segmentation. “Không NAT” mô tả địa chỉ (src/dst pod IP end-to-end trong path pod-to-pod), không mô tả “không có filter”.
2.3 Shared network namespace trong pod
Mỗi pod có private network namespace dùng chung bởi mọi container trong pod:
- Cùng IP (các address family được gán).
- Cùng port space — hai container không bind trùng
:8080. - Trong pod, container gọi nhau qua
localhost. - Hostname hệ thống trong pod thường khớp tên pod.
Đây là lời giải cho “highly-coupled container-to-container”: sidecar proxy, log shipper, auth helper… cùng logical host.
Scale out = nhiều pod (Deployment replicas), mỗi pod IP riêng. Sidecar = thêm container trong cùng pod, share netns. Nhầm hai pattern → port conflict hoặc “localhost không thấy service kia” (service kia đang ở pod khác).
3. Pause / infra container — ai giữ netns?
Trên Linux, network namespace gắn với process còn sống (và mount ns file). Runtime (containerd/CRI-O + kubelet) cần một process giữ netns của pod trong suốt đời pod, kể cả khi app container restart.
Pause container (hay gọi infra / sandbox container tùy runtime):
- Image tối giản (
pause/ tương đương): process “ngủ” (pause()/ sleep vòng), không chạy business logic. - Runtime tạo sandbox (netns + thường IPC/UTS share theo Pod) gắn process pause.
- App / init / sidecar container join cùng network namespace của sandbox.
- Pod delete → sandbox teardown → netns + veth/CNI resources được dọn (CNI
DEL— bài 02).
flowchart TB
subgraph POD["Pod sandbox = one netns"]
PAUSE["pause / infra process"]
APP["app container"]
SIDE["sidecar container"]
ETH["eth0 + lo in netns"]
PAUSE --- ETH
APP --- ETH
SIDE --- ETH
end
VETH["veth peer on host"] --- ETHBạn hiếm khi kubectl exec vào pause — nó không phải workload. kubectl exec -c <app> chạy trong cùng netns: ip addr, ss -lntp thấy bind của mọi container trong pod (cùng view mạng).
| Quan sát | Ý nghĩa |
|---|---|
kubectl get pod -o wide → một IP | IP của pod netns, không “IP từng container” |
Hai container cùng pod, một bind :80 | Cái kia không bind :80 được |
curl localhost:8080 từ sidecar | Đến process app cùng pod nếu app listen 8080 |
| App container restart | Netns/IP thường giữ (sandbox còn); connection cũ drop |
Pod hai container: app listen 0.0.0.0:8080, sidecar curl -sS 127.0.0.1:8080. Cùng node, pod khác cũng có app listen 8080. Sidecar có chạm nhầm pod kia không? Viết dự đoán — rồi đối chiếu mục 2.3.
Đáp án kỳ vọng: Không. 127.0.0.1 chỉ trong netns pod hiện tại. Pod kia có IP riêng; muốn gọi phải dùng pod IP (hoặc Service), không phải localhost.
4. Map về veth / bridge / route (recall M1–M2)
Kubernetes không thay softirq / sk_buff / netfilter. Trên một node, path quen thuộc Module 2:
4.1 Cùng node (điển hình bridge hoặc equivalent)
- Process app trong pod netns gửi gói từ
eth0(thường là đầu veth trong ns). - Peer veth nằm host/init netns (hoặc gắn bridge
cni0/flannel.*/ OVS / … tùy plugin). - L2/L3 trên node: bridge learning, hoặc route tới subnet pod local.
- Đích cùng node: gói vào veth peer của pod B → netns B.
Đây là nối netns bằng veth + bridge from scratch — chỉ ai gọi ip link đổi: Docker daemon vs CNI plugin do kubelet/runtime kích.
4.2 Khác node
Model vẫn: src = pod IP A, dst = pod IP B, không NAT đổi thành node IP giữa chừng (trong path chuẩn pod-to-pod).
Cách thực hiện do CNI:
- Routed: route/BGP quảng bá “subnet pod node X qua node X”; gói L3 thuần qua underlay.
- Overlay (vd VXLAN): gói pod bọc outer header giữa node; bên trong vẫn giữ pod IP — encapsulation ≠ NAT rewrite pod address.
Chi tiết trade-off: bài 02 — CNI.
flowchart TB
subgraph SRC["Pod A netns"]
AETH["eth0 veth"]
end
subgraph HOSTA["Node A host netns"]
AV["veth peer"]
BR["bridge or route/CNI"]
end
subgraph HOSTB["Node B host netns"]
BR2["bridge or route/CNI"]
BV["veth peer"]
end
subgraph DST["Pod B netns"]
BETH["eth0 veth"]
end
AETH --> AV --> BR
BR -->|"same node L2/L3 or underlay/overlay"| BR2
BR2 --> BV --> BETH4.3 So với Docker bridge “cổ điển”
| Docker bridge (lab M2) | Kubernetes pod model | |
|---|---|---|
| Đơn vị IP | Thường mỗi container một IP trên bridge | Mỗi pod một IP |
| Multi-process | Nhiều container = nhiều netns (trừ network_mode: container:…) | Nhiều container một netns |
| Ra Internet | Host SNAT/MASQUERADE (M2 bài 04) | Tương tự ở node; policy/CNI có thể siết |
| Publish port | DNAT host port (M2 bài 05) | Service/NodePort/Ingress — không map từng pod thủ công làm default |
| Cross-host | Không “free”; cần overlay/user-defined | Contract cluster: pod network xuyên node |
5. Worked walkthrough — đọc IP và netns (optional cluster)
Không bắt buộc cluster để hiểu model; nếu có kind / minikube:
# 1) See pod IPs (cluster-wide addresses on the pod network)
kubectl get pods -A -o wide
# 2) Pick a workload pod name/namespace from the table, then:
kubectl exec -n <ns> <pod> -- ip -br addr
kubectl exec -n <ns> <pod> -- ip route
# 3) Same view from another container in a multi-container pod (if any):
# kubectl exec -n <ns> <pod> -c <other> -- ip -br addr
# Expect the same pod IP on eth0.
# 4) Contrast Service VIP (no listener inside a random pod for that IP):
kubectl get svc -A
# Note ClusterIP range vs pod CIDR — different roles.
Kỳ vọng:
| Lệnh | Thấy gì |
|---|---|
get pods -o wide | Cột IP = pod IP trên node đã schedule |
ip -br addr trong pod | lo + eth0 (tên có thể khác) mang pod IP |
| Hai container cùng pod | Cùng địa chỉ trên iface pod |
get svc ClusterIP | Dải khác pod CIDR; không phải eth0 pod |
Trên node (lab advanced, cần shell node):
# Illustrative only — names vary by CNI
ip -br link | head
bridge link 2>/dev/null || true
# Often: vethXXXX@ifN pairs; one end in pod netns (not visible here without nsenter)
Map debug Module 2: nsenter / tcpdump đúng netns — khi “pod không ping pod”, vào đúng ns hoặc kubectl exec, đừng chỉ tcpdump eth0 host rồi kết luận app chết.
6. Vì sao nhầm pod IP với Service IP?
| Pod IP | Service ClusterIP | |
|---|---|---|
| Là gì? | Địa chỉ thật của netns pod | VIP ảo trong dải service CIDR |
| Ai “listen”? | Process trong pod bind port | Không có process listen VIP; kube-proxy/dataplane rewrite |
| Ổn định? | Đổi khi pod recreate | Ổn định theo object Service (trong đời Service) |
| Dùng khi debug app bind | kubectl exec + ss trong pod | get endpointslices / endpoints — backend pod IP:port |
| Client ngoài cluster | Thường không route thẳng (tuỳ network) | Cũng không — cần NodePort/LB/Ingress |
Triệu chứng nhầm:
- Hardcode pod IP trong config microservice → sau deploy, 50% call fail (pod mới IP mới).
curl <ClusterIP>từ máy laptop không có route/kube-proxy → timeout → “K8s hỏng” trong khi trong-cluster DNS Service vẫn ổn.- NetworkPolicy chọn nhầm: filter theo pod label/IP path, không “magically” hiểu tên Service nếu rule viết sai layer (chi tiết bài 05).
flowchart LR
C["Client in cluster"] --> VIP["Service ClusterIP VIP"]
VIP -->|"kube-proxy DNAT/IPVS"| PIP["Pod IP:targetPort"]
PIP --> APP["app in pod netns"]Bài 03 — Service & kube-proxy mổ rewrite; ở đây chỉ cần tách khái niệm: model phẳng gắn pod IP; ổn định discovery gắn Service.
Pod hostNetwork: true share netns host — không còn “một IP pod riêng” theo model chuẩn; port bind thẳng host, collision với daemon node. Dùng có chủ đích (một số agent); đừng lấy lab hostNetwork làm hình mẫu app thường.
📚 Deep Dive — tài liệu gốc
Spec / docs:
- Services, Load Balancing, and Networking — network model — pod IP, shared ns, no NAT pod-to-pod, vai trò CNI/NetworkPolicy.
- Pods — Pod networking — shared namespace, localhost, port space.
- Cluster Networking — bốn bài toán networking; CNI implements model.
- Design archive: Kubernetes networking design — lý do IP-per-pod.
Nội bộ OLHub (plumbing):
Liên hệ các bài khác
- 00 — Tổng quan Module 3 — bản đồ pod → CNI → Service → Ingress → NetworkPolicy.
- 02 — CNI là gì — ai tạo veth/IP khi pod start; overlay vs routed.
- 03 — Service & kube-proxy — VIP và DNAT/IPVS tới pod IP.
- 05 — NetworkPolicy — segmentation cố ý trên nền model default-allow.
- M2 — Debug container networking —
nsenter/tcpdumpkhi path veth lệch. - Networking Foundations — địa chỉ & định tuyến — L3 mental model trước khi đọc pod CIDR.
Tóm tắt
- Pod networking model: mỗi pod một IP; pod-to-pod L3 trực tiếp không NAT (model); segmentation là lớp thêm.
- Shared netns: mọi container trong pod chung IP/port/
localhost; scale = nhiều pod, không phải nhiều IP trong một pod. - Pause/infra: giữ sandbox/netns; app join ns — IP gắn pod, không gắn “từng container image”.
- Plumbing: veth + bridge/route (cùng node) và CNI path (khác node) — compose M1–M2, không stack user-space thay kernel.
- Pitfall: pod IP ephemeral endpoint; Service ClusterIP là VIP — đừng curl nhầm dual và đừng hardcode pod IP.
7. Tự kiểm tra
Q1Nêu ba đặc trưng cốt lõi của Kubernetes pod network model (IP, pod-to-pod, netns trong pod). Cái nào là 'model' chứ không phải 'mọi cluster luôn full-mesh không filter'?▸
Q2Hai container trong cùng pod: một sidecar gọi http://127.0.0.1:8080, app listen 8080. Vì sao được? Nếu tách app sang pod khác trên cùng node, localhost còn đúng không — phải dùng gì?▸
Q3Pause/infra container đóng vai trò gì với network namespace? App container restart có nhất thiết đổi pod IP không (model thông thường)?▸
Q4Trace mental model: gói từ pod A tới pod B cùng node. Liệt kê object Linux lần lượt (netns/veth/bridge-or-route) — map về lab M2.▸
Q5Phân biệt pod IP và Service ClusterIP theo: có process listen không, ổn định ra sao, dùng khi debug bind app thế nào?▸
Q6Junior hardcode 10.244.3.15 (pod IP lúc demo) vào config service khác. Sau rolling update, triệu chứng là gì và fix đúng hướng (không phải 'tăng timeout')?▸
Q7Vì sao model 'no NAT pod-to-pod' vẫn tương thích với việc node SNAT khi pod ra Internet (egress)? Hai chiều traffic khác nhau chỗ nào?▸
Bài tiếp theo: CNI là gì — interface gắn mạng cho pod
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