网络架构深度剖析

概述

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
// 1. CRI Runtime 创建 Sandbox 时调用 CNI

// 2. kubelet/network/cni/cni.go
func (c *cniPlugin) SetUpPod(podNamespace, podName string, id kubecontainer.ContainerID) error {
// 1. 加载 CNI 配置
networkConfigList, err := libcni.LoadConfList(c.confDir, c.confName)

// 2. 构建 CNI 参数
cniConfig := &libcni.CNIConfig{
Path: c.binDir,
}

// 3. 执行 ADD 命令
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
# ClusterIP (默认)
apiVersion: v1
kind: Service
metadata:
name: my-clusterip
spec:
type: ClusterIP # 默认
selector:
app: my-app
ports:
- port: 80
targetPort: 8080

# NodePort
apiVersion: v1
kind: Service
metadata:
name: my-nodeport
spec:
type: NodePort # 节点端口
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 可选,指定端口

# LoadBalancer
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
// kube-proxy/ipvs/proxier.go

func (proxier *Proxier) syncProxyRules() {
// 1. 获取所有 Services 和 Endpoints
services := proxier.serviceMap.Services()
endpoints := proxier.endpointsMap

// 2. 创建 IPVS 虚拟服务器
for _, svc := range services {
// 添加 ClusterIP 虚拟服务器
vs := &netlink.IPVSVirtualServer{
Address: svc.ClusterIP().To4(),
Protocol: uint16(svc.Protocol()),
Port: uint16(svc.Port()),
Scheduler: proxier.scheduler,
}
netlink.NewIPVS().AddVirtualServer(vs)
}

// 3. 添加真实服务器 (Endpoints)
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
# 查看 Service 相关的 iptables 规则
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 链
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
# kube-system/coredns ConfigMap
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
// pkg/controller/endpointslice/endpointslice_controller.go

func (c *Controller) syncService(key string) error {
// 1. 获取 Service
service, err := c.serviceLister.Services(namespace).Get(name)

// 2. 获取 Endpoints
endpoints := c.endpointLister.Endpoints(service)

// 3. 比较并更新 EndpointSlice
if !reflect.DeepEqual(currentSlices, desiredSlices) {
// 创建/更新/删除 EndpointSlice
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: # 目标 Pod
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 网络是如何配置的?

参考答案:

  1. kubelet 收到 Pod 创建请求
  2. CRI Runtime 创建 Pod Sandbox
  3. Runtime 调用 CNI 插件(/opt/cni/bin/)
  4. CNI ADD 命令执行:
    • 分配 IP(IPAM 插件)
    • 创建网络接口(bridge/veth)
    • 配置路由
  5. 返回网络配置结果给 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
# 方式1:使用完整域名
curl http://api-service.prod.svc.cluster.local

# 方式2:使用 DNS 搜索路径
# /etc/resolv.conf 配置了搜索路径
curl http://api-service.prod # 自动补全为 api-service.prod.svc.cluster.local

高级题

8. Calico 和 Flannel 有什么区别?

参考答案:

特性 Flannel Calico
网络模式 VXLAN Overlay BGP 路由
性能 一般 更好
NetworkPolicy
IPAM 简单 灵活
规模 小型 大型
运维 简单 复杂

9. IPVS 的工作原理是什么?

参考答案:
IPVS 是 Linux 内核级别的负载均衡:

  1. 虚拟服务器:为每个 Service 创建一个虚拟 IP
  2. 真实服务器:将后端 Pod 添加为真实服务器
  3. 调度算法:轮询、加权、最少连接等
  4. NAT 模式:修改数据包目的地址
1
2
# 查看 IPVS 规则
ipvsadm -Ln

10. 如何实现外部流量进入集群?

参考答案:

  1. NodePort

    1
    2
    3
    4
    5
    spec:
    type: NodePort
    ports:
    - port: 80
    nodePort: 30080 # 节点端口
  2. LoadBalancer

    1
    2
    3
    spec:
    type: LoadBalancer
    # 云提供商创建 LB,自动配置
  3. 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
# 1. 检查 Service 是否存在
kubectl get svc <name>

# 2. 检查 Endpoints
kubectl get endpoints <name>

# 3. 检查 Pod 是否 Running
kubectl get pods -l app=<label>

# 4. 测试 DNS 解析
kubectl exec -it test -- nslookup <svc-name>

# 5. 测试连接
kubectl exec -it test -- curl -v <svc-ip>:<port>

# 6. 检查 kube-proxy 日志
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
# 方式1:Service 权重分离
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10" # 10% 流量到金丝雀
spec:
rules:
- host: app.example.com
http:
paths:
- backend:
service:
name: my-app-canary
---
# 方式2:基于 Header
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
# Calico 实现
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 不能跨节点调度