CNI là gì — interface gắn mạng cho pod
CNI là interface (không phải implementation): plugin Flannel/Calico/Cilium, lúc tạo pod CNI được gọi, trade-off overlay (VXLAN) vs routed.
TL;DR: CNI (Container Network Interface) là hợp đồng giữa container runtime và plugin mạng: runtime gọi binary plugin với lệnh ADD/DEL/CHECK…; plugin tạo iface trong netns pod, gán IP, route, đôi khi policy. Kubernetes không “built-in Calico” — kubelet/CRI nhờ CNI thực hiện pod network model. Flannel / Calico / Cilium là implementation khác nhau (overlay VXLAN, BGP/routed, eBPF…). Trade-off lớn: overlay (đóng gói dễ qua subnet/cloud) vs routed (L3 thuần, ít encapsulation, ops routing/BGP). Pitfall cứng: cài CNI không implement NetworkPolicy → YAML policy xanh, traffic vẫn full-mesh.
On-call: cluster kind demo “default CNI”, junior apply NetworkPolicy default-deny rồi báo “policy không ăn — K8s bug”. kubectl get networkpolicies có object; kubectl exec pod A vẫn curl pod B. Bạn hỏi: “CNI nào? Plugin có policy enforcement không?” Nhiều lab CNI chỉ lo connectivity (ADD IP + route), không dataplane filter theo NetworkPolicy API. Object API tồn tại; effect = 0. Không phải RBAC, không phải nhãn sai trước — sai expectation về implementation.
Bài 01 chốt contract pod IP + shared netns. Bài này chốt ai gắn cáp: interface CNI, lifecycle ADD/DEL, bản đồ plugin, overlay vs routed.
1. Analogy — Ổ cắm chuẩn, nhiều hãng thiết bị
Pod model là nội quy toà nhà: mỗi căn một số máy, gọi nhau không qua NAT. Ai kéo cáp mỗi lần có cư dân mới?
- CNI spec = chuẩn ổ cắm / giao thức thợ: “khi có căn mới, thợ nhận lệnh ADD kèm path netns + tên iface; khi dọn căn, lệnh DEL”.
- Runtime (containerd/CRI-O + kubelet) = ban quản lý tạo căn (netns) rồi gọi thợ, không tự viết mọi hãng switch.
- Plugin binary (bridge, flannel, calico, cilium-cni…) = đội thợ / hãng thiết bị — cách kéo cáp khác nhau, cùng “ổ” ADD/DEL.
- Config JSON trên node (
/etc/cni/net.d/…) = hợp đồng gói thầu cố định: subnet, backend VXLAN hay BGP, IPAM…
| Đời thường | CNI |
|---|---|
| Chuẩn gọi thợ | CNI Specification |
| Ban quản lý | Container runtime (+ kubelet) |
| Đội thợ | Plugin executable (type trong config) |
| Sổ lệnh ADD/DEL | CNI_COMMAND + env + JSON stdin |
| Căn hộ (ns) | CNI_NETNS path |
| Tên cổng trong căn | CNI_IFNAME (thường eth0) |
Học interface trước brand. “Cluster dùng Calico” = chọn implementation cho cùng contract pod model — không phải Kubernetes đổi TCP/IP.
2. CNI là interface — không phải implementation
2.1 Định nghĩa theo spec
CNI Spec định nghĩa:
- Format cấu hình mạng (JSON:
name,cniVersion, listplugins…). - Protocol runtime → plugin: env vars + config stdin, result/error stdout.
- Thứ tự thực thi khi chain nhiều plugin.
- Delegation (vd IPAM plugin con).
- Result types (IP, iface, route, DNS…).
Ba thuật ngữ spec:
- container — domain isolation (thường = network namespace).
- network — nhóm endpoint addressable nói chuyện được với nhau.
- runtime — chương trình gọi plugin.
- plugin — chương trình áp cấu hình mạng.
Kubernetes docs nói rõ: phần lớn runtime Linux dùng CNI; các pod network implementation thường được gọi CNI plugins — nhưng model do K8s định nghĩa, cáp do plugin.
2.2 Runtime gọi gì? (operations)
| Command | Việc plugin làm (tóm tắt) |
|---|---|
ADD | Tạo/chỉnh iface CNI_IFNAME trong CNI_NETNS; gán IP/route; trả result JSON |
DEL | Gỡ iface / hoàn tác ADD; nên succeed cả khi resource đã mất (idempotent-ish) |
CHECK | Đối chiếu prevResult — iface/IP/route/policy còn đúng? |
VERSION | Báo spec versions plugin hỗ trợ |
GC / STATUS | Dọn stale / sẵn sàng nhận ADD (spec hiện đại) |
Tham số env cốt lõi: CNI_COMMAND, CNI_CONTAINERID, CNI_NETNS, CNI_IFNAME, CNI_PATH, CNI_ARGS.
sequenceDiagram
participant RT as Runtime CRI
participant PL as CNI plugin
participant NS as Pod netns
RT->>RT: create netns sandbox
RT->>PL: ADD + CNI_NETNS + IFNAME
PL->>NS: veth move IP route
PL-->>RT: result JSON IPs ifaces
Note over RT,PL: pod running
RT->>PL: DEL
PL->>NS: cleanup iface IPAM2.3 Lifecycle gắn pod (Linux)
Theo spec Lifecycle & Ordering (rút gọn đúng mental model K8s):
- Runtime tạo network namespace (sandbox/pause) trước khi gọi plugin.
ADD(có thể chain nhiều plugin trong list config — plugin sau nhậnprevResult).- Pod chạy; IP nằm trong result → kubelet report
pod.status.podIP. - Pod xoá / fail path: runtime
DEL(spec: ADD fail vẫn nên DEL cleanup); DEL có thể lặp. - Netns cleanup là trách nhiệm runtime.
Không parallel ADD/DEL cùng container; được song song khác container. Plugin phải lock tài nguyên dùng chung (IPAM file, v.v.).
Interface plugin tạo eth trong ns + connectivity. Chained (portmap, tuning, firewall…) chỉnh thêm trên prevResult. IPAM thường delegate: plugin chính gọi binary IPAM (host-local, dhcp…) để lấy địa chỉ rồi tự apply lên iface.
3. Bản đồ implementation — Flannel, Calico, Cilium
Không phải catalog marketing đủ feature — bản đồ đủ để đọc architecture review:
| Plugin (họ) | Hướng dataplane phổ biến | NetworkPolicy | Ghi chú nhập môn |
|---|---|---|---|
| Flannel | Thường overlay (VXLAN) hoặc backend host-gw | Hạn chế / không phải full policy engine | Đơn giản lab connectivity; đừng expect zero-trust YAML |
| Calico | Routed (BGP/route) và/hoặc overlay tuỳ config; iptables/nft/eBPF modes | Có (policy engine mạnh) | Hay gặp production “L3 + policy” |
| Cilium | eBPF dataplane; overlay hoặc native routing | Có (+ Hubble observe) | Identity/policy giàu; ops eBPF/kernel |
Các mảnh khác bạn sẽ gặp tên: Amazon VPC CNI, Azure CNI, Weave (legacy), kindnet (kind), Antrea… Cùng ổ CNI, khác cách implement pod CIDR và policy.
flowchart TB
MODEL["K8s pod network model"] --> IFACE["CNI interface ADD DEL"]
IFACE --> FL["Flannel family"]
IFACE --> CA["Calico family"]
IFACE --> CI["Cilium family"]
IFACE --> OT["Cloud VPC CNI kindnet ..."]
FL --> OV["Often overlay VXLAN"]
CA --> RT["Often routed BGP"]
CI --> EB["eBPF dataplane"]Chọn nhanh (heuristic, không dogma):
- Lab / “pod ping pod trước”: CNI đơn giản (kindnet/Flannel-style) OK.
- Cần NetworkPolicy production: chọn plugin document rõ enforce policy (Calico/Cilium/…); verify trên đúng distro/version.
- Multi-AZ cloud với routing hạn chế: overlay đôi khi “dễ lên”; bare-metal L3 sạch: routed/BGP thường gọn hơn encapsulation.
4. Overlay hay routed — trade-off chọn thế nào?
Cả hai nhằm giữ model: gói giữa pod mang pod IP nguồn/đích (no NAT east-west). Khác nhau ở đường giữa node.
4.1 Overlay — đóng gói
Ý tưởng: trên node A, gói từ pod được bọc (encapsulate) thành gói outer (thường UDP) gửi tới node B; node B tháo vỏ, đưa vào veth pod đích.
VXLAN (ví dụ phổ biến): VNI + VTEP; underlay chỉ cần IP connectivity node-to-node.
flowchart LR
PA["Pod A IP"] --> NA["Node A VTEP"]
NA -->|"outer UDP VXLAN"| NB["Node B VTEP"]
NB --> PB["Pod B IP"]| Ưu | Nhược |
|---|---|
| Chạy được khi underlay không biết route pod CIDR | MTU/overhead encapsulation; debug thêm lớp outer |
| “Lấp” multi-subnet/cloud dễ hơn cho team app | CPU/throughput encapsulation (mức độ tuỳ offload) |
| Topology pod logic tách underlay | Troubleshooting: tcpdump cả underlay và inner |
4.2 Routed — L3 thuần
Ý tưởng: mỗi node quảng bá (static route, BGP, …) “các IP pod của tôi đi qua tôi”. Router/underlay chuyển gói không bọc VXLAN (trong thiết kế pure routed).
flowchart LR
PA["Pod A"] --> NA["Node A"]
NA -->|"L3 route pod CIDR"| FAB["Underlay fabric"]
FAB --> NB["Node B"]
NB --> PB["Pod B"]| Ưu | Nhược |
|---|---|
| Ít overhead encapsulation; MTU đơn giản hơn | Underlay/BGP ops: scale route, policy routing |
| Dễ “nhìn” gói pod IP trên fabric (tuỳ design) | Cloud/VPC có lúc giới hạn route custom → ép overlay hoặc CNI cloud-native |
| Khớp tư duy L3 thuần Module foundations | Sai route table = “pod khác node timeout” dù cùng node OK |
4.3 Bảng so sánh một trang
| Trục | Overlay (vd VXLAN) | Routed (vd BGP/host-gw) |
|---|---|---|
| Outer header | Có (node→node) | Không (trong pure form) |
| Underlay cần biết pod CIDR? | Không (chỉ VTEP/node IP) | Có (route tới node “sở hữu” dải) |
| MTU | Phải trừ encapsulation | Gần MTU underlay |
| Debug | Hai lớp | Route/BGP + veth |
| Gần lab M2 | Bridge local + tunnel giữa host | Bridge/route local + ip route giữa host |
Hai node, pod CIDR khác nhau. tcpdump trên eth0 underlay node A khi pod A ping pod B. Overlay VXLAN: bạn kỳ vọng thấy ICMP echo trần pod IP hay UDP tới port VXLAN? Routed pure: khác gì?
Đáp án kỳ vọng: Overlay — thường thấy UDP (outer) giữa IP node; inner mang ICMP pod. Routed — thường thấy IP packet dst = pod B (hoặc next-hop) không bọc VXLAN. (Chi tiết port/VNI tuỳ backend — mental model đủ để chọn điểm bắt gói.)
5. Worked: đọc config CNI trên node (minh hoạ)
Tên path phổ biến (có thể khác distro):
# On a Kubernetes node (or kind node shell) — read-only survey
ls /etc/cni/net.d/ 2>/dev/null || echo "no /etc/cni/net.d"
ls /opt/cni/bin/ 2>/dev/null | head
# Example: show JSON list (do not paste secrets; lab only)
# sudo cat /etc/cni/net.d/*.conflist
Skeleton config list (minh hoạ — không copy production):
{
"cniVersion": "1.1.0",
"name": "cluster-network",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"ipam": {
"type": "host-local",
"subnet": "10.244.0.0/24"
}
}
]
}
Đọc field:
| Field | Ý nghĩa |
|---|---|
type | Tên binary trong CNI_PATH (vd /opt/cni/bin/bridge) |
ipam.type | Plugin IPAM delegated |
name | Tên network config (unique trên host) |
plugins[] | Chain: ADD xuôi, DEL ngược |
Khi pod Pending mãi với event mạng: kiểm CNI config có không, binary có trong PATH, log runtime/kubelet — trước khi nghi app image.
6. Pitfall — CNI không hỗ trợ NetworkPolicy
Kubernetes luôn có API NetworkPolicy. Docs network model nói thẳng:
- NetworkPolicy thường do pod network implementation enforce.
- Một số implementation đơn giản không implement policy, hoặc admin tắt.
- Khi đó API object vẫn apply (etcd xanh) nhưng không có hiệu lực trên dataplane.
| Dấu hiệu | Diễn giải |
|---|---|
kubectl get networkpolicy có resource | Chỉ chứng minh API server — không chứng minh enforce |
| Traffic full-mesh dù default-deny | Plugin không filter / sai CNI / kind lab CNI mỏng |
| Docs plugin ghi “supports NetworkPolicy” | Điều kiện cần — vẫn phải test deny rule thật |
| Đổi sang Calico/Cilium + rule đơn giản chặn được | Enforce path đã “có người nghe” API |
Quy trình an toàn trước khi tin zero-trust YAML:
- Xác định CNI đang chạy (DaemonSet/docs cluster).
- Đọc matrix NetworkPolicy support đúng version.
- Test: hai pod label khác nhau, policy deny,
curlphải fail; xoá policy → pass. - Không pass → đừng ship compliance dựa trên object tồn tại.
Chi tiết design rule: 05 — NetworkPolicy. Bài này chỉ đóng đinh: interface CNI ≠ mọi plugin làm đủ feature matrix.
Pod không có IP / FailedCreatePodSandBox → nghi ADD fail (config, IPAM cạn, binary missing).
Pod IP có, ping khác node fail → nghi route/overlay/underlay.
Policy không chặn → nghi thiếu enforce, không phải “quên apply” nếu object đã có. Ba class khác nhau — đừng một câu “restart CNI”.
📚 Deep Dive — tài liệu gốc
Spec / docs:
- CNI Specification — ADD/DEL/CHECK, config format, lifecycle, result JSON (spec 1.1.0 tại thời điểm biên soạn).
- Kubernetes — Services & networking model — CNI implements pod network; NetworkPolicy phụ thuộc implementation.
- Cluster Networking — runtime + CNI; danh sách addon networking.
- Network plugins (K8s) — cách kubelet/CRI tích hợp plugin.
Nội bộ OLHub:
- 01 — Pod networking cơ bản — contract IP/netns trước plugin.
- M2 — veth + bridge — object plugin thường tạo.
- M1 — iptables/netfilter — một số mode policy/SNAT plugin dùng.
Liên hệ các bài khác
- 01 — Pod networking — cái gì phải đúng sau ADD (IP, shared ns, flat model).
- 03 — Service & kube-proxy — sau khi pod có IP, VIP Service rewrite tới endpoint; một số CNI thay kube-proxy.
- 05 — NetworkPolicy — feature phụ thuộc plugin enforce.
- 04 — Ingress & LB — cửa L4/L7; vẫn giả định pod network đã ADD xong.
- M2 — SNAT egress — biên node khi pod ra ngoài; plugin có thể bật
ipMasq. - 00 — Tổng quan M3 — chỗ CNI trong pipeline capstone.
Tóm tắt
- CNI = spec + protocol plugin; Kubernetes compose model, plugin implement cáp/IP/policy.
- ADD/DEL (và CHECK…) gắn đời pod sandbox; runtime tạo ns trước, plugin gắn iface.
- Flannel / Calico / Cilium — bản đồ overlay / routed+policy / eBPF — chọn theo capability, không theo hype.
- Overlay vs routed: encapsulation vs L3 underlay — MTU, ops, debug khác nhau; cả hai phục vụ no-NAT pod IP model.
- Pitfall: NetworkPolicy không enforce nếu CNI không support — test deny thật, đừng tin mỗi
kubectl get.
7. Tự kiểm tra
Q1CNI là 'interface' nghĩa là gì — phân biệt với 'cluster đang chạy Calico'? Ai gọi binary plugin, ai implement veth/IP?▸
Q2Thứ tự lifecycle: netns tạo trước hay sau CNI ADD? Vì sao DEL vẫn chạy khi ADD fail (theo tinh thần spec)?▸
Q3Map nhanh Flannel vs Calico vs Cilium theo hai trục: dataplane điển hình và NetworkPolicy. Lab kind chỉ cần ping pod — chọn họ nào 'đủ', production zero-trust cần thêm gì?▸
Q4So sánh overlay VXLAN và pure routed: underlay có phải biết pod CIDR không? MTU/debug khác gì? Cả hai có phá model 'no NAT pod-to-pod' không?▸
Q5Junior apply NetworkPolicy default-deny, object Ready, traffic pod-to-pod vẫn full. Liệt kê checklist chẩn đoán theo thứ tự ưu tiên (CNI trước hay label trước)?▸
Q6Đọc field type và ipam.type trong CNI JSON list — mỗi field trỏ tới object gì trên disk? Sai type binary missing → triệu chứng pod phía K8s gần đúng là gì?▸
Q7Vì sao học CNI interface trước brand giúp debug 'Service OK, pod-to-pod khác node fail' tốt hơn chỉ đọc YAML Deployment?▸
Bài tiếp theo: Service & kube-proxy — traffic tới pod thế nào
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