kube-proxy和Kubernetes Ingress详解
kube-proxy
kube-proxy 是什么
kube-proxy 是 Kubernetes 集群中运行在每一个节点上的核心网络组件,它的核心职责就是实现 Service 的流量转发与负载均衡。(kube-proxy 就是跑在 K8s 每一台节点上的「流量调度员」。Service 只是一个固定的 “门牌号”,真正把访问 Service 的请求,准确送到后端 Pod 手里、还能均匀分摊压力的,就是 kube-proxy。)
简单来说: Service 只是一个抽象的概念、一组配置,本身不处理流量;真正在节点上落地转发规则、把发往 Service IP 的请求送到后端 Pod 的,就是 kube-proxy。 它会持续监听集群中 Service 和 Endpoint 的变化,实时更新节点上的转发规则,保证流量始终能正确转发到健康的后端 Pod。
kube-proxy 是 K8s 服务于 Pod 网络的核心组件,负责实现 Service(服务) 到 Endpoint(后端 Pod) 的流量转发与负载均衡。
工作模式类型
kube-proxy 工作模式有以下几种:
| 模式 | 地位 | 性能 | 适用场景 | 特点 |
|---|---|---|---|---|
| iptables | 默认模式 | 中(服务数 < 1000) | 小规模集群、环境稳定 | 依赖内核 netfilter,规则多时有性能损耗 |
| IPVS | 推荐模式 | 极高(服务数 10w+) | 中大规模生产环境 | 基于内核 IPVS,哈希表查找,性能碾压 iptables |
| Userspace | 老旧/废弃 | 低 | 仅测试、兼容旧版 | 全用户态转发,性能最差,K8s 1.25+ 已移除 |
✅ 生产环境必选 IPVS 模式,配合 Calico 网络插件,性能与稳定性最佳。
通俗理解三种模式的差异
-
iptables 模式:像“人工翻花名册”
• 工作方式:你没有电脑,只有一本超级厚的纸质花名册,上面按随机顺序记着所有住户的地址。每次快递来了,你只能从第一页开始,一行一行往下找:“张三?不是。李四?不是……”直到翻到最后一页才找到正确的地址。 • 痛点(短板):如果花名册只有几页(几百条规则),翻得很快。但如果有成千上万页(成千上万个 Service/Pod),每送一个快递都要从头翻到尾,光翻书就要花很长时间,CPU 都被翻书动作耗没了。 • 特点:门槛低,兼容性好,但服务越多,速度越慢。
-
IPVS 模式:像“智能分拣机器人 + 条码扫描”
• 工作方式:你引进了先进的自动化分拣系统。每个快递进来,机器一扫条码(目标 IP/端口),电脑屏幕瞬间就显示出对应的货架号和格子(后端 Pod),机器人直接精准投递。 • 优点:系统内置了哈希索引表(HashMap),无论仓库里有 100 个地址还是 100 万个地址,扫描+定位的时间几乎是恒定的(极短),完全不受规模影响。 • 特点:性能天花板,特别适合大规模集群,是目前生产环境的默认首选。
-
userspace 模式:像“保安大叔人工跑腿”
• 工作方式:快递到了大门口,你不能直接进小区送。必须先交给门口的保安大叔(用户空间的进程)。保安大叔先登记一下,然后亲自走一趟把快递送到住户手里,送完再跑回大门口等下一个包裹。 • 痛点(短板):所有包裹都要经过保安大叔的手,不仅多了一次搬运过程(数据拷贝),而且大叔跑腿来回的速度远不如机器人传送。发件量一多,大叔就累趴下了,门口堵成一团。 • 特点:最古老、最原始,多了一道内核态到用户态的转换,效率最低,已被淘汰。
工作模式切换
查看工作模式
#查看 kube-proxy 配置
[root@master30 ~ 18:22:52]# kubectl get cm -n kube-system kube-proxy -o yaml|grep mode
mode: ""
#默认输出 mode: "",空值表示使用默认模式,也就是 iptables。
# 先获取所有 kube-proxy Pod 名称
[root@master30 ~ 19:03:20]# kubectl get pods -n kube-system -l k8s-app=kube-proxy -o name
pod/kube-proxy-6scsp
pod/kube-proxy-8r5pq
pod/kube-proxy-h9n5w
# # 查看pod/kube-proxy日志(最准确);任选一个Pod查看日志,过滤模式关键字
[root@master30 ~ 19:03:40]# kubectl logs -n kube-system kube-proxy-6scsp |grep Using
I0629 00:41:39.383766 1 server_linux.go:69] "Using iptables proxy"
I0629 00:41:39.503671 1 server_linux.go:165] "Using iptables Proxier"
# 输出内容"Using iptables proxy",表明默认使用iptables
修改工作模式,切换为 IPVS 模式
# 步骤 1:编辑 kube-proxy 配置 ConfigMap
[root@master30 ~ 19:04:24]# kubectl edit configmaps -n kube-system kube-proxy
configmap/kube-proxy edited
# 找到并修改 `mode` 字段为相应的值例如ipvs。
....
metricsBindAddress: ""
mode: "ipvs"
....
# 步骤 2:重启 kube-proxy,kube-proxy是以 DaemonSet 方式部署的,滚动重启所有节点的 kube-proxy Pod:
[root@master30 ~ 19:05:47]# kubectl rollout restart daemonset -n kube-system kube-proxy
daemonset.apps/kube-proxy restarted
#DaemonSet 会逐个节点重建 Pod,新 Pod 会以 IPVS 模式启动。
# 步骤 3:验证模式切换
[root@master30 ~ 19:06:02]# kubectl get pods -n kube-system -l k8s-app=kube-proxy -o name
pod/kube-proxy-2sd57
pod/kube-proxy-nglqt
pod/kube-proxy-nr4ld
[root@master30 ~ 19:06:17]# kubectl logs -n kube-system kube-proxy-2sd57 |grep Using
I0629 11:06:04.012842 1 server_linux.go:233] "Using ipvs Proxier"
# 输出内容"Using ipvs Proxier",表明使用ipvs
IPVS 模式
IPVS 模式深度解析
1. 工作原理
IPVS(IP Virtual Server)是 Linux 内核自带的四层负载均衡模块,kube-proxy 只是调用内核的 IPVS 能力来实现转发,核心逻辑如下:
-
kube-proxy 监听 Service 和 Endpoint 变化;
-
在节点内核中创建对应的 IPVS 虚拟服务器(Virtual Server),对应 Service 的 IP + 端口;
-
将所有后端 Pod 作为真实服务器(Real Server)注册到这个虚拟服务器下;
-
流量到达节点后,内核 IPVS 直接通过哈希表快速查找到目标,按照调度算法转发给后端 Pod。
2. 核心优势
-
性能极高,不随服务数量下降 规则存在哈希表中,查找时间是固定的 O (1),哪怕集群有上万个 Service,转发延迟也几乎不变,这是它相比 iptables 最核心的优势。
-
调度算法丰富 内置多种负载均衡算法,适配不同业务场景,iptables 模式仅支持随机 / 轮询类简单策略。
-
天然支持会话保持 源地址哈希(SH)算法原生实现 ClientIP 会话保持,和 Service 的
sessionAffinity: ClientIP完美对应。 -
连接管理更高效 内核态维护连接状态,超时、回收机制更完善,高并发下资源占用更低。
3. 完整流量转发流程
以 Pod 访问 Service 为例:
-
客户端 Pod 发起请求,目标地址为 Service 的 ClusterIP;
-
数据包出 Pod 到所在节点的内核网络栈;
-
内核 IPVS 模块匹配到对应的虚拟服务,通过调度算法选中一个后端 Pod;
-
做地址伪装(MASQ)后,将数据包转发给目标 Pod;
-
目标 Pod 处理请求后,响应报文原路返回。
IPVS 为将流量均衡到后端 Pod 提供了更多选择:
-
rr:轮询 -
lc:最少连接(打开连接数最少) -
dh:目标地址哈希 -
sh:源地址哈希 -
sed:最短预期延迟 -
nq:最少队列
工作原理
kube-proxy 在宿主机内核中创建 IPVS 虚拟服务器,并将后端 Pod 作为 Real Server 注册。IPVS 基于 哈希表 存储转发规则,查找效率为 O(1)。流量到达后,IPVS 根据配置的调度算法直接将流量转发到后端 Pod,绕过了复杂的 iptables 规则链。
通信流程图:
访问 Service IP:Port
哈希查找+调度算法
直接路由/隧道
客户端 Pod
宿主机网卡
内核 IPVS 虚拟服务器
选择最优后端 Pod
后端 Pod IP:Port
响应流量直接返回
核心优势:
-
支持多种高级调度算法(轮询 rr、加权轮询 wrr、最少连接 lc 等)。
-
性能与服务数量无关,支持十万级服务规模。
-
内置健康检查(与 K8s Endpoint 联动)。
验证原理
前置准备
-
已安装 IPVS 依赖(
ipvsadm、ipset)并加载内核模块。 -
kube-proxy 已切换为 IPVS 模式。
验证步骤
1. 创建测试资源
# 创建一个 nginx Deployment
[root@master30 ~ 19:10:32]# kubectl create deployment web --image=docker.io/library/nginx --replicas=3
deployment.apps/web created
# 查看Pod IP
[root@master30 ~ 19:11:28]# kubectl get pods -o wide | awk '{print $1,$6}'
NAME IP
web-68b95c775c-69fwf 10.224.170.29
web-68b95c775c-h5rbw 10.224.215.174
web-68b95c775c-znb72 10.224.170.60
# 为了区分不同 Pod,修改每个 Pod 的首页为自身 Pod 名称:
[root@master30 ~ 19:11:45]# for pod in $( kubectl get pods -o custom-columns=NAME:.metadata.name --no-headers)
do
kubectl exec $pod -- bash -c "echo $pod > /usr/share/nginx/html/index.html"
done
# 验证主页内容
[root@master30 ~ 19:12:05]# curl http://10.224.170.29
web-68b95c775c-69fwf
[root@master30 ~ 19:12:28]# curl http://10.224.215.174
web-68b95c775c-h5rbw
[root@master30 ~ 19:12:58]# curl http://10.224.170.60
web-68b95c775c-znb72
#创建 ClusterIP 类型的 Service:
[root@master30 ~ 19:13:40]# kubectl expose deployment web --port=80
service/web exposed
[root@master30 ~ 19:13:42]# kubectl get svc web
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web ClusterIP 10.106.34.95 <none> 80/TCP 12s
2. 查看 IPVS 规则
在任意集群节点执行,这里在master30节点执行,查看 kube-proxy 创建的 IPVS 虚拟服务:
# 列出虚拟服务器 [root@master30 ~ 19:13:54]# ipvsadm -Lnt 10.106.34.95:80 Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.106.34.95:80 rr -> 10.224.170.29:80 Masq 1 0 0 -> 10.224.170.60:80 Masq 1 0 0 -> 10.224.215.174:80 Masq 1 0 0 字段解释: - Scheduler: rr:当前调度算法为轮询 - RemoteAddress:Port:后端真实 Pod 的 IP 和端口 - Masq:采用地址伪装转发模式,是 K8s 集群内部的默认转发方式 - Weight:后端节点的权重,默认都是 1 - ActiveConn:当前活跃的连接数 - InActConn:空闲 / 非活跃连接数
结论:IPVS 已成功为 Service 创建了虚拟服务,并绑定了所有后端 Pod。
3. 验证负载均衡效果
在集群内或外部访问 Service,观察流量是否分发到不同 Pod:
# 连续访问 60 次
[root@master30 ~ 19:14:23]# for i in {1..60}; do curl -s 10.106.34.95; done| sort | uniq -c
20 web-68b95c775c-69fwf
20 web-68b95c775c-h5rbw
20 web-68b95c775c-znb72
[root@master30 ~ 19:19:49]# ipvsadm -Lnt 10.106.34.95:80
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.106.34.95:80 wrr
-> 10.224.170.29:80 Masq 1 0 0
-> 10.224.170.60:80 Masq 1 0 0
-> 10.224.215.174:80 Masq 1 0 0
预期输出:会看到不同的 Pod 名称各自出现20次,证明 IPVS 轮询(rr)算法生效。
调度算法选择
1. rr(Round Robin,轮询)
-
逻辑:按顺序轮流将请求分配给后端 Pod,一人一次,绝对平均。
-
适用场景:后端 Pod 配置完全一致、请求处理耗时相近的普通 Web 服务、API 服务。
-
特点:最简单通用,也是默认算法。
2. wrr(Weighted Round Robin,加权轮询)
-
逻辑:根据后端权重分配请求,权重越高的 Pod 分到的请求越多。
-
适用场景:集群节点配置不一致(有高配有低配)、需要按性能分配流量的场景。
-
说明:权重可以和 Pod 的 CPU / 内存申请量联动,性能强的 Pod 自动获得更高权重。
3. lc(Least Connections,最少连接)
-
逻辑:优先把新请求发给当前活跃连接数最少的后端 Pod。
-
适用场景:长连接服务(WebSocket、游戏服务、数据库代理),请求处理时长差异大的场景。
-
特点:能自动避免慢节点堆积请求,负载均衡更精准。
4. sh(Source Hashing,源地址哈希)
-
逻辑:对客户端源 IP 做哈希计算,同一个 IP 永远转发到同一个后端 Pod。
-
适用场景:需要基于客户端 IP 的会话保持,对应 Service 的
sessionAffinity: ClientIP配置。 -
说明:Service 开启 ClientIP 会话保持时,IPVS 会自动切换为 sh 算法,优先级高于全局配置。
5. dh(Destination Hashing,目标地址哈希)
-
逻辑:对目标地址做哈希,同一个目标 IP 永远转发到同一个后端。
-
适用场景:缓存服务、正向代理场景,提升缓存命中率。
6. sed /nq(最短预期延迟 / 最少队列)
-
逻辑:更智能的动态调度算法,根据后端的响应延迟、等待队列长度分配请求。
-
适用场景:对延迟敏感的高性能业务,普通场景很少用到。
更改调度算法:
#编辑 kube-proxy ConfigMap,在 ipvs 配置段指定 scheduler调度算法:
root@master30:~# kubectl edit configmap kube-proxy -n kube-system
......
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: "wrr" #改为加权轮询wrr
.......
mode: "ipvs"
.......
# 重启 kube-proxy生效:
[root@master30 ~ 19:16:52]# kubectl rollout restart ds kube-proxy -n kube-system
daemonset.apps/kube-proxy restarted
#查看原来的权值发现都为1
[root@master30 ~ 19:19:49]# ipvsadm -Lnt 10.106.34.95:80
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.106.34.95:80 wrr
-> 10.224.170.29:80 Masq 1 0 0
-> 10.224.170.60:80 Masq 1 0 0
-> 10.224.215.174:80 Masq 1 0 0
假设把第一个后端的权重改成 10
[root@master30 ~ 19:23:46]# ipvsadm -e -t 10.106.34.95:80 -r 10.224.170.29:80 -m --weight 10
#发现确实权值变了
[root@master30 ~ 19:23:54]# ipvsadm -Lnt 10.106.34.95:80
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.106.34.95:80 wrr
-> 10.224.170.29:80 Masq 10 0 0
-> 10.224.170.60:80 Masq 1 0 0
-> 10.224.215.174:80 Masq 1 0 0
#验证wrr轮询策略
[root@master30 ~ 19:26:29]# for i in {1..24}; do curl -s 10.106.34.95; done | sort | uniq -c
20 web-68b95c775c-69fwf
2 web-68b95c775c-h5rbw
2 web-68b95c775c-znb72
最佳配置
apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: ipvs # ========== IPVS 核心配置 ========== ipvs: # 调度算法:普通业务用rr,异构节点用wrr,长连接用lc scheduler: "rr" # TCP连接超时时间(秒),超时后回收空闲连接,避免资源浪费 tcpTimeout: 900 # TCP FIN状态超时时间,优化连接关闭回收 tcpFinTimeout: 120 # UDP连接超时时间 udpTimeout: 300 # 排除本地回环地址的负载均衡,避免本地访问异常,生产必开 excludeCIDRs: - "127.0.0.1/32" # 严格ARP模式,避免ARP响应异常,配合Calico/MetalLB必开 strictARP: true # ========== 性能与稳定性优化 ========== # 降低OOM优先级,避免kube-proxy被系统杀掉,高并发必调 oomScoreAdj: -999 # iptables规则同步周期优化,避免频繁同步消耗CPU iptables: minSyncPeriod: 5s syncPeriod: 30s # 日志级别,2级适合生产,信息适中 logging: format: text verbosity: 2
iptables 模式(自学)
工作原理
kube-proxy 默认工作模式是 iptables 模式。
kube-proxy 监听 Service 和 Endpoint 变化,在宿主机内核中动态生成 iptables 规则链(KUBE-SERVICES、KUBE-SEP-XXX 等)。当流量进入宿主机时,通过 netfilter 框架逐条匹配 iptables 规则,实现 DNAT(目标地址转换)和负载均衡。
通信流程图:
访问 Service IP:Port
匹配 Service 规则
DNAT 转换
客户端 Pod
宿主机网卡
内核 iptables 规则链
随机选择后端 Endpoint IP
后端 Pod IP:Port
响应流量原路返回
核心缺点:
-
每增加一个 Service 或 Endpoint,都会新增/修改 iptables 规则。
-
当服务数量超过 1000 时,规则链膨胀,CPU 占用飙升,延迟显著增加。
验证原理
前置准备
-
kube-proxy 已切换为 iptables 模式。
验证步骤
1. 创建测试资源
使用ipvs实验环境准备的资源。
2. 查看防火墙规则
步骤1:获取防火墙规则。
在任意集群节点执行,这里在master30节点执行,保存防火墙规则:
root@master30:~# iptables-save > iptables.list
步骤2:分析 svc-nginx 规则。
root@master30:~# cat iptables.list |grep 10.103.143.120 -A KUBE-SERVICES -d 10.103.143.120/32 -p tcp -m comment --comment "services/web cluster IP" -m tcp --dport 80 -j KUBE-SVC-7D76YWGERGEPC4GC -A KUBE-SVC-7D76YWGERGEPC4GC ! -s 10.224.0.0/16 -d 10.103.143.120/32 -p tcp -m comment --comment "services/web cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
分析防火墙规则:
-
第一条防火墙规则:在
nat表KUBE-SERVICES服务总入口链中,匹配目的 IP 为 10.103.143.120/32、协议 TCP、目的端口 80 的报文,通过注释标识为 services/web 的 ClusterIP 服务,并跳转至该服务专属调度链 KUBE-SVC-7D76YWGERGEPC4GC。 -
第二条防火墙规则:则在服务专属链
KUBE-SVC-7D76YWGERGEPC4GC中,匹配源地址非 Pod 网段 10.224.0.0/16、目的 IP 10.103.143.120/32、协议 TCP、目的端口 80 的报文,注释标识为 services/web cluster IP,并跳转至 KUBE-MARK-MASQ 进行 SNAT 标记。
步骤3:进一步追踪链路KUBE-SVC-7D76YWGERGEPC4GC。
root@master30:~# cat iptables.list | grep KUBE-SVC-7D76YWGERGEPC4GC :KUBE-SVC-7D76YWGERGEPC4GC - [0:0] -A KUBE-SERVICES -d 10.103.143.120/32 -p tcp -m comment --comment "services/web cluster IP" -m tcp --dport 80 -j KUBE-SVC-7D76YWGERGEPC4GC -A KUBE-SVC-7D76YWGERGEPC4GC ! -s 10.224.0.0/16 -d 10.103.143.120/32 -p tcp -m comment --comment "services/web cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ -A KUBE-SVC-7D76YWGERGEPC4GC -m comment --comment "services/web -> 10.224.113.164:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-HYZM2VM7RCC7M2HX -A KUBE-SVC-7D76YWGERGEPC4GC -m comment --comment "services/web -> 10.224.113.165:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CHPZVFCOFL4YLCYM -A KUBE-SVC-7D76YWGERGEPC4GC -m comment --comment "services/web -> 10.224.19.38:80" -j KUBE-SEP-HM7RLUR2RXSQ3D6F
分析防火墙规则:
-
第一条防火墙规则:已分析过。
-
第二条防火墙规则:已分析过。
-
第三条防火墙规则:在服务调度链
KUBE-SVC-7D76YWGERGEPC4GC中,对所有协议与地址的访问报文,以 1/3 随机概率 将其跳转至后端端点链KUBE-SEP-HYZM2VM7RCC7M2HX,注释标识该端点对应 services/web 服务后端 10.224.113.164:80。 -
第四条防火墙规则:在服务调度链
KUBE-SVC-7D76YWGERGEPC4GC中,对未被前序规则匹配的报文,以 剩余流量 1/2 随机概率(总概率 1/3)跳转至后端端点链KUBE-SEP-CHPZVFCOFL4YLCYM,注释标识对应 services/web 后端 10.224.113.165:80。 -
第五条防火墙规则:在服务调度链
KUBE-SVC-7D76YWGERGEPC4GC中,对未被前序概率规则匹配的报文,无条件跳转(总概率 1/3)至后端端点链KUBE-SEP-HM7RLUR2RXSQ3D6F,注释标识对应 services/web 后端 10.224.19.38:80。
步骤4:进一步追踪上面最后三条规则目标链路。
root@master30:~# cat iptables.list | grep -e KUBE-SEP-HYZM2VM7RCC7M2HX -e KUBE-SEP-CHPZVFCOFL4YLCYM -e KUBE-SEP-HM7RLUR2RXSQ3D6F | grep DNAT -A KUBE-SEP-CHPZVFCOFL4YLCYM -p tcp -m comment --comment "services/web" -m tcp -j DNAT --to-destination 10.224.113.165:80 -A KUBE-SEP-HM7RLUR2RXSQ3D6F -p tcp -m comment --comment "services/web" -m tcp -j DNAT --to-destination 10.224.19.38:80 -A KUBE-SEP-HYZM2VM7RCC7M2HX -p tcp -m comment --comment "services/web" -m tcp -j DNAT --to-destination 10.224.113.164:80
分析防火墙规则:
-
第一条防火墙规则:在后端端点链
KUBE-SEP-HM7RLUR2RXSQ3D6F中,匹配TCP 协议报文,注释标识为 services/web 服务,执行DNAT 目标地址转换,将报文目的地址修改为10.224.19.38:80。 -
第二条防火墙规则:在后端端点链
KUBE-SEP-HYZM2VM7RCC7M2HX中,匹配TCP 协议报文,注释标识为 services/web 服务,执行DNAT 目标地址转换,将报文目的地址修改为10.224.113.164:80。 -
第三条防火墙规则:在后端端点链
KUBE-SEP-CHPZVFCOFL4YLCYM中,匹配TCP 协议报文,注释标识为 services/web 服务,执行DNAT 目标地址转换,将报文目的地址修改为10.224.113.165:80。
3. 总结
全链路流程图:
-
入口:访问 ClusterIP
-
分流:进入
KUBE-SERVICES -
服务调度:进入
KUBE-SVC-XXX(SNAT + 负载均衡) -
端点转发:进入
KUBE-SEP-XXX -
最终到达:后端 Pod
客户端访问
ClusterIP: 10.103.143.120:80
PREROUTING
nat 表
KUBE-SERVICES
服务总入口
KUBE-SVC-7D76YWGERGEPC4GC
services/web 专属调度链
SNAT 标记:非 Pod 网段流量
→ KUBE-MARK-MASQ
概率 1/3 负载均衡
概率 1/3 负载均衡
默认 1/3 负载均衡
KUBE-SEP-HYZM2VM7RCC7M2HX
KUBE-SEP-CHPZVFCOFL4YLCYM
KUBE-SEP-HM7RLUR2RXSQ3D6F
DNAT 转发
→ Pod: 10.224.113.164:80
DNAT 转发
→ Pod: 10.224.113.165:80
DNAT 转发
→ Pod: 10.224.19.38:80
Userspace 模式(下架)
kube-proxy 在用户态监听 Service 端口,接收流量后,通过本地代理转发到后端 Pod。全用户态处理,性能极低。
通信流程图:
访问 Service IP:Port
客户端 Pod
宿主机 kube-proxy 用户态进程
负载均衡选择后端 Pod
建立连接转发流量
后端 Pod
现状:K8s 1.25+ 版本已彻底移除该模式,不再支持。
环境清理
root@master30:~# kubectl delete ns services
Kubernetes Ingress
学习参考:Ingress
环境准备
[root@master30 ~ 10:42:18]# kubectl create ns ingress namespace/ingress created [root@master30 ~ 10:43:28]# kubectl config set-context --current --namespace ingress Context "cluster1-context" modified.
Ingress 介绍
一、先搞懂:为什么需要 Ingress?
在学 Ingress 之前,我们暴露服务用的是 NodePort:每个服务占用一个宿主机端口(比如 32213、30613),外面通过「节点 IP + 端口」访问。
但 NodePort 有三个很明显的问题:
-
端口不够用:服务一多,每个占一个 30000+ 端口,管理混乱,记不住;
-
只能四层转发:只管 IP + 端口,不能根据域名、URL 路径分流;
-
不支持 HTTPS、灰度发布、限流这些 Web 常用功能。
Ingress 就是来解决这些问题的: 它是集群的统一流量大门,所有 HTTP/HTTPS 请求都走这一个入口,它根据「域名、路径」把请求精准转发给后端不同的 Service。 你可以把它理解成:部署在 K8s 里的、能自动更新配置的 Nginx 反向代理
下面是 Ingress 的一个简单示例,可将所有流量都发送到同一 Service:
Ingress 不会随意公开端口或协议, 将 HTTP 和 HTTPS 以外的服务开放到 Internet 时,通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的 Service。
二、两个核心概念:Ingress 控制器 vs Ingress 资源
很多新手最懵的就是这俩,其实特别好区分:
1. Ingress 控制器(Ingress Controller)
-
它是真正干活的实体,本质就是 Nginx/Traefik 这类反向代理程序,以 Pod 形式跑在集群里;
-
它会一直盯着 K8s 的 API 服务器,一旦有新的 Ingress 规则创建,就自动把规则翻译成 Nginx 配置,然后重载生效;
-
重点:只创建 Ingress 规则没用,必须先部署控制器,就像你写了 Nginx 配置,但没有 Nginx 程序跑着,配置当然不生效。
2. Ingress 资源(Ingress)
-
它就是一个 K8s 的 YAML 配置文件,相当于 **「Nginx 配置规则」**;
-
里面写清楚:哪个域名、哪个路径,要转发到哪个 Service 的哪个端口;
-
它本身不处理流量,只是「规则说明书」,交给控制器去执行。
ingress-nginx 完整工作流程(对应你笔记里的 5 步)
-
部署 Ingress 控制器(跑起来 Nginx Pod);
-
我们写 Ingress 规则 YAML,提交给 K8s;
-
控制器实时监测到有新规则,自动读取;
-
把规则翻译成 Nginx 的
server/location配置,写进容器里的 nginx.conf; -
自动 reload Nginx,新规则立刻生效,全程不用手动登进容器改配置。
Ingress 工作在 OSI 第七层(HTTP/HTTPS),所以叫「七层代理」;Service 的 ClusterIP/NodePort 工作在第四层(TCP/UDP)。
ingress-nginx 部署前提
项目地址: kubernetes/ingress-nginx
-
本次环境使用负载均衡器处理流量,提前部署好 LoadBalancer,例如 metallb。
-
你必须部署一个 Ingress 控制器 才能满足 Ingress 的要求,例如 ingress-nginx。
ingress-nginx 版本
| Supported | Ingress-NGINX version | k8s supported version | Alpine Version | Nginx Version | Helm Chart Version |
|---|---|---|---|---|---|
| 🔄 | v1.11.2 | 1.30, 1.29, 1.28, 1.27, 1.26 | 3.20.0 | 1.25.5 | 4.11.2 |
| 🔄 | v1.11.1 | 1.30, 1.29, 1.28, 1.27, 1.26 | 3.20.0 | 1.25.5 | 4.11.1 |
| 🔄 | v1.11.0 | 1.30, 1.29, 1.28, 1.27, 1.26 | 3.20.0 | 1.25.5 | 4.11.0 |
| 🔄 | v1.10.2 | 1.30, 1.29, 1.28, 1.27, 1.26 | 3.20.0 | 1.25.5 | 4.10.2 |
| 🔄 | v1.10.1 | 1.30, 1.29, 1.28, 1.27, 1.26 | 3.19.1 | 1.25.3 | 4.10.1 |
| 🔄 | v1.10.0 | 1.29, 1.28, 1.27, 1.26 | 3.19.1 | 1.25.3 | 4.10.0 |
| ... |
ingress-nginx 部署
#上传ingress-nginx-controller-v1.11.2.tar.gz到master主机 #然后解压 [root@master30 ~ 11:12:30]# tar -xf ingress-nginx-controller-v1.11.2.tar.gz [root@master30 ~ 11:14:27]# ls | grep ingress ingress-nginx-controller-v1.11.2 ingress-nginx-controller-v1.11.2.tar.gz
ingress-nginx 部署文件 deploy.yaml文件包涵4个部分:
-
创建一个独立的命名空间 ingress-nginx
-
创建 ConfigMap
ConfigMap是存储通用的配置变量的,类似于配置文件,使用户可以将分布式系统中用于不同模块的环境变量统一到一个对象中管理;而它与配置文件的区别在于它是存在集群的“环境”中的,并且支持K8S集群中所有通用的操作调用方式。
创建pod时,对configmap进行绑定,pod内的应用可以直接引用ConfigMap的配置。相当于configmap为应用/运行环境封装配置。
pod使用ConfigMap,通常用于:设置环境变量的值、设置命令行参数、创建配置文件。
-
Ingress的RBAC授权的控制,其创建了Ingress用到的ServiceAccount、ClusterRole、Role、RoleBinding、ClusterRoleBinding
-
创建ingress-controller。前面提到过,ingress-controller的作用是将新加入的Ingress进行转化为httpd的配置
# 查看资源使用的镜像
[root@master30 ~ 11:12:42]# grep image: ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml|uniq
image: registry.k8s.io/ingress-nginx/controller:v1.11.2@sha256:d5f8217feeac4887cb1ed21f27c2674e58be06bd8f5184cacea2a69abaf78dce
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.4.3@sha256:a320a50cc91bd15fd2d6fa6de58bd98c1bd64b9a6f926ce23a600d87043455a3
#部署 ingress-nginx 需要两个镜像:
#controller:核心 Nginx 反向代理程序;
#kube-webhook-certgen:一次性 Job,生成准入校验证书,校验 Ingress 规则合法性;
#registry.k8s.io 是谷歌海外镜像仓库,国内环境拉取超时、下载失败,所以必须替换内网镜像源。
[root@master30 cloud 11:22:16]# pwd
/root/ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud
[root@master30 cloud 11:22:11]# ls
deploy.yaml kustomization.yaml
# 按需修改镜像,sed 替换镜像仓库地址:逻辑:把deployment.yaml文件里所有 registry.k8s.io 镜像仓库前缀,统一替换为内网私有仓库 hub.laoma.cloud;替换后镜像会变成:hub.laoma.cloud/ingress-nginx/controller:v1.11.2@sha256:xxx
[root@master30 ~ 11:23:59]# sed -i 's/registry.k8s.io/hub.laoma.cloud/g' ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
#sed 删除 sha256 校验哈希
[root@master30 ~ 11:24:01]# sed -i 's/@sha256.*//' ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
# 创建 Ingress
#kubectl apply -f yaml文件:标准创建 / 更新 K8s 资源命令;
#这个 yaml 一次性创建全套资源:独立命名空间、ConfigMap、RBAC 权限、准入 Webhook Job、控制器 Deployment、LoadBalancer 类型 Service;
[root@master30 ~ 11:24:06]# kubectl apply -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
注意:registry.k8s.io 镜像仓库中镜像无法直接下载,需要配置加速。我们也可以从 这里 获取。
查看部署的资源
[root@master30 ~ 11:24:16]# kubectl get all -n ingress-nginx NAME READY STATUS RESTARTS AGE pod/ingress-nginx-admission-create-mq24q 0/1 Completed 0 67s pod/ingress-nginx-admission-patch-cdf5m 0/1 Completed 0 67s pod/ingress-nginx-controller-8659885ffd-45cjk 1/1 Running 0 67s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ingress-nginx-controller LoadBalancer 10.107.50.75 <pending> 80:31282/TCP,443:30503/TCP 67s service/ingress-nginx-controller-admission ClusterIP 10.99.73.198 <none> 443/TCP 67s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/ingress-nginx-controller 1/1 1 1 67s NAME DESIRED CURRENT READY AGE replicaset.apps/ingress-nginx-controller-8659885ffd 1 1 1 67s NAME STATUS COMPLETIONS DURATION AGE job.batch/ingress-nginx-admission-create Complete 1/1 7s 67s job.batch/ingress-nginx-admission-patch Complete 1/1 8s 67s #执行 kubectl get all -n ingress-nginx 后,重点看这几个: #1. 核心 Pod(容器组)—— 一切正常 • pod/ingress-nginx-controller-8659885ffd-45cjk (状态: Running 1/1):这是真正干活的 Ingress 控制器。它正在后台运行,并时刻监控着集群里的 Ingress 规则。1/1 表示它已经就绪,随时可以处理流量。 • pod/ingress-nginx-admission-create-... 和 admission-patch-... (状态: Completed 0/1):这是两个初始化任务(Job)。它们的作用是在部署时自动生成 SSL 证书并配置给 API Server,用于验证 Ingress 资源的合法性。它们执行完任务就自动退出了(Completed),这是完全正常的现象,不是报错。 #2. Service(服务)—— 注意外网访问方式 这里有两个 Service,需要特别注意: (1)• service/ingress-nginx-controller (Type: LoadBalancer): ◦ 这是对外提供服务的入口。 ◦ 关键点:EXTERNAL-IP 显示为 <pending>(待定)。因为你的集群是裸机(或非云环境),没有对接云厂商的负载均衡器,所以它无法自动分配公网 IP。 ◦ 但这不影响使用! 注意到后面的 PORT(S) 列显示 80:31282/TCP, 443:30503/TCP。这意味着,虽然外部 IP 没分配,但 NodePort(节点端口)已经生效。你可以通过集群中任意一个节点(Node)的 IP 地址加上 31282(HTTP)或 30503(HTTPS)端口来访问你的服务。 (2)• service/ingress-nginx-controller-admission (Type: ClusterIP): ◦ 这是一个内部服务,仅供 Kubernetes API Server 调用,用于验证你创建的 Ingress 规则是否正确。用户无需关心它。 #3. 工作负载(Deployment 和 ReplicaSet) • deployment.apps/ingress-nginx-controller (1/1):表示你期望运行 1 个控制器实例,目前 1 个正在运行。状态完美。 • replicaset.apps/...:这是 Deployment 自动管理的版本控制器,不需要你手动干预。 #4.两个job.batch是干什么的? 它们是 Admission Webhook(准入控制器) 的部署和配置任务,作用是验证你后续创建的 Ingress 规则是否合法。 简单说:它们是一个 “门卫”,会在你提交 Ingress 资源时自动检查配置,防止你把错误的规则(比如路径格式不对、后端服务不存在)应用到集群里,从而避免 Controller 因解析失败而崩溃。
Ingress 规则实践
Ingress 规则说明
规则示例
-
示例1: 没有rule的Ingress规则
指定一个没有rule的defaultBackend的方式,所有发送给该IP的流量都被转发到了
defaultBackend所列的Kubernetes service上。. 使用场景 全局兜底页面,没有任何域名、路径匹配规则,所有打到 Ingress 入口 IP 的流量,全部转发给 testsvc 服务。 适合:集群统一 404 错误页、单站点极简环境(只有一个网站,不需要区分域名)。
-
访问逻辑 不管你用什么域名、什么路径访问 Ingress 入口 IP: http://10.1.8.40、http://xxx.abc.com、http://10.1.8.40/abc/123 全部转发 testsvc:80。
-
优缺点 优点:最简单,不用配置域名; 缺点:无法区分多个网站,只能单一服务对外。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: test-ingress spec: defaultBackend: service: name: testsvc port: number: 80 -
-
示例2: 虚拟主机,一个域名对应一个path
-
使用场景 集群部署两个完全独立的网站,两个域名分开访问、分开后端: 官网 www.laoma.cloud → 后端服务 www 业务系统 web.laoma.cloud → 后端服务 web
-
访问匹配逻辑 访问 www.laoma.cloud、www.laoma.cloud/xxx:匹配第一条 host,转发 www:80; 访问 web.laoma.cloud、web.laoma.cloud/games:匹配第二条 host,转发 web:80; 访问不存在的域名(如 xxx.laoma.cloud):没有匹配规则,返回 404。 类比传统 Nginx 等同于 Nginx 配置两个server_name虚拟主机,共用同一个 80 端口。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress spec: ingressClassName: nginx rules: - host: www.laoma.cloud http: paths: - path: / pathType: Prefix backend: service: name: www port: number: 80 - host: web.laoma.cloud http: paths: - path: / pathType: Prefix backend: service: name: web port: number: 80 -
示例3: 一个域名对应对多个path
-
使用场景 只有一个域名,但网站拆分为多个模块 / 微服务: 根路径 /:网站首页,由 web 服务提供; /laoma 子路径:后台管理模块,由 laoma 服务提供。
-
访问匹配逻辑 www.laoma.cloud/、www.laoma.cloud/article → 匹配/,转发 web 服务; www.laoma.cloud/laoma、www.laoma.cloud/laoma/user → 匹配/laoma,转发 laoma 服务。 补充匹配规则 路径越长优先级越高,如果同时存在 / 和 /laoma,访问 /laoma 会优先匹配更长的路径,不会走根路径。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress spec: ingressClassName: nginx rules: - host: www.laoma.cloud http: paths: - path: / pathType: Prefix backend: service: name: web port: number: 80 - path: /laoma pathType: Prefix backend: service: name: laoma port: number: 80 -
-
示例4: https 透传(Ingress 不解密,后端自身加密)
如果后端的svc是https流量,系统ingress直接转发https流量给后端service,则需要配置透传 TLS。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myingress annotations: # 开启SSL透传:Ingress不做TLS解密,原始加密包直接转发后端 nginx.ingress.kubernetes.io/ssl-passthrough: "true" # 告诉Ingress:和后端通信使用HTTPS协议,不是默认HTTP nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" spec: ingressClassName: nginx rules: - host: www.laoma.cloud http: paths: - path: / pathType: Prefix backend: service: name: web port: number: 443
配置说明
-
跟Kubernetes的其他配置一样,ingress的配置也需要
apiVersion,kind和metadata字段。 -
Ingress spec 中包含配置一个loadbalancer或proxy server的所有信息。最重要的是,它包含了一个匹配所有入站请求的规则列表。目前ingress只支持http规则。
-
每条http规则包含以下信息:
-
一个
host配置项(比如www.laoma.cloud,默认是*) -
paths列表(比如:/laoma),每个path都关联一个backend,service:port的组合,比如web:80。在loadbalancer将流量转发到backend之前,所有的入站请求都要先匹配host和path。
-
4 套 Ingress 规则选型总结 单服务、不需要区分域名 → 示例 1 defaultBackend; 多个独立网站、不同域名分开部署 → 示例 2 多 Host 虚拟主机; 一个域名、多模块拆分微服务 → 示例 3 单域名多 Path; 后端需要全程加密、双向证书校验 → 示例 4 SSL 透传。
IngressClass
1.作用
集群可装多种网关(nginx-ingress、traefik 等),IngressClass 用来区分、绑定规则和对应的网关。 写 ingressClassName: nginx,这条路由才会交给 nginx 控制器处理。
2.默认类注解 ingressclass.kubernetes.io/is-default-class: "true"
给 nginx 这个 IngressClass 打上默认标记后,写 Ingress 时可以省略 ingressClassName,集群自动交给 nginx 处理,简化 yaml。
路径匹配
Ingress 中的每个路径都需要有对应的路径类型(Path Type)。未明确设置 pathType 的路径无法通过合法性检查。
1. 三种路径类型(Path Type)—— 就好比三种“找东西”的规则
| 类型 | 通俗解释(人话版) | 关键关键词 |
|---|---|---|
| Exact(精确匹配) | 必须一模一样,差一个字符、差一个斜杠都不行。 比如密码解锁,错了就是错了。 | 完全相等、区分大小写 |
| Prefix(前缀匹配) | 只要按 / 分隔开的“文件夹层级”对上了,就算匹配。 只要你进了我这个“根目录”下的这个“大文件夹”,里面的子文件夹我全管。 | 按 / 分段、目录前缀 |
| ImplementationSpecific | “看心情”或“看说明书”。 具体怎么匹配取决于你用的 Ingress 控制器(比如 Nginx 还是其他)。一般不推荐乱用,保持用前两种最安全。 | 视具体实现而定 |
2. 致命细节:什么是“按 / 分隔的元素前缀”(Prefix 的核心)?
这是最容易踩坑的地方!Prefix 不是简单的“字符串开头匹配”!
-
错误理解:
/aaa/bbb能匹配/aaa/bbbxyz(错!因为bbbxyz是一个整体,中间没有/分隔)。 -
正确理解:路径被
/切成了一小块一小块的(比如/aaa/bbb切成["aaa", "bbb"])。匹配时,请求路径的每一块,都必须以规则的对应块作为开头,并且必须是完整的“块”结尾。
举个生活例子: 规则是 /江苏省/南京市(Prefix)。
-
/江苏省/南京市/江宁区✅ 匹配(江宁区是南京市下面的子区,符合)。 -
/江苏省/南京市江宁区❌ 不匹配(因为没有/把“南京市”和“江宁区”隔开,它变成了一个整体地名)。
示例
| 规则路径 | 请求路径 | 匹配? | 为什么(一句话说清) |
|---|---|---|---|
/foo (Exact) | /foo/ | 否 | 多了一个斜杠,不相等。 |
/foo/ (Exact) | /foo | 否 | 少了一个斜杠,不相等。 |
/foo (Prefix) | /foo/ 或 /foo | 是 | 多一个少一个尾部斜杠无所谓,忽略它。 |
/aaa/bbb (Prefix) | /aaa/bbb/ccc | 是 | bbb 后面有 /,ccc 是子级,匹配。 |
/aaa/bbb (Prefix) | /aaa/bbbxyz | 否 | bbb 和 xyz 之间没有 / 分隔,它们是一个词,匹配不上。 |
/ (Prefix) | 任何路径 | 是 | 根目录,代表所有请求都归它管(默认兜底)。 |
多重匹配
在某些情况下,Ingress 中会有多条路径与同一个请求匹配。这时匹配路径最长者优先。 如果仍然有两条同等的匹配路径,则精确路径类型优先于前缀路径类型。
想象一下:你设置了两个规则:/ 和 /api。现在有人访问 /api/user。
-
因为
/是全匹配,/api也匹配。 -
Kubernetes 的处理原则是:谁更“细”谁优先。
-
路径最长者优先:
/api比/长,所以走/api的规则。 -
如果一样长,Exact > Prefix:比如规则是
/foo(Exact) 和/foo(Prefix),请求是/foo,那么 Exact 优先。
-
主机名匹配(Hostname)—— 就像收件地址的门牌号
主机名可以是精确匹配(例如 “foo.bar.com”)或者使用通配符匹配 (例如 “*.foo.com”)
-
精确匹配:
www.example.com。必须完全一致,多一个点少一个点都不行。 -
通配符匹配:
*.example.com。-
注意:这里的
*只能代表一级(一个层级的域名)。 -
bar.example.com✅ 匹配(一层)。 -
foo.bar.example.com❌ 不匹配(这里有foo.bar两层,*只能管一个)。 -
example.com❌ 不匹配(没有点前面的那部分)。
-
精确匹配要求 HTTP host 头部字段与 host 字段值完全匹配。 通配符匹配则要求 HTTP host 头部字段与通配符规则中的后缀部分相同。
| 主机 | host 头部 | 匹配与否? |
|---|---|---|
*.foo.com | bar.foo.com | 基于相同的后缀匹配 |
*.foo.com | baz.bar.foo.com | 不匹配,通配符仅覆盖了一个 DNS 标签 |
*.foo.com | foo.com | 不匹配,通配符仅覆盖了一个 DNS 标签 |
Ingress 规则实践
以下主要讲解生产环境 Ingress-Nginx 常用规则。
整体目标:同一套 Nginx Ingress Controller(同一个入口 IP),通过不同域名区分后端两个业务服务 webapp01、webapp02,实现类似 Nginx 的 server_name 多虚拟主机效果。
环境准备
站点 webapp01
# 创建Deployment [root@master30 ~ 11:25:23]# kubectl create deployment webapp01 --image=docker.io/library/httpd --replicas=2 deployment.apps/webapp01 created # 查看pod标签 [root@master30 ~ 12:01:32]# kubectl get pod -L app NAME READY STATUS RESTARTS AGE APP webapp01-57b8567f7c-jtm2k 1/1 Running 0 11s webapp01 webapp01-57b8567f7c-k24sz 1/1 Running 0 11s webapp01 # 准备pod主页内容 [root@master30 ~ 13:32:25]# kubectl exec -it webapp01-57b8567f7c-jtm2k -- bash -c "echo hello webapp01 pod1 > htdocs/index.html" [root@master30 ~ 13:34:50]# kubectl exec -it webapp01-57b8567f7c-k24sz -- bash -c "echo hello webapp01 pod2 > htdocs/index.html" [root@master30 ~ 13:35:47]# kubectl expose deployment webapp01 --port=80 --target-port=80 service/webapp01 exposed
站点 webapp02
# 创建Deployment [root@master30 ~ 13:36:56]# kubectl create deployment webapp02 --image=docker.io/library/httpd --replicas=2 deployment.apps/webapp02 created # 查看pod标签 [root@master30 ~ 13:38:04]# kubectl get pod | grep webapp02 webapp02-598c447b5b-dpxll 1/1 Running 0 24s webapp02-598c447b5b-tzg99 1/1 Running 0 24s # 准备pod主页内容 #httpd:网页目录 默认在/usr/local/apache2/htdocs/,访问 httpd Pod 的 IP / 域名,Apache 服务会主动去固定目录 /usr/local/apache2/htdocs/ 下寻找资源响应请求。htdocs目录下有文件→输出内容,有多个文件时返回第一个文件的内容;有文件夹无 index.html→403,有文件夹 + 内部存在 index.html 文件,返回index.html 中的内容;整个 htdocs 文件夹丢失→404 [root@master30 ~ 13:39:50]# kubectl exec -it webapp02-598c447b5b-dpxll -- bash -c "echo hello webapp02 pod1 > htdocs/index.html mkdir htdocs/games echo hello webapp02 game1 > htdocs/games/index.html" [root@master30 ~ 13:40:07]# kubectl exec -it webapp02-598c447b5b-tzg99 -- bash -c "echo hello webapp02 pod2 > htdocs/index.html mkdir htdocs/games echo hello webapp02 game2 > /htdocs/games/index.html" [root@master30 ~ 13:40:45]# kubectl expose deployment webapp02 --port=80 --target-port=80 service/webapp02 exposed
一、基础通用规则
1. 多域名虚拟主机(最常用)
场景:公司有两个业务,webapp01 和 webapp02,都想用 80 端口访问,不想各自开 NodePort。
原理: HTTP 请求头里有个 Host 字段,写着访问的域名。Ingress 收到请求后,看 Host 是啥,就转发给对应的 Service。
比如:
-
请求 Host =
webapp01.zy.cloud→ 转给webapp01:80 -
请求 Host =
webapp02.zy.cloud→ 转给webapp02:80
关键点:
-
ingressClassName: nginx必须写,告诉集群「这条规则交给 nginx 控制器处理」; -
一个 Ingress 里可以写多条
host规则; -
客户端必须把域名解析到 Ingress 的入口 IP(10.1.8.40),不然请求都到不了控制器。
root@master30:~# vim ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
spec:
# 这里一定要指定ingressClassName为nginx
ingressClassName: nginx
rules:
- host: webapp01.zy.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
- host: webapp02.zy.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp02
port:
number: 80
[root@master30 ~ 13:42:09]# kubectl apply -f ingress.yaml
ingress.networking.k8s.io/multi-host-ingress created
[root@master30 ~ 15:08:51]# kubectl describe ingress multi-host-ingress
Name: multi-host-ingress
Labels: <none>
Namespace: ingress
Address: 10.1.8.40 #!!!!!!只有配置过Matellb才会出现地址,没配置则没有(前面的kubernetes Service 知识里面的LoadBalancer这一节配置了)
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
webapp01.zy.cloud
/ webapp01:80 (10.224.170.34:80,10.224.215.140:80)
webapp02.zy.cloud
/ webapp02:80 (10.224.170.10:80,10.224.215.176:80)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 3m16s (x2 over 4m1s) nginx-ingress-controller Scheduled for sync
访问验证
# 修改www.laoma.cloud解析,确保客户端能解析该名称 # 如果有多个域名,建议使用配置DNS-wild匹配 [root@master30 ~ 15:08:55]# echo '10.1.8.40 webapp01.zy.cloud' >> /etc/hosts [root@master30 ~ 15:09:37]# echo '10.1.8.40 webapp02.zy.cloud' >> /etc/hosts # 注意: 这里我们直接访问域名,没有加端口号 [root@master30 ~ 15:08:55]# echo '10.1.8.40 webapp01.zy.cloud' >> /etc/hosts [root@master30 ~ 15:09:37]# echo '10.1.8.40 webapp02.zy.cloud' >> /etc/hosts [root@master30 ~ 15:53:14]# curl webapp01.zy.cloud hello webapp01 pod1 [root@master30 ~ 16:13:15]# curl webapp01.zy.cloud hello webapp01 pod1 [root@master30 ~ 16:13:15]# curl webapp01.zy.cloud hello webapp02 pod2 [root@master30 ~ 16:13:16]# curl webapp01.zy.cloud hello webapp01 pod1 [root@master30 ~ 16:13:17]# curl webapp01.zy.cloud hello webapp02 pod2 [root@master30 ~ 16:13:17]# curl webapp01.zy.cloud hello webapp01 pod1 [root@master30 ~ 16:13:18]# curl webapp01.zy.cloud hello webapp02 pod2
删除 ingress
root@master30:~# kubectl delete ingress multi-host-ingress
2. 同一域名多路径分流
场景:就一个域名 www.zy.cloud,根路径 / 走首页,/games 走游戏页,两个页面由不同后端服务提供。
原理: 在同一个 Host 下,根据 URL 路径匹配,转发给不同 Service。
-
访问
www.zy.cloud/→ webapp01 -
访问
www.zy.cloud/games/xxx→ webapp02
root@master30:~# vim ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-path-ingress
spec:
ingressClassName: nginx
rules:
- host: www.zy.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
- path: /games
pathType: Prefix
backend:
service:
name: webapp02
port:
number: 80
[root@master30 ~ 16:15:28]# kubectl apply -f ingress.yaml
ingress.networking.k8s.io/multi-path-ingress created
[root@master30 ~ 16:15:39]# kubectl describe ingress multi-path-ingress
Name: multi-path-ingress
Labels: <none>
Namespace: ingress
Address: 10.1.8.40
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
www.zy.cloud
/ webapp01:80 (10.224.170.34:80,10.224.215.140:80)
/games webapp02:80 (10.224.170.10:80,10.224.215.176:80)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 17s (x2 over 17s) nginx-ingress-controller Scheduled for sync
访问验证
# 修改www.laoma.cloud解析,确保客户端能解析该名称 # 如果有多个域名,建议使用配置DNS-wild匹配 [root@master30 ~ 16:21:26]# echo '10.1.8.40 www.zy.cloud' >> /etc/hosts # 注意: 这里我们直接访问域名,没有加端口号 [root@master30 ~ 16:29:20]# curl www.zy.cloud hello webapp01 pod1 [root@master30 ~ 16:29:28]# curl www.zy.cloud hello webapp01 pod2 [root@master30 ~ 16:29:28]# curl www.zy.cloud hello webapp01 pod1 [root@master30 ~ 16:29:29]# curl www.zy.cloud hello webapp01 pod1 [root@master30 ~ 16:29:55]# curl www.zy.cloud/games/ hello webapp02 game1 [root@master30 ~ 16:29:56]# curl www.zy.cloud/games/ hello webapp02 game2 [root@master30 ~ 16:29:56]# curl www.zy.cloud/games/ hello webapp02 game1 [root@master30 ~ 16:29:57]# curl www.zy.cloud/games/ hello webapp02 game2
删除 ingress
[root@master30 ~ 16:29:57]# kubectl delete ingress multi-path-ingress ingress.networking.k8s.io "multi-path-ingress" deleted
二、生产核心:路径重写
为什么需要重写?
痛点:前端访问地址是 /webapp01/index.html,但后端服务的根目录是 /,它不认识 /webapp01 这个前缀,直接转发会返回 404。
怎么解决?
用 rewrite-target 注解:把路径里的前缀裁掉,再转发给后端。
路径裁剪(等价 Nginx proxy_pass /)
场景:前端访问 /api/xxx,后端实际只识别 /xxx,剥离 /api 前缀
[root@master30 ~ 16:34:45]# vim ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-path-ingress
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx
rules:
- host: www.zy.cloud
http:
paths:
- path: /webapp01/(.*)
pathType: ImplementationSpecific
backend:
service:
name: webapp01
port:
number: 80
- path: /webapp02/(.*)
pathType: ImplementationSpecific
backend:
service:
name: webapp02
port:
number: 80
[root@master30 ~ 16:58:30]# kubectl apply -f ingress.yaml
ingress.networking.k8s.io/multi-path-ingress created
[root@master30 ~ 16:58:36]# kubectl describe ingress multi-path-ingress
Name: multi-path-ingress
Labels: <none>
Namespace: ingress
Address: 10.1.8.40
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
www.zy.cloud
/webapp01/(.*) webapp01:80 (10.224.170.34:80,10.224.215.140:80)
/webapp02/(.*) webapp02:80 (10.224.170.10:80,10.224.215.176:80)
Annotations: nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: true
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 2s (x2 over 5s) nginx-ingress-controller Scheduled for sync
访问验证
root@master30 ~ 16:58:41]# curl www.zy.cloud/webapp01/ hello webapp01 pod1 [root@master30 ~ 16:59:29]# curl www.zy.cloud/webapp01/ hello webapp01 pod2 [root@master30 ~ 16:59:32]# curl www.zy.cloud/webapp01/ hello webapp01 pod1 [root@master30 ~ 16:59:55]# curl www.zy.cloud/webapp02/ hello webapp02 pod1 [root@master30 ~ 17:00:00]# curl www.zy.cloud/webapp02/ hello webapp02 pod2 [root@master30 ~ 17:00:01]# curl www.zy.cloud/webapp02/ hello webapp02 pod1 [root@master30 ~ 17:00:01]# curl www.zy.cloud/webapp02/ hello webapp02 pod2 #可以进一步验证: [root@master30 ~ 17:00:03]# curl www.zy.cloud/webapp02/games/ hello webapp02 game1 [root@master30 ~ 17:10:49]# curl www.zy.cloud/webapp02/games/ hello webapp02 game2 [root@master30 ~ 17:10:54]# curl www.zy.cloud/webapp02/games/ hello webapp02 game2 [root@master30 ~ 17:10:57]# curl www.zy.cloud/webapp01/index.html hello webapp01 pod2 [root@master30 ~ 17:11:06]# curl www.zy.cloud/webapp01/index.html hello webapp01 pod2 [root@master30 ~ 17:11:06]# curl www.zy.cloud/webapp01/index.html hello webapp01 pod1
原理:Nginx 路径重写(魔法核心)
你配置的 rewrite-target: /$1 是关键!
它会自动裁剪掉前缀 /webapp01/、/webapp02/,只把后面的路径转发给 Pod:
| 你访问的地址 | 重写后真实传给 Pod 的路径 | 访问结果 |
|---|---|---|
/webapp01/ | / | 访问 Pod 根目录 |
/webapp01/index.html | /index.html | 访问首页文件 |
/webapp02/ | / | 访问 webapp02 根目录 |
/webapp02/games/ | /games/ | 访问游戏子目录 |
❌ 如果不加重写:
请求路径会原封不动传给 Pod,Pod 里没有 /webapp01 文件夹 → 直接报 404 Not Found。
删除 ingress
root@master30:~# kubectl delete ingress multi-path-ingress
三、HTTPS 强制 & TLS 证书
为什么要 TLS?
HTTP 是明文传输,容易被窃听篡改;HTTPS 用证书加密,保证传输安全。
K8s 里怎么用?
-
先生成证书(生产环境买正规证书,实验用自签);
-
把证书存到
Secret里(K8s 专门存敏感数据的资源); -
Ingress 里引用这个 Secret,控制器就会把证书加载到 Nginx 里。
强制 HTTPS
加两个注解,访问 80 端口自动 308 跳转到 443,全站加密。
注意:TLS 终止在 Ingress 控制器这一层,控制器到后端 Pod 之间还是明文 HTTP,这是最常用的模式。
环境准备
root@master30:~# openssl genrsa -out www.key 2048 root@master30:~# openssl req -new -key www.key -out www.csr -subj "/C=CN/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=www.laoma.cloud/emailAddress=webadmin@laoma.cloud" root@master30:~# openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt root@master30:~# kubectl create secret tls www-tls --cert=./www.crt --key=./www.key
生产标配:80 自动跳转 443,加密访问
root@master30:~# vim ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- www.laoma.cloud
secretName: www-tls
rules:
- host: www.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
root@master30:~# kubectl apply -f ingress.yaml
root@master30:~# kubectl describe ingress tls-ingress
Name: tls-ingress
Labels: <none>
Namespace: ingress
Address:
Ingress Class: nginx
Default backend: <default>
TLS:
www-tls terminates www.laoma.cloud
Rules:
Host Path Backends
---- ---- --------
www.laoma.cloud
/ webapp01:80 (10.224.19.54:80,10.224.19.56:80)
Annotations: nginx.ingress.kubernetes.io/force-ssl-redirect: true
nginx.ingress.kubernetes.io/ssl-redirect: true
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 11s nginx-ingress-controller Scheduled for sync
访问验证
# 使用 -L 跟随 301/302/307/308 所有重定向 [root@client ~]# curl -Lk http://www.laoma.cloud/ hello webapp01 pod1 [root@client ~]# curl -Lk http://www.laoma.cloud/ hello webapp01 pod2 # 访问https站点 [root@client ~]# curl -k https://www.laoma.cloud/ hello webapp01 pod1 [root@client ~]# curl -k https://www.laoma.cloud/ hello webapp01 pod2
删除 ingress
root@master30:~# kubectl delete ingress tls-ingress
四、限流、防刷、超时优化
5. 连接数限流、单IP限速
annotations: # 单IP最大并发连接 nginx.ingress.kubernetes.io/limit-connections: "50" # 单IP每秒请求数 nginx.ingress.kubernetes.io/limit-rps: "20"
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"
五、跨域配置(前后端分离必备)
7. 全局跨域放行
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. 限制指定IP段访问
场景:管理后台、内部系统,只允许公司内网IP
annotations: # 只放行 10.1.8.0/24 网段 nginx.ingress.kubernetes.io/whitelist-source-range: "10.1.8.0/24,127.0.0.1/32"
七、静态资源缓存、请求头透传
9. 透传真实客户端IP
annotations: nginx.ingress.kubernetes.io/x-forwarded-for: "true" nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "10.0.0.0/8"
10. 静态资源缓存优化
annotations: nginx.ingress.kubernetes.io/proxy-cache: "true" nginx.ingress.kubernetes.io/proxy-cache-valid: "200 302 10m"
八、灰度 / 权重分流(金丝雀发布)
11. 权重流量拆分
场景:线上灰度,90%流量走稳定版,10%走测试版
annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "10"
九、错误页面、自定义配置
12. 自定义后端错误页、关闭目录浏览
annotations: nginx.ingress.kubernetes.io/custom-http-errors: "404,500,502,503"
十、生产高频注解 速查表
| 注解 | 作用 |
|---|---|
force-ssl-redirect: true | 80 强制跳转 HTTPS |
rewrite-target | 路径重写、裁剪路由前缀 |
whitelist-source-range | IP白名单 |
limit-rps / limit-connections | 防CC、限流 |
enable-cors | 前后端跨域 |
proxy-read-timeout | 解决接口超时断开 |
x-forwarded-for | 后端获取真实客户端IP |
环境清理
root@master30:~# kubectl delete ns ingress
更多推荐
所有评论(0)