《Kubernetes Service 进阶、kube-proxy 与 Ingress 实战精要》
本总结覆盖 Service 高级类型(NodePort / LoadBalancer / ExternalName / Headless) 、会话保持 、金丝雀发布 ,以及 kube-proxy 三种模式原理与切换 ,最后深入 Ingress-Nginx 控制器部署与核心规则 ,全部知识点配有带详细注释的 YAML 代码和命令示例,可直接用于生产环境参考。
一、Service 高级类型详解
1.1 环境准备(通用)
bash
kubectl create ns services
kubectl config set-context --current --namespace services
kubectl create deployment web --image=httpd --replicas=2 # 后端应用
1.2 ClusterIP(默认)
- 仅在集群内部可访问,分配一个虚拟 IP(ClusterIP)。
- 其他类型(NodePort、LoadBalancer)都基于 ClusterIP 构建。
YAML 示例(不带注释,简单):
yaml
apiVersion: v1
kind: Service
metadata:
name: web-clusterip
spec:
type: ClusterIP # 可省略,默认
selector:
app: web
ports:
- port: 80
targetPort: 80
1.3 NodePort
- 在每个节点开放一个静态端口(默认 30000-32767),集群外部可通过
NodeIP:NodePort访问。 - 内部仍然分配 ClusterIP,kube-proxy 负责转发。
带注释的 YAML:
yaml
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort # 指定类型
selector:
app: web
ports:
- port: 8080 # ClusterIP 监听的端口
targetPort: 80 # Pod 容器端口
nodePort: 30080 # 可选,固定节点端口(范围 30000-32767)
创建命令:
bash
kubectl expose deployment web --type=NodePort --port=8080 --target-port=80
访问测试(集群内任一节点 IP + nodePort):
bash
curl http://<任意节点IP>:30080
1.4 LoadBalancer
- 需要外部负载均衡器支持(云厂商或 MetalLB)。
- 为 Service 分配一个独立的外部 IP,外部客户端可直接通过该 IP 访问。
部署 MetalLB(裸机 K8s 负载均衡实现):
bash
# 下载并部署 metallb(需按环境替换镜像源)
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml
# 配置 IP 地址池(IPAddressPool)
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 10.1.8.40-10.1.8.80 # 可用的外部 IP 范围
EOF
# 配置 L2 宣告(L2Advertisement)
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
EOF
LoadBalancer Service YAML(带注释):
yaml
apiVersion: v1
kind: Service
metadata:
name: web-lb
spec:
type: LoadBalancer # 关键类型
selector:
app: web
ports:
- port: 80 # 外部访问端口
targetPort: 80
创建后,Kubernetes 会自动分配一个 EXTERNAL-IP(如 10.1.8.40)。
流量路径: 客户端 → LB IP:80 → 节点 kube-proxy → Service 转发 → Pod。
1.5 ExternalName
- 通过 CNAME 记录将 Service 映射到外部域名,不提供代理。
- 适用于集群内应用访问外部服务(如数据库)时统一使用 Service 名称。
示例:
yaml
apiVersion: v1
kind: Service
metadata:
name: my-external-service
spec:
type: ExternalName
externalName: database.example.com # 实际外部域名
集群内访问 my-external-service.namespace.svc.cluster.local 会解析为 database.example.com。
1.6 Headless Service(无头服务)
clusterIP: None,不分配 ClusterIP,kube-proxy 不处理。- DNS 直接返回后端 Pod IP 列表(带选择器)或 CNAME(无选择器 + ExternalName)。
- 适用于 StatefulSet、自定义服务发现。
YAML:
yaml
apiVersion: v1
kind: Service
metadata:
name: web-headless
spec:
clusterIP: None # 关键,设为 None
selector:
app: web
ports:
- port: 80
targetPort: 80
二、Service 会话保持(Session Affinity)
2.1 概念
- 默认
sessionAffinity: None,请求随机转发。 - 设置为
ClientIP后,基于源 IP 哈希,同一客户端始终转发到同一 Pod(适合有状态服务)。
2.2 配置与验证
bash
# 创建 Deployment 和 Service(普通)
kubectl create deployment web --image=httpd --replicas=2
kubectl expose deployment web --port=80
# 修改每个 Pod 主页为 Pod 名称(用于观察)
for pod in $(kubectl get pods -o name | cut -d/ -f2); do
kubectl exec $pod -- bash -c "echo $pod > htdocs/index.html"
done
# 验证默认分发(轮询)
for i in {1..10}; do curl -s 10.111.90.183; done | sort | uniq -c
# 输出会看到两个 Pod 各约 5 次
# 开启会话保持(使用 patch 命令)
kubectl patch svc web -p '{"spec":{"sessionAffinity":"ClientIP"}}'
# 再次测试,所有请求都发给同一个 Pod
for i in {1..10}; do curl -s 10.111.90.183; done | sort | uniq -c
# 输出只有 10 次同一条
YAML 中配置:
yaml
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 3600 # 粘性超时(默认 10800 秒)
注意: 会话保持与 kube-proxy 的 IPVS 模式配合时,会自动采用
sh(源地址哈希)调度算法。
三、金丝雀发布(Canary Deployment)复习
(已在 0810 笔记中详述,这里仅强调实现方式)
- 同时运行两个 Deployment(稳定版
track: stable,金丝雀版track: canary),Service 的 selector 只包含公共标签(如app: web, tier: frontend)。 - 通过调整两个 Deployment 的副本数比例实现流量灰度。
四、kube-proxy 工作模式详解
kube-proxy 是 K8s 核心网络组件,负责将 Service 的流量负载均衡到后端 Pod。
4.1 三种模式对比
| 模式 | 特点 | 性能 | 适用场景 |
|---|---|---|---|
| iptables(默认) | 基于 netfilter 规则链,规则多时性能下降 | 中(<1000 服务) | 小规模、稳定环境 |
| IPVS(推荐) | 基于内核哈希表,O(1) 查找,支持多种调度算法 | 极高(10w+ 服务) | 中大规模生产 |
| Userspace(废弃) | 用户态代理,性能极低 | 低 | K8s 1.25+ 已移除 |
4.2 查看当前模式
bash
# 查看 kube-proxy ConfigMap
kubectl get cm -n kube-system kube-proxy -o yaml | grep mode
# 查看 Pod 日志
kubectl logs -n kube-system -l k8s-app=kube-proxy | grep "Using"
# 输出:Using iptables proxy 或 Using ipvs Proxier
4.3 切换到 IPVS 模式
bash
# 1. 编辑 ConfigMap
kubectl edit cm -n kube-system kube-proxy
# 将 mode: "" 改为 mode: "ipvs"
# 2. 重启 kube-proxy DaemonSet
kubectl rollout restart ds -n kube-system kube-proxy
# 3. 验证
kubectl logs -n kube-system -l k8s-app=kube-proxy | grep "Using ipvs"
4.4 IPVS 原理验证(重点)
① 创建测试资源
bash
kubectl create deployment web --image=nginx --replicas=3
kubectl expose deployment web --port=80
② 查看 IPVS 虚拟服务器
bash
# 安装 ipvsadm 工具(节点上)
ipvsadm -L -n | grep -A5 "10.103.143.120:80" # Service ClusterIP
输出类似:
TCP 10.103.143.120:80 rr
-> 10.224.19.38:80 Masq 1 0 0
-> 10.224.113.164:80 Masq 1 0 0
-> 10.224.113.165:80 Masq 1 0 0
rr为调度算法(默认轮询)。- 每个后端 Pod 被注册为 Real Server。
③ 验证负载均衡
bash
for i in {1..60}; do curl -s 10.103.143.120; done | sort | uniq -c
# 每个 Pod 约 20 次,说明 rr 轮询生效。
④ 修改调度算法(如 wrr)
bash
# 编辑 ConfigMap,添加 ipvs.scheduler: "wrr"
kubectl edit cm -n kube-system kube-proxy
# ... 添加 scheduler: "wrr"
# 重启 kube-proxy 后生效
4.5 iptables 模式原理(补充)
- iptables 规则链:
KUBE-SERVICES→KUBE-SVC-XXX(SNAT + 概率负载均衡) →KUBE-SEP-XXX(DNAT) → Pod。 - 概率负载均衡通过
--probability实现,规则数量随后端增加而线性增长。
五、Ingress 控制器与核心规则
5.1 Ingress 是什么
- 为集群外部访问提供 7 层 HTTP/HTTPS 路由(域名、路径分流)。
- 需要部署 Ingress 控制器(如 ingress-nginx)才能生效。
5.2 部署 ingress-nginx(使用 LoadBalancer 类型)
bash
# 下载部署文件(已替换镜像源)
wget http://example.com/ingress-nginx-controller-v1.11.2.tar.gz
tar -xf ingress-nginx-controller-v1.11.2.tar.gz
# 修改镜像为私有仓库(如需)
sed -i 's#registry.k8s.io#hub.laoma.cloud#g' deploy.yaml
kubectl apply -f deploy.yaml
# 查看控制器资源
kubectl get all -n ingress-nginx
# 会看到 LoadBalancer Service 分配了外部 IP(如 10.1.8.40)
5.3 环境准备(两个后端服务)
bash
# webapp01
kubectl create deployment webapp01 --image=httpd --replicas=2
kubectl expose deployment webapp01 --port=80
# webapp02
kubectl create deployment webapp02 --image=httpd --replicas=2
kubectl expose deployment webapp02 --port=80
# 设置各自主页内容(略)
5.4 核心 Ingress 规则(带完整注释)
(1)多域名虚拟主机
场景: 不同域名 webapp01.laoma.cloud 和 webapp02.laoma.cloud 分别路由到不同服务。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
spec:
ingressClassName: nginx # 指定控制器
rules:
- host: webapp01.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
- host: webapp02.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp02
port:
number: 80
(2)同一域名多路径
场景: www.laoma.cloud/ 走 webapp01,www.laoma.cloud/games 走 webapp02。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-path-ingress
spec:
ingressClassName: nginx
rules:
- host: www.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
- path: /games
pathType: Prefix
backend:
service:
name: webapp02
port:
number: 80
(3)路径重写(裁剪前缀)------生产核心
场景: 前端访问 /webapp01/api/xxx,后端实际只认 /api/xxx,需要去掉 /webapp01 前缀。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-trimming-ingress
annotations:
nginx.ingress.kubernetes.io/use-regex: "true" # 启用正则
nginx.ingress.kubernetes.io/rewrite-target: /$1 # 重写目标,$1 捕获第一个括号内容
spec:
ingressClassName: nginx
rules:
- host: www.laoma.cloud
http:
paths:
- path: /webapp01/(.*)
pathType: ImplementationSpecific # 必须用 ImplementationSpecific 以支持正则
backend:
service:
name: webapp01
port:
number: 80
- path: /webapp02/(.*)
pathType: ImplementationSpecific
backend:
service:
name: webapp02
port:
number: 80
- 访问
www.laoma.cloud/webapp01/hello会转发到 webapp01 服务的/hello。
(4)HTTPS + TLS 证书 + 强制跳转
准备证书并创建 Secret:
bash
openssl genrsa -out www.key 2048
openssl req -new -key www.key -out www.csr -subj "/CN=www.laoma.cloud"
openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt
kubectl create secret tls www-tls --cert=www.crt --key=www.key
Ingress 配置:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true" # 强制 HTTPS 重定向
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- www.laoma.cloud
secretName: www-tls # 引用证书 Secret
rules:
- host: www.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
5.5 生产级常用注解速查(带说明)
| 注解 | 作用 | 示例值 |
|---|---|---|
nginx.ingress.kubernetes.io/rewrite-target |
路径重写 | /$1(裁剪前缀) |
nginx.ingress.kubernetes.io/ssl-redirect |
80 端口自动跳转 443 | "true" |
nginx.ingress.kubernetes.io/whitelist-source-range |
IP 白名单(逗号分隔 CIDR) | "10.1.8.0/24,192.168.1.0/24" |
nginx.ingress.kubernetes.io/limit-rps |
每秒请求数限流(单 IP) | "20" |
nginx.ingress.kubernetes.io/limit-connections |
单 IP 最大并发连接数 | "50" |
nginx.ingress.kubernetes.io/enable-cors |
开启跨域 | "true" |
nginx.ingress.kubernetes.io/proxy-read-timeout |
后端读取超时(秒) | "60" |
nginx.ingress.kubernetes.io/x-forwarded-for |
透传真实客户端 IP | "true" |
nginx.ingress.kubernetes.io/canary |
启用灰度(金丝雀) | "true" |
nginx.ingress.kubernetes.io/canary-weight |
灰度流量权重(0-100) | "10" |
示例(限流 + 白名单 + 超时):
yaml
metadata:
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "10.1.8.0/24"
nginx.ingress.kubernetes.io/limit-rps: "30"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "5"
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
六、环境清理
bash
kubectl delete ns services # 删除 Service 实验命名空间
kubectl delete ns ingress # 删除 Ingress 实验命名空间
以上内容涵盖了 Service 高级类型 、kube-proxy 模式切换与验证 、Ingress 控制器部署和 10+ 核心规则,可直接用于生产环境配置。