Kubernetes 网络模型
K8s 要求网络实现满足以下约束(即"扁平网络"模型):
- 每个 Pod 都有唯一的 IP 地址
- 所有 Pod 无需 NAT 就能互相通信(跨节点也行)
- 节点与 Pod 无需 NAT 就能互相通信
- Pod 看到自己 IP 和别人看到它的 IP 是同一个
K8s 网络层次 ┌──────────────────────────────────────────────────────────┐ │ 外部用户 / 互联网 │ └──────────────────┬───────────────────────────────────────┘ │ ┌──────────────────▼───────────────────────────────────────┐ │ Ingress (L7 HTTP 路由,基于域名/路径分发) │ └──────────────────┬───────────────────────────────────────┘ │ ┌──────────────────▼───────────────────────────────────────┐ │ Service (L4 TCP/UDP 负载均衡,稳定虚拟 IP) │ └────────┬─────────────────────────┬────────────────────────┘ │ │ ┌────────▼────────┐ ┌────────▼────────┐ │ Pod │ │ Pod │ │ 10.244.1.5 │ │ 10.244.2.8 │ └─────────────────┘ └─────────────────┘ Node 192.168.1.10 Node 192.168.1.11
四种 Service 类型
ClusterIP(默认)
在集群内分配一个虚拟 IP,只能在集群内访问。适合服务间内部通信。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ClusterIP # 默认类型,可省略
selector: # 通过标签选择后端 Pod
app: my-app
ports:
- name: http
port: 80 # Service 暴露的端口
targetPort: 8080 # 转发到 Pod 的端口
protocol: TCP
# 集群内访问:http://my-service.default.svc.cluster.local
# 简写(同 namespace):http://my-service
NodePort
在每个 Node 上开放一个固定端口(30000-32767),外部通过 NodeIP:NodePort 访问。
spec:
type: NodePort
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 指定端口(可不填,随机分配 30000-32767)
# 外部访问:http://<任意节点IP>:30080
LoadBalancer
请求云厂商创建外部负载均衡器。是云上暴露服务的标准方式(每个 Service 会分配一个独立 LB,成本较高)。
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
# 云厂商会分配公网 IP,存入 status.loadBalancer.ingress[0].ip
Headless Service
设置 clusterIP: None,不分配虚拟 IP。DNS 直接返回所有后端 Pod 的 IP。StatefulSet 专用,用于 Pod 直接寻址。
spec:
clusterIP: None # Headless:不分配 ClusterIP
selector:
app: mysql
ports:
- port: 3306
# DNS 查询 mysql.default.svc.cluster.local
# 返回:10.244.1.5, 10.244.2.8, 10.244.3.3 (所有 Pod IP)
# 单个 Pod 寻址:mysql-0.mysql.default.svc.cluster.local
Endpoints 机制
Service 通过 Endpoints 对象维护后端 Pod IP 列表。当 Pod 就绪状态变化时,Endpoint Controller 自动更新 Endpoints。
# 查看 Service 的 Endpoints
kubectl get endpoints my-service
# 输出示例:
# NAME ENDPOINTS AGE
# my-service 10.244.1.5:8080,10.244.2.8:8080,10.244.3.3:8080 5m
Readiness Probe 失败时,EndpointSlice Controller 将该 Pod IP 从 Service 的 Endpoints 中移除,kube-proxy 不再向其转发流量。这正是 readinessProbe 与 livenessProbe 的核心区别:前者控制流量,后者控制重启。
kube-proxy 工作模式
Ingress 控制器
Service 提供 L4 负载均衡,而 Ingress 提供 L7 HTTP(S) 路由。一个 Ingress 资源可以根据域名和路径将流量路由到不同的 Service,共用一个 LoadBalancer,大幅降低成本。
Ingress 流量路由 外部请求 │ ▼ ┌─────────────────────────────────┐ │ Ingress Controller │ │ (如 ingress-nginx) │ └────────┬──────────┬──────────────┘ │ │ api.example.com app.example.com/v1 ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ api-service │ │ app-service │ └──────────────┘ └──────────────┘
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # 路径重写
nginx.ingress.kubernetes.io/ssl-redirect: "true" # 强制 HTTPS
nginx.ingress.kubernetes.io/rate-limit: "100" # 限流
spec:
ingressClassName: nginx # 指定使用哪个 Ingress Controller
tls: # HTTPS 配置
- hosts:
- api.example.com
secretName: api-tls-secret # TLS 证书 Secret
rules:
- host: api.example.com # 基于域名路由
http:
paths:
- path: /v1
pathType: Prefix # Prefix/Exact/ImplementationSpecific
backend:
service:
name: api-service-v1
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: api-service-v2
port:
number: 80
安装 ingress-nginx
# 使用 Helm 安装 ingress-nginx
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace
# 查看 Ingress Controller 获得的外部 IP
kubectl get svc -n ingress-nginx ingress-nginx-controller
K8s 1.24+ 引入了 Gateway API 作为 Ingress 的下一代替代品,提供更强大的路由能力(流量权重、Header 修改、TLS 终止等)。目前两者并存,新项目可考虑直接使用 Gateway API(需要支持的 Ingress Controller,如 Contour、Envoy Gateway)。
NetworkPolicy 网络策略
默认情况下 K8s 中所有 Pod 可以互相通信。NetworkPolicy 允许定义基于 Pod/namespace 标签的流量访问控制规则(需要 CNI 支持,如 Calico/Cilium)。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-to-db-only
namespace: production
spec:
podSelector: # 规则应用到哪些 Pod
matchLabels:
role: database
policyTypes:
- Ingress # 控制入站流量
ingress:
- from:
- podSelector: # 只允许 role=api 的 Pod 访问
matchLabels:
role: api
ports:
- protocol: TCP
port: 5432