Service-Ingress与流量管理
1. Service 类型
Pod IP 变来变去(重启就换),Service 提供稳定入口。
| 类型 | 用途 |
|---|---|
| ClusterIP | 集群内访问(默认) |
| NodePort | 每节点开个端口对外 |
| LoadBalancer | 调云厂商 LB(公网 IP) |
| ExternalName | DNS CNAME |
| Headless | 无 ClusterIP,直接给 Pod IP 列表(StatefulSet 用) |
1.1 ClusterIP
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api
ports:
- port: 80 # Service 端口
targetPort: 3000 # Pod 端口
protocol: TCP
type: ClusterIP
集群内访问:my-api.<namespace>.svc.cluster.local:80 或同 ns 内 my-api。
1.2 NodePort
spec:
type: NodePort
ports:
- port: 80
targetPort: 3000
nodePort: 30080 # 30000-32767
每个节点的 30080 端口都能访问。开发测试用。
1.3 LoadBalancer
spec:
type: LoadBalancer
云上自动建 LB(阿里 SLB、AWS ALB),分配公网 IP。每个 Service 一个 LB 成本高,生产用 Ingress 收口。
1.4 Headless
spec:
clusterIP: None
selector:
app: db
nslookup db 返回所有 Pod IP 列表,不做负载均衡。StatefulSet 用。
2. Service 实现:kube-proxy
kube-proxy 在每个节点维护 iptables / IPVS 规则。Pod 访问 Service IP 时被 NAT 到具体 Pod。
# 看 iptables 规则
sudo iptables -t nat -L KUBE-SERVICES -n
IPVS 模式比 iptables 性能好(O(1) vs O(n)),生产推荐:
kubectl -n kube-system get cm kube-proxy -o yaml | grep mode
3. DNS
CoreDNS 是集群 DNS。每个 Service 自动注册:
<service>.<namespace>.svc.cluster.local
Pod 内 /etc/resolv.conf 配 search domain,所以同 ns 直接 my-api 即可。
4. Ingress
LoadBalancer 一服务一 LB 不经济。Ingress = 一个 LB + 7 层路由:
公网 → LB → Ingress Controller (Pod) → 多个 Service → 多个 Pod
↑
按 host / path 路由
4.1 Ingress Controller
K8s 不内置,要装:
- nginx-ingress(社区版,最常用)
- nginx-ingress(NGINX 公司版,配置语法略不同)
- Traefik
- HAProxy
- 云厂商:AWS ALB Controller、阿里 ALB Controller
4.2 Ingress 资源
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Frame-Options: SAMEORIGIN";
spec:
ingressClassName: nginx
tls:
- hosts: [app.example.com]
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
4.3 pathType
| 值 | 含义 |
|---|---|
| Prefix | 前缀匹配(推荐) |
| Exact | 精确 |
| ImplementationSpecific | 控制器特定 |
4.4 cert-manager 自动签证书
# ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: ops@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
ingressClassName: nginx
# Ingress 加 annotation
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
cert-manager 自动签发 + 续期。
5. Gateway API(新一代)
Ingress 表达力有限,K8s 1.29+ 推 Gateway API:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-route
spec:
parentRefs:
- name: my-gateway
hostnames: [app.example.com]
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 80
weight: 90
- name: api-service-canary
port: 80
weight: 10
支持金丝雀流量分配、headers 改写、路由策略 CRD 化。Istio、Cilium、Envoy Gateway 都已支持。
6. NetworkPolicy(Pod 防火墙)
默认 Pod 之间网络全通。生产应该用 NetworkPolicy 限制:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow
namespace: backend
spec:
podSelector:
matchLabels:
app: api
policyTypes: [Ingress, Egress]
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: db
ports: [{protocol: TCP, port: 5432}]
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports: [{protocol: UDP, port: 53}]
CNI 插件必须支持(Calico、Cilium 支持,Flannel 不支持)。
7. Service 高级特性
7.1 sessionAffinity
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
同一 IP 路由到同一 Pod。NAT 后所有用户同 IP,慎用。
7.2 externalTrafficPolicy
spec:
type: LoadBalancer
externalTrafficPolicy: Local # Cluster | Local
- Cluster(默认):流量进任何节点都会被路由(可能跨节点跳一次)
- Local:只发给本节点的 Pod,保留客户端真实 IP,但要做好 Pod 在每节点都有
8. 故障排查
# Service 没 endpoints
kubectl get endpoints my-api
# 没结果 = selector 不匹配 / Pod 不 ready
# DNS 不通
kubectl run debug --rm -it --image=alpine -- sh
nslookup my-api
nslookup my-api.frontend.svc.cluster.local
# Ingress 502
kubectl logs -n ingress-nginx <ingress-controller-pod>
# 看 Nginx 错误日志
# 看 Ingress 实际生成的 Nginx 配置
kubectl exec -n ingress-nginx <ingress-controller-pod> -- cat /etc/nginx/nginx.conf
9. 常见反模式
- 每个 Service 都 LoadBalancer:成本爆炸
- 不用 Ingress 用 NodePort:端口管理混乱
- Ingress 不做 SSL:明文流量
- 不做 NetworkPolicy:Pod 间无隔离,一个被攻破全集群暴露
pathType: Exact给前端 SPA:刷新路由 404- Service selector 和 Pod label 不匹配:endpoints 为空,500
- 不限
proxy-body-size:上传被拒(默认 1MB) - 生产 default 流量策略 Local 但 Pod 不在每节点:部分节点请求 timeout