Kubernetes 服务暴露终极指南:从 Service 到 Ingress,深入理解 kube-proxy 与流量治理
Kubernetes 服务暴露终极指南:从 Service 到 Ingress,深入理解 kube-proxy 与流量治理
一文搞懂 K8s 服务发现、负载均衡、kube-proxy 三种模式、Ingress 部署与 12 个生产级规则实战
写在前面
在 Kubernetes 集群中,Pod 是动态的——它们随时可能被重建、迁移、扩缩容。如何让客户端(无论是集群内部还是外部)稳定、可靠地访问这些不断变化的 Pod?答案是 Service 和 Ingress。
- Service 提供稳定的访问入口(ClusterIP、NodePort、LoadBalancer),并负责 Pod 的负载均衡。
- Ingress 提供七层(HTTP/HTTPS)路由能力,支持域名、路径分发、SSL 终止、重写、限流等高级功能。
本文将系统讲解:
- Service 的四种类型与三种服务发现方式
- 会话保持与金丝雀发布
- kube-proxy 的 iptables 与 IPVS 模式原理(附实验验证)
- Ingress 控制器(ingress-nginx)部署
- 12 个生产级 Ingress 规则(多域名、路径重写、HTTPS 强制、限流、跨域、白名单等)
无论你是刚入门的 K8s 新手,还是正在优化集群网络的运维工程师,这篇实战指南都能帮你彻底搞懂“怎么把服务放出去”。
一、Service:K8s 的稳定访问入口
1.1 为什么需要 Service?
Pod 有自己的 IP,但 Pod 随时可能被删除重建(IP 变化)。Service 通过标签选择器动态关联一组 Pod,并提供固定的 ClusterIP 和 DNS 名称,实现:
- 服务发现:客户端只需访问 Service 的固定地址
- 负载均衡:流量在 Service 后端的所有健康 Pod 之间分发
- 解耦:无需关心 Pod 的 IP 变化
1.2 创建 Service 的基本方式
# 方式1:命令行 expose
kubectl expose deployment web --port=8080 --target-port=80
# 方式2:YAML 文件
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 8080
targetPort: 80
type: ClusterIP
二、Service 的三种发现方式
集群内的 Pod 如何访问 Service?有三种途径:
2.1 直接访问 ClusterIP
kubectl get svc web # 看到 ClusterIP: 10.103.19.150
curl http://10.103.19.150:8080
2.2 环境变量
Kubernetes 会在 Pod 启动时注入 Service 相关的环境变量:
kubectl run test --rm -it --image=busybox -- sh
/ # env | grep WEB_SERVICE
WEB_SERVICE_HOST=10.103.19.150
WEB_SERVICE_PORT=8080
2.3 DNS(CoreDNS)
Kubeadm 部署的集群默认安装 CoreDNS。Pod 可通过 <service>.<namespace>.svc.cluster.local 访问。
# 在 Pod 内
wget -qO- http://web.services.svc.cluster.local:8080
# 同一 Namespace 下可简写为
wget -qO- http://web:8080
三、Service 的四种类型
3.1 ClusterIP(默认)
仅集群内部可访问。适合内部微服务间通信。
type: ClusterIP
3.2 NodePort
在每个节点上开放一个固定端口(默认 30000-32767),外部可通过 <NodeIP>:<NodePort> 访问。
kubectl expose deployment web --type=NodePort --port=8080 --target-port=80
kubectl get svc web # 输出:8080:31917/TCP
curl http://10.1.8.31:31917
原理:kube-proxy 在每个节点监听该端口,并将流量转发到 ClusterIP。
3.3 LoadBalancer
需要云厂商或本地 LB 方案(如 MetalLB)。它会在 ClusterIP 和 NodePort 基础上再分配一个外部 IP。
注意:裸机环境需部署 MetalLB。
3.4 Headless Service
设置 clusterIP: None,不分配 ClusterIP,直接返回 Pod IP 列表(通过 DNS A 记录)。适合 StatefulSet 等需要直连 Pod 的场景。
spec:
clusterIP: None
selector:
app: web
四、会话保持(Session Affinity)
默认 Service 轮询分发请求。若需同一客户端始终访问同一 Pod,启用 sessionAffinity: ClientIP:
kubectl patch svc web -p '{"spec":{"sessionAffinity":"ClientIP"}}'
可调整超时时间(默认 10800 秒):
kubectl patch svc web -p '{"spec":{"sessionAffinityConfig":{"clientIP":{"timeoutSeconds":3600}}}}'
五、金丝雀发布与 Service 配合
通过 两个 Deployment + 同一个 Service 实现流量灰度:
- 稳定版 Deployment 带有
track: stable标签,副本数 10 - 金丝雀版 Deployment 带有
track: canary标签,副本数 1 - Service 的 selector 只选择
app=web(不含 track),因此两个版本都在后端
逐步调整副本数,即可按比例分配流量。
kubectl scale deployment web-stable --replicas=8
kubectl scale deployment web-canary --replicas=2
# 此时 20% 流量进入 canary
六、kube-proxy 工作原理
kube-proxy 是 K8s 的网络代理组件,负责实现 Service 的转发。它有三种模式:
| 模式 | 地位 | 性能 | 特点 |
|---|---|---|---|
| iptables | 默认 | 中(<1000 服务) | 规则链线性匹配,大规模时性能下降 |
| IPVS | 推荐 | 极高(10w+ 服务) | 内核哈希表,O(1) 查找,支持多种算法 |
| Userspace | 已废弃(1.25+) | 低 | 用户态转发,性能差 |
6.1 iptables 模式详解
当 Service 创建后,kube-proxy 在 nat 表中生成规则链:
KUBE-SERVICES:总入口KUBE-SVC-XXX:每个 Service 的负载均衡链(随机概率分发)KUBE-SEP-XXX:每个 Endpoint 的 DNAT 链
验证:
iptables-save | grep <Service-ClusterIP>
6.2 IPVS 模式(生产首选)
IPVS 基于内核哈希表,性能远超 iptables,且支持多种调度算法:rr、wrr、lc、sh 等。
切换 IPVS 模式:
kubectl edit configmap -n kube-system kube-proxy
# 修改 mode: "ipvs"
kubectl rollout restart ds -n kube-system kube-proxy
验证:
kubectl logs -n kube-system kube-proxy-xxx | grep "Using ipvs Proxier"
ipvsadm -Ln # 查看虚拟服务器和 Real Server
七、Ingress:七层路由网关
7.1 Ingress 是什么?
Ingress 是 K8s 的 API 资源,定义 HTTP/HTTPS 路由规则(域名、路径)。它本身不处理流量,需要 Ingress 控制器(如 ingress-nginx、Traefik)解析规则并配置实际的负载均衡器。
典型架构:
Client --> Ingress Controller (Nginx) --> Service --> Pod
7.2 部署 ingress-nginx
本次选用 ingress-nginx 控制器(v1.11.2),支持 K8s 1.30。
# 下载部署文件(已修改镜像源)
kubectl apply -f deploy.yaml
部署后会创建:
- 命名空间
ingress-nginx - LoadBalancer 类型的 Service(需 MetalLB 分配外部 IP)
- Deployment + DaemonSet
kubectl get svc -n ingress-nginx
# 输出包含 EXTERNAL-IP(如 10.1.8.40)
7.3 Ingress 规则结构与基础示例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
ingressClassName: nginx
rules:
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp
port:
number: 80
八、生产级 Ingress 规则 12 项实战
以下实验基于两个测试服务:webapp01 和 webapp02,均已暴露为 ClusterIP Service。
8.1 多域名虚拟主机
rules:
- host: webapp01.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
- host: webapp02.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp02
port:
number: 80
8.2 同一域名多路径分流
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
- path: /games
pathType: Prefix
backend:
service:
name: webapp02
port:
number: 80
8.3 路径重写(剥离前缀)
场景:前端访问 /webapp01/api/xxx,后端只认 /api/xxx。
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: www.example.com
http:
paths:
- path: /webapp01/(.*)
pathType: ImplementationSpecific
backend:
service:
name: webapp01
port:
number: 80
8.4 HTTPS 强制 + TLS 证书
# 生成自签名证书
openssl req -x509 -newkey rsa:2048 -nodes -keyout tls.key -out tls.crt -days 365 -subj "/CN=www.example.com"
kubectl create secret tls www-tls --key=tls.key --cert=tls.crt
Ingress 配置:
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
tls:
- hosts:
- www.example.com
secretName: www-tls
rules:
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
8.5 限流(防刷)
annotations:
nginx.ingress.kubernetes.io/limit-connections: "50" # 单IP最大并发连接
nginx.ingress.kubernetes.io/limit-rps: "20" # 单IP每秒请求数
8.6 自定义超时
annotations:
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
8.7 跨域 CORS
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET,POST,PUT,DELETE,OPTIONS"
8.8 IP 白名单
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "10.1.8.0/24,192.168.0.0/16"
8.9 透传真实客户端 IP
annotations:
nginx.ingress.kubernetes.io/x-forwarded-for: "true"
nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "10.0.0.0/8"
8.10 静态资源缓存
annotations:
nginx.ingress.kubernetes.io/proxy-cache: "true"
nginx.ingress.kubernetes.io/proxy-cache-valid: "200 302 10m"
8.11 金丝雀(权重分流)
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10" # 10% 流量到金丝雀服务
8.12 自定义错误页面
annotations:
nginx.ingress.kubernetes.io/custom-http-errors: "404,500,502,503"
九、总结与最佳实践
9.1 Service 选型建议
| 场景 | 推荐类型 |
|---|---|
| 内部微服务通信 | ClusterIP |
| 开发测试环境暴露 | NodePort |
| 生产环境外部入口 | LoadBalancer + Ingress |
| StatefulSet 直连 Pod | Headless Service |
9.2 kube-proxy 选型
- 小规模(<1000 服务):iptables 足够
- 中大规模生产:务必切换 IPVS,性能提升数倍
9.3 Ingress 最佳实践
- 生产环境必须启用 HTTPS 强制 + 真实证书
- 配置合理的 限流和超时,防止雪崩
- 使用 路径重写 剥离路由前缀,避免后端感知前端路径
- 内部管理后台加 IP 白名单
- 金丝雀发布通过 Ingress 注解实现,比手动调整 Service 更方便
9.4 常见问题排查
- Service 无法访问:检查 selector 是否匹配 Pod label;targetPort 是否与容器端口一致
- Ingress 404:确认 path 类型(Prefix/Exact)和重写规则是否正确
- kube-proxy 切换 IPVS 失败:确认内核模块已加载(
ip_vs等),安装ipvsadm验证
写在最后
这篇文章我们从 Service 的基础概念一直讲到 Ingress 的十二个生产级规则,并深入解析了 kube-proxy 的两种核心模式。希望你能在实际集群中动手实验,把理论变成肌肉记忆。
本文所有 YAML 和命令均基于 K8s v1.30 + containerd + ingress-nginx v1.11.2 实测,请根据你的版本微调。
更多推荐
所有评论(0)