跳到主要内容

Service-Ingress与流量管理

1. Service 类型

Pod IP 变来变去(重启就换),Service 提供稳定入口。

类型用途
ClusterIP集群内访问(默认)
NodePort每节点开个端口对外
LoadBalancer调云厂商 LB(公网 IP)
ExternalNameDNS 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

10. 延伸阅读