基于 Kubernetes v1.37 源码(
pkg/proxy/、pkg/controller/endpointslice/)
一、为什么需要网络抽象? @
Kubernetes 中 Pod 是短暂的,IP 会变化,多个 Pod 需要统一访问入口:
Pod IP 会变化 → 不能直接访问 Pod
↓
需要稳定的访问入口 → Service 抽象
↓
多个 Pod 需要负载均衡 → Endpoints/EndpointSlice
↓
外部访问 → NodePort / LoadBalancer / Ingress
↓
Pod 之间通信 → CNI 网络插件
二、网络体系全景 @
┌─────────────────────────────────────────────────────────────┐
│ 外部流量 │
│ ↓ │
│ Ingress Controller (Nginx/Traefik/Envoy) │
│ ↓ │
│ Service (ClusterIP / NodePort / LoadBalancer) │
│ ↓ │
│ kube-proxy (iptables / IPVS / nftables) │
│ ↓ │
│ Endpoints / EndpointSlice (后端 Pod IP) │
│ ↓ │
│ Pod │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Pod 间通信 │
│ CNI 插件 (Calico/Flannel/Cilium) → 路由/Overlay │
└─────────────────────────────────────────────────────────────┘
三、Service @
Service 为一组 Pod 提供稳定的网络端点。
3.1 Service 类型 @
| 类型 | 访问范围 | 用途 |
|---|---|---|
| ClusterIP | 集群内部 | 默认,仅内部可达 |
| NodePort | 节点 IP + 端口 | 外部直接访问 |
| LoadBalancer | 云厂商 LB | 自动创建外部负载均衡器 |
| ExternalName | CNAME 映射 | 映射到外部服务 |
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 80 # Service 端口
targetPort: 8080 # 容器端口
protocol: TCP
3.2 Service 实现原理 @
ClusterIP 是一个虚拟 IP(VIP),只存在于 iptables/ipvs 规则中:
客户端访问 ClusterIP:80
↓
kube-proxy 维护的 iptables/ipvs 规则
↓
DNAT 转换 → Pod IP:8080
↓
响应返回客户端
四、Endpoints / EndpointSlice @
4.1 Endpoints @
Endpoints 存储 Service 后端所有 Pod 的 IP 和端口:
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 10.244.1.5
nodeName: node-1
targetRef:
kind: Pod
name: nginx-1
- ip: 10.244.2.3
nodeName: node-2
targetRef:
kind: Pod
name: nginx-2
ports:
- port: 8080
protocol: TCP
4.2 EndpointSlice @
EndpointSlice 是 Endpoints 的替代方案,解决大规模集群性能问题:
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: my-service-abc123
labels:
kubernetes.io/service-name: my-service
addressType: IPv4
endpoints:
- addresses: ["10.244.1.5"]
nodeName: node-1
conditions:
ready: true
- addresses: ["10.244.2.3"]
nodeName: node-2
conditions:
ready: true
ports:
- port: 8080
protocol: TCP
为什么需要 EndpointSlice?
| 问题 | Endpoints | EndpointSlice |
|---|---|---|
| 单对象大小 | 所有后端在一个对象 | 每组最多 100 个端点 |
| 更新频率 | 任何变化都更新整个对象 | 只更新变化的 Slice |
| 扩展性 | 5000+ Pod 时性能下降 | 支持 100,000+ 端点 |
4.3 EndpointSlice Controller @
// pkg/controller/endpointslice/endpointslice_controller.go
func (c *Controller) syncService(logger klog.Logger, key string) error {
service, err := c.serviceLister.Services(namespace).Get(name)
// 1. 获取 Service 选择的所有 Pod
pods, err := c.podLister.Pods(namespace).List(labels.SelectorFromSet(service.Spec.Selector))
// 2. 按 kubernetes.io/service-name + endpointslice.kubernetes.io/managed-by
// 标签列出现有的 EndpointSlices
endpointSlices, err := c.endpointSliceLister.EndpointSlices(namespace).List(esLabelSelector)
// 3. 计算期望的 Slice,对比现有 Slice,执行增删改
// (计算逻辑封装在 staging/src/k8s.io/endpointslice/reconciler.go 的 Reconciler 中)
err = c.reconciler.Reconcile(logger, service, pods, endpointSlices, lastChangeTriggerTime)
return nil
}
五、kube-proxy @
kube-proxy 运行在每个节点上,实现 Service 的负载均衡。
5.1 三种模式 @
| 模式 | 实现 | 适用场景 |
|---|---|---|
| iptables | Linux iptables 规则 | 通用,默认 |
| IPVS | IPVS(内核负载均衡) | 大规模集群 |
| nftables | nftables(iptables 继任者) | 未来趋势 |
5.2 iptables 模式 @
// pkg/proxy/iptables/proxier.go
func (proxier *Proxier) syncProxyRules() {
// 1. 为每个 Service 创建 KUBE-SVC-XXXX 链及跳转规则
for svcName, svcInfo := range proxier.serviceMap {
// ...(KUBE-SERVICES → KUBE-SVC-XXXX 跳转)
// 2. 为该 Service 的所有 Endpoint 生成 KUBE-SEP-XXXX 链与 DNAT 规则
proxier.writeServiceToEndpointRules(natRules, svcPortNameString, svcInfo, svcChain, endpoints, args)
}
}
iptables 规则示例:
# 访问 ClusterIP:80
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp --dport 80 -j KUBE-SVC-ABCDE
# Service 链 → 随机选择后端
-A KUBE-SVC-ABCDE -m statistic --mode random --probability 0.5 -j KUBE-SEP-AAAAA
-A KUBE-SVC-ABCDE -j KUBE-SEP-BBBBB
# DNAT 转换
-A KUBE-SEP-AAAAA -p tcp -j DNAT --to-destination 10.244.1.5:8080
-A KUBE-SEP-BBBBB -p tcp -j DNAT --to-destination 10.244.2.3:8080
5.3 IPVS 模式 @
// pkg/proxy/ipvs/proxier.go
func (proxier *Proxier) syncProxyRules() {
// 1. 为每个 Service 创建 IPVS 虚拟服务
for svcName, svcInfo := range proxier.serviceMap {
vs := &utilipvs.VirtualServer{Address: svcInfo.ClusterIP, Port: svcInfo.Port /* ... */}
err = proxier.ipvs.AddVirtualServer(vs)
// 2. 为每个 Endpoint 添加真实服务器
for _, ep := range svcInfo.Endpoints {
rs := &utilipvs.RealServer{Address: ep.IP, Port: ep.Port}
err = proxier.ipvs.AddRealServer(vs, rs)
}
}
}
IPVS vs iptables:
| 特性 | iptables | IPVS |
|---|---|---|
| 匹配方式 | 顺序遍历 | 哈希表 O(1) |
| 规模限制 | ~5000 Service 性能下降 | 10,000+ Service |
| 负载均衡 | 随机 | 多种算法(rr/lc/dh/sh) |
| 内核模块 | 无需额外模块 | 需要 ip_vs 模块 |
5.4 nftables 模式 @
// pkg/proxy/nftables/proxier.go
func (proxier *Proxier) syncProxyRules() {
// 使用 nftables 替代 iptables
// 优势:原子更新、性能更好、规则更简洁
}
六、Ingress @
Ingress 提供 HTTP/HTTPS 层的路由规则。
6.1 Ingress 资源 @
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: foo.example.com
http:
paths:
- path: /bar
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
- path: /baz
pathType: Prefix
backend:
service:
name: service2
port:
number: 80
tls:
- hosts:
- foo.example.com
secretName: tls-secret
6.2 Ingress Controller @
Ingress 只是规则,需要 Ingress Controller 来执行:
| Controller | 实现 | 特点 |
|---|---|---|
| Nginx Ingress | Nginx | 最常用,功能丰富 |
| Traefik | Traefik | 自动发现,云原生 |
| Envoy Ingress | Envoy/Istio | 服务网格集成 |
| Contour | Envoy | Kubernetes 原生 |
| Gateway API | 多实现 | Ingress 的继任者 |
6.3 Ingress 执行流程 @
外部请求 → Ingress Controller(监听 Ingress 资源)
↓
匹配 Host + Path 规则
↓
转发到对应的 Service
↓
Service → kube-proxy → Pod
七、Gateway API @
Gateway API 是 Ingress 的继任者,解决 Ingress 的功能局限:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: example-class
spec:
controllerName: example.com/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: example-gateway
spec:
gatewayClassName: example-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example-route
spec:
parentRefs:
- name: example-gateway
hostnames:
- "foo.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /bar
backendRefs:
- name: service1
port: 80
Gateway API vs Ingress:
| 特性 | Ingress | Gateway API |
|---|---|---|
| 角色分离 | 管理员+用户混在一起 | GatewayClass/Gateway/Route 分离 |
| 多协议 | 主要 HTTP | HTTP/TCP/TLS/gRPC |
| 跨命名空间 | 不支持 | 支持 |
| 权重路由 | 注解实现 | 原生支持 |
八、CNI(容器网络接口) @
CNI 是 Pod 间通信的基础,由网络插件实现。
8.1 CNI 架构 @
┌────────────────────────────────────────────────────────────┐
│ Kubernetes 集群 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ CNI 插件(二进制 + 配置) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Calico │ │ Flannel │ │ Cilium │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ ↓ │
│ kubelet → CRI → CNI 插件 → 配置 Pod 网络 │
└────────────────────────────────────────────────────────────┘
8.2 CNI 插件接口 @
// github.com/containernetworking/cni/libcni/api.go
type CNI interface {
AddNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
DelNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
GetNetworkListCachedConfig(net *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
// 单个网络的 Add/Del/Check,以及
// ValidateNetworkList、GCNetworkList、GetStatusNetworkList 等
AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
// ...
}
8.3 网络配置流程 @
1. kubelet 创建 Pod
↓
2. kubelet 调用 CRI 创建 Sandbox
↓
3. CRI 调用 CNI 插件
↓
4. CNI 插件执行:
a. 创建 veth pair
b. 将一端放入 Pod 网络命名空间
c. 将一端放入主机网桥
d. 分配 Pod IP
e. 配置路由
↓
5. Pod 获得 IP,可以通信
8.4 主流 CNI 插件 @
| 插件 | 实现 | 特点 |
|---|---|---|
| Calico | BGP 路由 | 高性能,网络策略 |
| Flannel | VXLAN/Host-gw | 简单易用 |
| Cilium | eBPF | 高性能,可观测性 |
| Weave Net | Mesh 网络 | 零配置 |
| Antrea | OVS | VMware 开源 |
8.5 网络策略(NetworkPolicy) @
NetworkPolicy 控制 Pod 之间的通信:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-except-same-namespace
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: my-namespace
egress:
- to:
- namespaceSelector:
matchLabels:
name: my-namespace
九、DNS(CoreDNS) @
CoreDNS 为集群提供 DNS 服务:
9.1 Service DNS @
# ClusterIP Service
<service-name>.<namespace>.svc.cluster.local
# 示例
my-service.default.svc.cluster.local → 10.96.0.10
9.2 Pod DNS @
# Pod(需启用 hostname/subdomain)
<pod-ip-dashed>.<namespace>.pod.cluster.local
# 示例
10-244-1-5.default.pod.cluster.local
9.3 CoreDNS 配置 @
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
十、完整流量路径 @
10.1 集群内访问 @
客户端 Pod → Service ClusterIP
↓
kube-proxy(iptables/ipvs)
↓
DNAT 转换 → 选择后端 Pod
↓
响应返回客户端
10.2 外部访问(NodePort) @
外部请求 → 节点 IP:NodePort
↓
kube-proxy 拦截
↓
DNAT 转换 → 选择后端 Pod
↓
响应返回外部
10.3 外部访问(LoadBalancer) @
外部请求 → 云厂商 LB IP
↓
LB 转发到节点 NodePort
↓
kube-proxy 拦截
↓
DNAT 转换 → 选择后端 Pod
↓
响应返回外部
10.4 外部访问(Ingress) @
外部请求 → Ingress Controller(80/443)
↓
匹配 Host + Path 规则
↓
转发到对应 Service
↓
kube-proxy → Pod
↓
响应返回外部
十一、生产最佳实践 @
11.1 使用 IPVS 模式 @
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
ipvs:
scheduler: lc # 最少连接
11.2 启用 EndpointSlice @
# 默认已启用,检查状态
kubectl get endpointslices -A
11.3 使用 NetworkPolicy @
# 默认拒绝所有 ingress
kubectl apply -f deny-all.yaml
# 按需开放
kubectl apply -f allow-specific.yaml
11.4 使用 Gateway API @
# 安装 Gateway API CRD(standard channel,版本以最新发布为准)
kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/standard-install.yaml
十二、设计亮点总结 @
- 分层抽象:Service 提供稳定 VIP,Endpoints 维护后端 Pod IP,kube-proxy 实现负载均衡,Ingress 处理 HTTP 路由,CNI 管理 Pod 网络。
- kube-proxy 多模式:iptables/IPVS/nftables 适应不同规模和场景。
- EndpointSlice:解决大规模集群性能问题,支持 100,000+ 端点。
- Gateway API:角色分离,功能更强大,是 Ingress 的继任者。
十三、总结 @
Kubernetes 网络体系的设计体现了几个核心思想:
- 分层解耦:Service → Endpoints → kube-proxy → Pod
- 可插拔:CNI、Ingress Controller、kube-proxy 模式均可替换
- 可扩展:EndpointSlice、Gateway API 解决规模问题
- 安全性:NetworkPolicy 实现微隔离
理解网络体系,就掌握了 Kubernetes 服务间通信和外部访问的关键。