网络架构深度剖析 概述 Kubernetes 网络系统涵盖 Pod 网络、Service 网络、Ingress 网络等多个层次,涉及 CNI 插件、kube-proxy、CoreDNS 等多个组件。本文深入剖析 Kubernetes 网络架构的工作原理。
整体架构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ┌──────────────────────────────────────────────────────────────────────────────┐ │ Kubernetes 网络分层 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Service 网络层 (L4) │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ClusterIP │ │ NodePort │ │ LoadBalancer │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ kube-proxy │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Pod 网络层 (L3/L2) │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ Flannel │ │ Calico │ │ Cilium │ │ │ │ │ │ (Overlay) │ │ (BGP) │ │ (eBPF) │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ CNI Plugins │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ DNS 解析层 │ │ │ │ CoreDNS │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
Pod 网络 CNI 插件类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ┌──────────────────────────────────────────────────────────────────────────────┐ │ CNI 插件类型 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Overlay (VXLAN/Geneve) │ │ │ │ │ │ │ │ Pod A (10.244.1.5) ──────────────────> Pod B (10.244.2.3) │ │ │ │ │ │ │ │ │ │ │ eth0 │ eth0 │ │ │ │ │ │ │ │ │ │ cni0 │ cni0 │ │ │ │ │ │ │ │ │ │ │ veth0 veth0 │ │ │ │ │ │ │ │ │ │ flannel.1 (VXLAN) ──────── 隧道 ───────────> flannel.1 │ │ │ │ │ │ │ │ Node A Node B │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Route (BGP/IPIP) │ │ │ │ │ │ │ │ Pod A ─> cni0 ─> eth0 ────────────────────────────> Pod B │ │ │ │ 直连路由 (无需封装) │ │ │ │ │ │ │ │ Node A Node B │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ eBPF (Cilium) │ │ │ │ │ │ │ │ Pod ─> veth ─> eth0 ─> TC ─> eBPF ─> NIC │ │ │ │ │ │ │ │ 直接在 TC 层处理,无需 iptables │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
Pod 网络配置流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 func (c *cniPlugin) SetUpPod(podNamespace, podName string , id kubecontainer.ContainerID) error { networkConfigList, err := libcni.LoadConfList(c.confDir, c.confName) cniConfig := &libcni.CNIConfig{ Path: c.binDir, } netResult, err := cniConfig.AddNetworkList( context.TODO(), networkConfigList, &containerConfig{ ContainerID: id.ID, PodName: podName, PodNamespace: podNamespace, }, ) return nil }
Service 网络 Service 类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 apiVersion: v1 kind: Service metadata: name: my-clusterip spec: type: ClusterIP selector: app: my-app ports: - port: 80 targetPort: 8080 apiVersion: v1 kind: Service metadata: name: my-nodeport spec: type: NodePort selector: app: my-app ports: - port: 80 targetPort: 8080 nodePort: 30080 apiVersion: v1 kind: Service metadata: name: my-lb spec: type: LoadBalancer selector: app: my-app ports: - port: 80 targetPort: 8080
kube-proxy 工作模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 ┌──────────────────────────────────────────────────────────────────────────────┐ │ kube-proxy 模式对比 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ userspace 模式 (旧) │ │ │ │ │ │ │ │ Client ──> Service IP ──> kube-proxy ──> Pod │ │ │ │ (iptables 捕获) (用户态转发) │ │ │ │ │ │ │ │ 缺点:额外转发,性能差 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ iptables 模式 (旧) │ │ │ │ │ │ │ │ Client ──> Service IP ──> iptables ──> Pod │ │ │ │ (IPVS NAT) │ │ │ │ │ │ │ │ 缺点:O(n) 规则,n 增则性能下降 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ IPVS 模式 (推荐) │ │ │ │ │ │ │ │ Client ──> Service IP ──> IPVS ──> Pod │ │ │ │ (ipvsadm) (内核态转发) │ │ │ │ │ │ │ │ 优点:O(1) 查找算法,高性能 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ NFT 模式 (新) │ │ │ │ │ │ │ │ 使用 nftables 替代 iptables │ │ │ │ 更好的性能和可扩展性 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
IPVS 工作原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 func (proxier *Proxier) syncProxyRules() { services := proxier.serviceMap.Services() endpoints := proxier.endpointsMap for _, svc := range services { vs := &netlink.IPVSVirtualServer{ Address: svc.ClusterIP().To4(), Protocol: uint16 (svc.Protocol()), Port: uint16 (svc.Port()), Scheduler: proxier.scheduler, } netlink.NewIPVS().AddVirtualServer(vs) } for _, ep := range endpoints { rs := &netlink.IPVSRealServer{ Address: ep.IP(), Port: uint16 (ep.Port()), Weight: 1 , } netlink.NewIPVS().AddRealServer(vs, rs) } }
iptables 规则 1 2 3 4 5 6 7 8 9 iptables -t nat -L KUBE-SERVICES -n KUBE-SERVICES - all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/my-clusterip:http has endpoints */ KUBE-SEP-XXX - all -- * * 10.244.1.5 0.0.0.0/0 statistic mode random probability 0.50000000000 KUBE-SEP-YYY - all -- * * 10.244.1.6 0.0.0.0/0 statistic mode random probability 1.00000000000
DNS 解析 DNS 架构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ┌──────────────────────────────────────────────────────────────────────────────┐ │ DNS 解析流程 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Pod /etc/resolv.conf │ │ │ │ │ │ │ │ nameserver 10.96.0.10 # CoreDNS ClusterIP │ │ │ │ search <ns>.svc.cluster.local svc.cluster.local cluster.local │ │ │ │ options ndots:5 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ CoreDNS │ │ │ │ │ │ │ │ 1. kubernetes 插件 │ │ │ │ - 处理集群内域名 │ │ │ │ - 格式: <svc>.<ns>.svc.cluster.local │ │ │ │ │ │ │ │ 2. forward 插件 │ │ │ │ - 转发外部域名到上游 DNS │ │ │ │ │ │ │ │ 3. cache 插件 │ │ │ │ - 缓存查询结果 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
DNS 域名格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ┌──────────────────────────────────────────────────────────────────────────────┐ │ DNS 域名层次 │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 全限定域名 (FQDN) │ │ │ │ │ │ │ │ my-svc.my-namespace.svc.cluster.local │ │ │ │ ├───┬──┘├──┬──┤├───┬──┤└─────────────┘ │ │ │ │ │ │ │ └─────── cluster.local (集群域) │ │ │ │ │ │ └───────────── svc.cluster.local (服务域) │ │ │ │ │ └───────────────── my-namespace (命名空间) │ │ │ │ └───────────────────────── my-svc (服务名) │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ 简称: │ │ - my-svc # 同命名空间内 │ │ - my-svc.my-namespace # 跨命名空间 │ │ - my-svc.my-namespace.svc.cluster.local # 全限定 │ └──────────────────────────────────────────────────────────────────────────────┘
CoreDNS 配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 apiVersion: v1 kind: ConfigMap metadata: name: coredns data: Corefile: | .:53 { errors health kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure endpoint https://kubernetes.default.svc:443 pods verified } forward . /etc/resolv.conf { policy sequential } cache 30 loop reload loadbalance }
EndpointSlice Endpoint vs EndpointSlice 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ┌──────────────────────────────────────────────────────────────────────────────┐ │ Endpoint vs EndpointSlice │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Endpoint (旧) │ │ │ │ │ │ │ │ kind: Endpoints │ │ │ │ metadata: │ │ │ │ name: my-svc │ │ │ │ subsets: │ │ │ │ - addresses: │ │ │ │ - ip: 10.244.1.5 │ │ │ │ targetRef: │ │ │ │ kind: Pod │ │ │ │ name: my-app-abc123 │ │ │ │ │ │ │ │ 问题: 大规模集群一个 Service 可能上万 Endpoints │ │ │ │ 单个对象太大,etcd 压力,Watch 效率低 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ EndpointSlice (新) │ │ │ │ │ │ │ │ kind: EndpointSlice │ │ │ │ metadata: │ │ │ │ name: my-svc-abc123 │ │ │ │ labels: │ │ │ │ kubernetes.io/serviceName: "my-svc" │ │ │ │ addressType: IPv4 │ │ │ │ endpoints: │ │ │ │ - addresses: ["10.244.1.5"] │ │ │ │ conditions: │ │ │ │ ready: true │ │ │ │ targetRef: │ │ │ │ kind: Pod │ │ │ │ name: my-app-abc123 │ │ │ │ │ │ │ │ 优点: 每个 Slice 最大 100 个 Endpoints,按需分片 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
EndpointSlice Controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func (c *Controller) syncService(key string ) error { service, err := c.serviceLister.Services(namespace).Get(name) endpoints := c.endpointLister.Endpoints(service) if !reflect.DeepEqual(currentSlices, desiredSlices) { c.updateEndpointSlices(service, desiredSlices) } }
Ingress Ingress 工作原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ┌──────────────────────────────────────────────────────────────────────────────┐ │ Ingress 架构 │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Client │ --> │ Ingress │ --> │ Ingress │ │ │ │ │ │ Nginx │ │ Controll│ │ │ └─────────┘ └─────────┘ └────┬────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Ingress Resource │ │ │ │ │ │ │ │ apiVersion: networking.k8s.io/v1 │ │ │ │ kind: Ingress │ │ │ │ metadata: │ │ │ │ annotations: │ │ │ │ nginx.ingress.kubernetes.io/rewrite-target: / │ │ │ │ spec: │ │ │ │ rules: │ │ │ │ - host: app.example.com │ │ │ │ http: │ │ │ │ paths: │ │ │ │ - path: /api │ │ │ │ pathType: Prefix │ │ │ │ backend: │ │ │ │ service: │ │ │ │ name: api-service │ │ │ │ port: │ │ │ │ number: 80 │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘
Ingress Controller 类型
控制器
特点
支持 Annotation
NGINX Ingress
最流行,功能丰富
nginx.ingress.kubernetes.io/*
Traefik
云原生,支持自动 TLS
traefik.ingress.kubernetes.io/*
Ambassador
基于 Envoy,API 管理
getambassador.io/*
Contour
基于 Envoy,HVASS
projectcontour.io/*
Istio Ingress
与服务网格集成
istio.io/*
关键代码路径
文件
说明
pkg/kubelet/network/cni/
CNI 插件
pkg/kubelet/network/
网络插件接口
pkg/proxy/
kube-proxy 实现
pkg/kubelet/network/dns/
DNS 配置
pkg/controller/endpointslice/
EndpointSlice Controller
pkg/controller/endpoint/
Endpoint Controller
plugin/pkg/network/
网络插件
网络策略 NetworkPolicy 语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: api-network-policy namespace: production spec: podSelector: matchLabels: app: api policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: role: frontend - namespaceSelector: matchLabels: name: monitoring ports: - protocol: TCP port: 8080 egress: - to: - podSelector: matchLabels: role: database ports: - protocol: TCP port: 5432
CNI 插件对 NetworkPolicy 的支持
插件
NetworkPolicy 支持
Flannel
❌ 不支持
Calico
✅ 支持
Cilium
✅ 支持
Weave
✅ 支持
Canal
✅ 支持 (Flannel + Calico)
面试题 基础题 1. Kubernetes 网络模型有哪些要求? 参考答案:
所有 Pod 可以直接通信,无需 NAT
所有 Node 可以直接与所有 Pod 通信,无需 NAT
Pod 看到的自己 IP 与其他人看到的相同
总结:扁平网络,IP 唯一,无 NAT
2. Service 的 ClusterIP 是如何工作的? 参考答案:
ClusterIP 是虚拟 IP,不存在于网络设备上
kube-proxy 通过 iptables/IPVS 规则拦截到 ClusterIP 的流量
规则将流量转发到后端 Pod 的真实 IP
使用 DNAT 修改目的地址
3. kube-proxy 有哪几种模式?各有什么特点? 参考答案:
模式
优点
缺点
userspace
兼容性好
性能差,额外转发
iptables
成熟,稳定
O(n) 规则,性能随规模下降
IPVS
O(1) 算法,高性能
需要 IPVS 内核模块
NFT
更好的可扩展性
新功能,部分发行版不支持
中级题 4. Pod 网络是如何配置的? 参考答案:
kubelet 收到 Pod 创建请求
CRI Runtime 创建 Pod Sandbox
Runtime 调用 CNI 插件(/opt/cni/bin/)
CNI ADD 命令执行:
分配 IP(IPAM 插件)
创建网络接口(bridge/veth)
配置路由
返回网络配置结果给 Runtime
5. DNS 解析的完整流程是什么? 参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 1. Pod 执行 nslookup api.default.svc.cluster.local 2. /etc/resolv.conf 配置: nameserver 10.96.0.10 # CoreDNS ClusterIP search default.svc.cluster.local ... 3. 请求发送到 10.96.0.10 4. CoreDNS 处理: - kubernetes 插件查询集群内域名 - 查询 Endpoints 获取 Pod IP - 返回 A 记录:api.default.svc.cluster.local -> 10.244.1.5 5. Pod 收到 IP,建立连接
6. EndpointSlice 相比 Endpoint 有什么优势? 参考答案:
分片 :每个 Slice 最多 100 个 Endpoints
高效 Watch :减少单个对象大小,提高 Watch 效率
减少 etcd 压力 :避免大对象
更好的索引 :通过标签快速定位
7. 如何实现跨命名空间的服务发现? 参考答案:
1 2 3 4 5 6 curl http://api-service.prod.svc.cluster.local curl http://api-service.prod
高级题 8. Calico 和 Flannel 有什么区别? 参考答案:
特性
Flannel
Calico
网络模式
VXLAN Overlay
BGP 路由
性能
一般
更好
NetworkPolicy
❌
✅
IPAM
简单
灵活
规模
小型
大型
运维
简单
复杂
9. IPVS 的工作原理是什么? 参考答案: IPVS 是 Linux 内核级别的负载均衡:
虚拟服务器 :为每个 Service 创建一个虚拟 IP
真实服务器 :将后端 Pod 添加为真实服务器
调度算法 :轮询、加权、最少连接等
NAT 模式 :修改数据包目的地址
10. 如何实现外部流量进入集群? 参考答案:
NodePort :
1 2 3 4 5 spec: type: NodePort ports: - port: 80 nodePort: 30080
LoadBalancer :
1 2 3 spec: type: LoadBalancer
Ingress :
1 2 3 4 5 6 7 8 9 10 11 apiVersion: networking.k8s.io/v1 kind: Ingress spec: rules: - host: app.example.com http: paths: - path: / backend: service: name: my-svc
11. 网络策略 (NetworkPolicy) 如何实现? 参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all spec: podSelector: {} policyTypes: - Ingress - Egress apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend spec: podSelector: matchLabels: app: backend ingress: - from: - podSelector: matchLabels: app: frontend
场景题 12. 如何排查 Service 无法访问的问题? 参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 kubectl get svc <name> kubectl get endpoints <name> kubectl get pods -l app=<label> kubectl exec -it test -- nslookup <svc-name> kubectl exec -it test -- curl -v <svc-ip>:<port> kubectl logs -n kube-system -l k8s-app=kube-proxy
13. 如何实现金丝雀发布? 参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "10" spec: rules: - host: app.example.com http: paths: - backend: service: name: my-app-canary --- annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "X-Canary" nginx.ingress.kubernetes.io/canary-by-header-value: "always"
14. 如何实现 Pod 固定 IP? 参考答案:
1 2 3 4 5 6 7 8 9 10 11 apiVersion: v1 kind: Pod metadata: name: static-ip-pod annotations: cni.projectcalico.org/ipAddrs: '["10.244.0.10"]' spec: containers: - name: app image: nginx
注意事项:
IP 必须在 Pod CIDR 范围内
IP 不能与其他 Pod 冲突
静态 IP 的 Pod 不能跨节点调度