从零吃透 K8s 网络:ServiceIngressMetalLB 实操手册

Kubernetes Service

学习参考:Service

环境准备

bash 复制代码
root@master30 ~ 10:20:01# kubectl create ns services
root@master30 ~ 10:20:05# kubectl config set-context --current --namespace services

Service 类型

Kubernetes Service 共支持五类服务类型:

  • ClusterIP:仅允许集群内部发起访问。
  • NodePort:依托物理节点开放端口实现访问,集群内所有节点会复用同一个端口号。
  • LoadBalancer:提供负载均衡能力,绑定独立的物理网段外网 IP。
  • ExternalName:用于配置集群内部域名 CNAME 解析记录。
  • Headless:仅提供服务域名,不会分配独立集群 IP。

若业务应用需要将服务暴露至集群外部访问,Kubernetes 提供两种实现方案:NodePort 与 LoadBalancer。

环境准备

创建 Deployment 资源

bash 复制代码
root@master30 ~ 10:20:06# kubectl create deployment web --image=hub.laoma.cloud/library/httpd --replicas=2
deployment.apps/web created

ClusterIP

ClusterIP 会分配集群内部专用 IP 对外暴露服务,采用该类型时服务仅能在集群内部访问,同时这也是 Service 的默认类型。

  • ClusterIP 的 IP 地址从集群预留的专用地址段中分配,其余几类 Service 均基于 ClusterIP 底层能力拓展实现。
  • 创建 Service 时,可通过 .spec.clusterIP 字段手动指定自定义集群 IP;若将该字段值设为 "None",Kubernetes 将不再为此服务分配集群 IP。
  • 自定义的 IP 地址必须为合法 IPv4/IPv6 地址,且归属 API 服务配置的 service-cluster-ip-range 网段。若填写非法集群 IP,API 服务会返回 422 状态码提示参数不合法。

更多细节可参考前文「服务发现」相关章节。

NodePort

  1. 若将 Service 的 type 字段设置为 NodePort,Kubernetes 控制平面会从 --service-node-port-range 参数划定的端口区间自动分配端口(默认区间:30000-32767 ),分配完成后端口号会记录在 .spec.ports[*].nodePort 字段中。
  2. NodePort 类型服务会借助集群所有节点的 IP 与分配端口对外提供访问入口;为保证节点端口可正常转发流量,Kubernetes 会同步为该服务分配 ClusterIP,集群全部节点都会监听该统一端口,并将接收的请求转发至对应 Service。

实操示例:

bash 复制代码
root@master30 ~ 10:20:16# kubectl expose deployment web --type NodePort --port=8080 --target-port=80 -o yaml --dry-run=client > service-NodePort.yaml
root@master30 ~ 10:20:25# vim service-NodePort.yaml
bash 复制代码
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 80
  selector:
    app: web
  type: NodePort
status:
  loadBalancer: {}
bash 复制代码
# 创建NodePort类型Service
root@master30 ~ 10:20:32# kubectl apply -f service-NodePort.yaml
service/web created
# 查看节点分配的对外端口31917
root@master30 ~ 10:20:39#  kubectl get service
NAME   TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
web    NodePort   10.100.38.69   <none>        8080:30389/TCP   7s
# 参数说明:
# 1. EXTERNAL-IP 显示为<none>,代表可通过集群任意节点的物理IP访问当前服务。
# 2. PORT(S) 字段格式为8080:31917:8080是ClusterIP监听端口,31917是宿主机节点监听端口。
#    Kubernetes 会从30000~32767区间选取空闲端口,集群所有节点统一监听该端口并转发请求至Service
# 访问集群任意节点完成连通性测试
root@master30 ~ 10:20:46# curl http://10.1.8.30:30389
<html><body><h1>It works!</h1></body></html>
root@master30 ~ 10:20:59# curl http://10.1.8.31:30389
<html><body><h1>It works!</h1></body></html>
root@master30 ~ 10:21:03# curl http://10.1.8.32:30389
<html><body><h1>It works!</h1></body></html>

内核防火墙转发规则解析:

bash 复制代码
root@master30 ~ 10:21:35# iptables-save |grep 30389
-A KUBE-NODEPORTS -p tcp -m comment --comment "services/web" -m tcp --dport 30389 -j KUBE-EXT-7D76YWGERGEPC4GC
root@master30 ~ 10:21:56# iptables-save |grep KUBE-EXT-7D76YWGERGEPC4GC
:KUBE-EXT-7D76YWGERGEPC4GC - [0:0]
-A KUBE-EXT-7D76YWGERGEPC4GC -m comment --comment "masquerade traffic for services/web external destinations" -j KUBE-MARK-MASQ
-A KUBE-EXT-7D76YWGERGEPC4GC -j KUBE-SVC-7D76YWGERGEPC4GC
-A KUBE-NODEPORTS -p tcp -m comment --comment "services/web" -m tcp --dport 30389 -j KUBE-EXT-7D76YWGERGEPC4GC
root@master30 ~ 10:22:15# iptables-save |grep KUBE-SVC-7D76YWGERGEPC4GC
:KUBE-SVC-7D76YWGERGEPC4GC - [0:0]
-A KUBE-EXT-7D76YWGERGEPC4GC -j KUBE-SVC-7D76YWGERGEPC4GC
-A KUBE-SERVICES -d 10.100.38.69/32 -p tcp -m comment --comment "services/web cluster IP" -m tcp --dport 8080 -j KUBE-SVC-7D76YWGERGEPC4GC
-A KUBE-SVC-7D76YWGERGEPC4GC ! -s 10.224.0.0/16 -d 10.100.38.69/32 -p tcp -m comment --comment "services/web cluster IP" -m tcp --dport 8080 -j KUBE-MARK-MASQ
-A KUBE-SVC-7D76YWGERGEPC4GC -m comment --comment "services/web -> 10.224.133.122:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-6KP5PMO4XMNPF6TB
-A KUBE-SVC-7D76YWGERGEPC4GC -m comment --comment "services/web -> 10.224.218.136:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-554EDXQBQCQ25NV6
-A KUBE-SVC-7D76YWGERGEPC4GC -m comment --comment "services/web -> 10.224.218.161:80" -j KUBE-SEP-Z2E2SH65MYX7M5GX
root@master30 ~ 10:22:32# iptables-save |grep KUBE-SEP-Z2E2SH65MYX7M5GX
:KUBE-SEP-Z2E2SH65MYX7M5GX - [0:0]
-A KUBE-SEP-Z2E2SH65MYX7M5GX -s 10.224.218.161/32 -m comment --comment "services/web" -j KUBE-MARK-MASQ
-A KUBE-SEP-Z2E2SH65MYX7M5GX -p tcp -m comment --comment "services/web" -m tcp -j DNAT --to-destination 10.224.218.161:80
-A KUBE-SVC-7D76YWGERGEPC4GC -m comment --comment "services/web -> 10.224.218.161:80" -j KUBE-SEP-Z2E2SH65MYX7M5GX

NodePort 默认自动随机分配端口,也可通过 nodePort 字段手动指定固定端口。

bash 复制代码
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 8080
    protocol: TCP
    # 手动指定宿主机固定监听端口
    nodePort: 30080
    targetPort: 80
  selector:
    app: web
  type: NodePort
status:
  loadBalancer: {}

端口字段释义:

  • nodePort:宿主机节点对外开放的监听端口。
  • port:ClusterIP 集群内部监听端口。
  • targetPort:后端 Pod 内部业务容器监听端口。

资源清理

bash 复制代码
root@master30 ~ 10:42:42# kubectl delete svc web 
service "web" deleted

LoadBalancer

Kubernetes 原生并未内置负载均衡实现,需要借助第三方组件完成,典型方案为 MetalLB。

每一个 LoadBalancer 类型 Service 都会分配独立的外网 IP,仅需将 Service 的 type 字段修改为 LoadBalancer 即可创建该类型服务。

下文将基于 MetalLB 演示完整部署流程。

官方文档地址: https://metallb.universe.tf/

GitHub 开源地址:https://github.com/metallb/metallb

部署 MetalLB
bash 复制代码
root@master30 ~ 10:46:08#  wget http://192.168.46.200/class/course-materials/softwares/stage03/metallb-0.14.8.tar.gz
--2026-08-11 11:10:51--  http://192.168.46.200/class/course-materials/softwares/stage03/metallb-0.14.8.tar.gz
Connecting to 192.168.46.200:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14835368 (14M) [application/octet-stream]
Saving to: 'metallb-0.14.8.tar.gz'
metallb-0.14.8.tar.gz  100%[=========================>]  14.15M  3.24MB/s    in 4.4s    
2026-08-11 11:10:55 (3.24 MB/s) - 'metallb-0.14.8.tar.gz' saved [14835368/14835368]
root@master30 ~ 11:10:55# tar -xf metallb-0.14.8.tar.gz 
# 查看镜像配置
root@master30 ~ 11:11:04# grep image metallb-0.14.8/config/manifests/metallb-native.yaml         image: quay.io/metallb/controller:v0.14.8
        image: quay.io/metallb/speaker:v0.14.8
# 根据内网镜像仓库替换镜像地址
root@master30 ~ 11:11:25# sed -i 's/quay.io/hub.laoma.cloud/g' metallb-0.14.8/config/manifests/metallb-native.yaml
root@master30 ~ 11:11:35# kubectl apply -f  metallb-0.14.8/config/manifests/metallb-native.yaml 
namespace/metallb-system created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
...
# 等待全部Pod进入正常运行状态后再执行后续操作
root@master30 ~ 11:12:25# kubectl get all -n metallb-system 
NAME                             READY   STATUS    RESTARTS   AGE
pod/controller-d6499775f-48q5x   1/1     Running   0          32s
pod/speaker-4tv4k                1/1     Running   0          32s
pod/speaker-j8l97                1/1     Running   0          32s
pod/speaker-q6xsq                1/1     Running   0          32s
NAME                              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/metallb-webhook-service   ClusterIP   10.107.23.110   <none>        443/TCP   32s
NAME                     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/speaker   3         3         3       3            3           kubernetes.io/os=linux   32s
NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   1/1     1            1           32s
NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-d6499775f   1         1         1       32s

配置 IP 地址分配池

bash 复制代码
root@master30 ~ 11:12:35# cat << 'EOF' > ippool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 10.1.8.40-10.1.8.80
EOF
root@master30 ~ 11:12:51# kubectl apply -f ippool.yaml 
ipaddresspool.metallb.io/first-pool created

配置二层广播宣告模式

bash 复制代码
root@master30 ~ 11:12:58# cat << 'EOF' > L2.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system
EOF
root@master30 ~ 11:13:11# kubectl apply -f L2.yaml 
功能验证
bash 复制代码
root@master30 ~ 11:13:22#  kubectl expose deployment web --type LoadBalancer --port=80 --target-port=80 -o yaml --dry-run=client > service-LoadBalancer.yaml 
root@master30 ~ 11:13:59# cat service-LoadBalancer.yaml 
bash 复制代码
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
  type: LoadBalancer
status:
  loadBalancer: {}
bash 复制代码
root@master30 ~ 11:14:07# kubectl apply -f service-LoadBalancer.yaml 
service/web created
root@master30 ~ 11:14:21# kubectl get service
NAME   TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
web    LoadBalancer   10.97.78.201   10.1.8.40     80:32306/TCP   6s
# 访问测试需使用Service暴露的80端口,而非节点分配的32101端口
root@master30 ~ 11:14:27# curl -s http://10.1.8.40:80
<html><body><h1>It works!</h1></body></html>
核心总结
  • 客户端流量完整转发链路:用户请求 → MetalLB 虚拟负载均衡 IP → 节点 kube-proxy 组件 → Service 负载均衡调度 → 后端业务 Pod。
  • ✅ MetalLB 仅负责 ARP 广播宣告与 IP 地址占用,实际流量转发逻辑完全依赖 kube-proxy 与 Service 机制实现。
  • MetalLB 搭配 LoadBalancer 类型 Service 是 Kubernetes 集群标准负载均衡落地方案。
完整流量流程图

访问 LB VIP:10.1.8.40
客户端用户
ARP 寻址 → 流量进入集群任意节点
节点内核拦截 Service IP 流量
kube-proxy 处理 iptables/IPVS 规则
Service 负载均衡:选择一个健康 Pod
通过 CNI 网络转发到 Pod 所在节点
流量进入 Pod 网络命名空间
目标 Pod 接收并响应请求

#mermaid-svg-4nxKIKAjpQGPpK4J{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4nxKIKAjpQGPpK4J .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4nxKIKAjpQGPpK4J .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4nxKIKAjpQGPpK4J .error-icon{fill:#552222;}#mermaid-svg-4nxKIKAjpQGPpK4J .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4nxKIKAjpQGPpK4J .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4nxKIKAjpQGPpK4J .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4nxKIKAjpQGPpK4J .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4nxKIKAjpQGPpK4J .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4nxKIKAjpQGPpK4J .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4nxKIKAjpQGPpK4J .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4nxKIKAjpQGPpK4J .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4nxKIKAjpQGPpK4J .marker.cross{stroke:#333333;}#mermaid-svg-4nxKIKAjpQGPpK4J svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4nxKIKAjpQGPpK4J p{margin:0;}#mermaid-svg-4nxKIKAjpQGPpK4J .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4nxKIKAjpQGPpK4J .cluster-label text{fill:#333;}#mermaid-svg-4nxKIKAjpQGPpK4J .cluster-label span{color:#333;}#mermaid-svg-4nxKIKAjpQGPpK4J .cluster-label span p{background-color:transparent;}#mermaid-svg-4nxKIKAjpQGPpK4J .label text,#mermaid-svg-4nxKIKAjpQGPpK4J span{fill:#333;color:#333;}#mermaid-svg-4nxKIKAjpQGPpK4J .node rect,#mermaid-svg-4nxKIKAjpQGPpK4J .node circle,#mermaid-svg-4nxKIKAjpQGPpK4J .node ellipse,#mermaid-svg-4nxKIKAjpQGPpK4J .node polygon,#mermaid-svg-4nxKIKAjpQGPpK4J .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4nxKIKAjpQGPpK4J .rough-node .label text,#mermaid-svg-4nxKIKAjpQGPpK4J .node .label text,#mermaid-svg-4nxKIKAjpQGPpK4J .image-shape .label,#mermaid-svg-4nxKIKAjpQGPpK4J .icon-shape .label{text-anchor:middle;}#mermaid-svg-4nxKIKAjpQGPpK4J .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4nxKIKAjpQGPpK4J .rough-node .label,#mermaid-svg-4nxKIKAjpQGPpK4J .node .label,#mermaid-svg-4nxKIKAjpQGPpK4J .image-shape .label,#mermaid-svg-4nxKIKAjpQGPpK4J .icon-shape .label{text-align:center;}#mermaid-svg-4nxKIKAjpQGPpK4J .node.clickable{cursor:pointer;}#mermaid-svg-4nxKIKAjpQGPpK4J .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4nxKIKAjpQGPpK4J .arrowheadPath{fill:#333333;}#mermaid-svg-4nxKIKAjpQGPpK4J .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4nxKIKAjpQGPpK4J .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4nxKIKAjpQGPpK4J .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4nxKIKAjpQGPpK4J .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4nxKIKAjpQGPpK4J .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4nxKIKAjpQGPpK4J .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4nxKIKAjpQGPpK4J .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4nxKIKAjpQGPpK4J .cluster text{fill:#333;}#mermaid-svg-4nxKIKAjpQGPpK4J .cluster span{color:#333;}#mermaid-svg-4nxKIKAjpQGPpK4J div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4nxKIKAjpQGPpK4J .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4nxKIKAjpQGPpK4J rect.text{fill:none;stroke-width:0;}#mermaid-svg-4nxKIKAjpQGPpK4J .icon-shape,#mermaid-svg-4nxKIKAjpQGPpK4J .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4nxKIKAjpQGPpK4J .icon-shape p,#mermaid-svg-4nxKIKAjpQGPpK4J .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4nxKIKAjpQGPpK4J .icon-shape .label rect,#mermaid-svg-4nxKIKAjpQGPpK4J .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4nxKIKAjpQGPpK4J .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4nxKIKAjpQGPpK4J .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4nxKIKAjpQGPpK4J :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 访问 LB VIP:10.1.8.40
客户端用户
ARP 寻址 → 流量进入集群任意节点
节点内核拦截 Service IP 流量
kube-proxy 处理 iptables/IPVS 规则
Service 负载均衡:选择一个健康 Pod
通过 CNI 网络转发到 Pod 所在节点
流量进入 Pod 网络命名空间
目标 Pod 接收并响应请求

访问 LB VIP:10.1.8.40
客户端用户
ARP 寻址 → 流量进入集群任意节点
节点内核拦截 Service IP 流量
kube-proxy 处理 iptables/IPVS 规则
Service 负载均衡:选择一个健康 Pod
通过 CNI 网络转发到 Pod 所在节点
流量进入 Pod 网络命名空间
目标 Pod 接收并响应请求

  1. 客户端发起访问:用户通过浏览器或业务程序访问 MetalLB 分配的负载均衡虚拟 IP(示例:10.1.8.200)。
  2. ARP 寻址转发流量至集群节点:MetalLB 工作在二层模式,通过 ARP 广播声明虚拟 IP 归属,客户端流量会转发至集群任意一台节点。
  3. 节点内核捕获目标流量:宿主机内核识别访问目标为负载均衡 IP,将流量交由内核网络子系统处理。
  4. kube-proxy 匹配转发规则:kube-proxy 匹配内核中预生成的 iptables/IPVS 转发规则,定位流量归属的 Service 资源。
  5. Service 完成负载均衡调度:从 Service 绑定的就绪端点列表中,按预设调度策略选择一台健康后端 Pod。
  6. CNI 插件跨节点转发:若目标 Pod 不在当前接收流量的节点,流量将通过 Calico、Flannel 等 CNI 网络插件跨节点传输。
  7. 流量送入 Pod 网络命名空间:目标节点通过 veth-pair 虚拟网卡设备,将流量转发至 Pod 独立网络命名空间。
  8. 业务 Pod 处理并返回响应:容器内业务程序接收请求处理后,沿原链路将响应数据返回客户端。

ExternalName

ExternalName 类型服务用于将集群内服务映射至外部域名,映射逻辑由 externalName 字段定义(示例域名:api.foo.bar.example)。该配置会修改集群 DNS 解析,对外返回对应外部域名的 CNAME 解析记录,集群不会为此服务创建任何流量代理转发规则。

示例:将 prod 命名空间下 my-service 服务映射至外部数据库域名database.example.com

bash 复制代码
apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: database.example.com

当程序解析域名 my-service.prod.svc.cluster.local 时,集群 DNS 会返回一条 CNAME 记录,指向 database.example.com。访问该服务的调用方式与常规 Service 完全一致,核心差异在于域名重定向逻辑由 DNS 解析层完成,不存在内核代理转发流程。

Headless Services

部分业务场景无需负载均衡能力,也不需要分配独立集群 IP,此时可通过将 ClusterIP 显式设置为 None 创建无头服务(Headless Service)

无头服务不会分配集群 IP,kube-proxy 不会为其生成转发规则,集群也不会提供负载均衡与路由转发能力。

DNS 解析规则会根据 Service 是否配置标签选择器分为两种逻辑:

  • 配置标签选择器的无头服务:Kubernetes 控制平面会在 API 中生成 EndpointSlice 资源,并修改集群 DNS 配置,直接返回后端 Pod 对应的 IPv4/A 或 IPv6/AAAA 解析记录。

  • 未配置标签选择器的无头服务

    :控制平面不会创建 EndpointSlice 资源,集群 DNS 执行逻辑区分两种场景:

    • 若服务类型为 type: ExternalName,生成对应 CNAME 解析记录;

    • 其余服务类型,会读取服务就绪端点的全部 IP 并生成 A/AAAA 解析记录(IPv4 生成 A 记录,IPv6 生成 AAAA 记录)。

      定义无选择器的无头服务时,port 端口值必须与 targetPort完全一致。

Service 会话保持

会话保持基础介绍

若需要保证同一客户端的全部请求始终转发至同一台后端 Pod,可将 Service 的 .spec.sessionAffinity 字段设置为 ClientIP,开启基于客户端源 IP 的会话粘性,默认配置为 None(关闭会话保持)。

同时可通过 .spec.sessionAffinityConfig.clientIP.timeoutSeconds 配置会话粘性的最大超时时间,默认值 10800 秒(3 小时)。

底层工作逻辑:

  1. 客户端首次发起服务访问时,Service 将请求转发至某一台 Pod,并记录客户端 IP 与目标 Pod 的绑定关系。
  2. 该客户端后续所有请求,都会匹配绑定记录转发至同一台 Pod。

该特性更适配有状态业务场景(如 Java Web 应用、WebSocket 长连接、游戏服务端),典型收益:

  • 用户登录会话状态不会丢失
  • 购物车数据保持一致
  • 长连接链路稳定不中断

测试环境准备

bash 复制代码
root@master30 ~ 11:14:48# kubectl create deployment web --image=hub.laoma.cloud/library/httpd --replicas=2
root@master30 ~ 11:40:05# kubectl expose deployment web --port 80
root@master30 ~ 11:40:44# for pod in $(kubectl get pods -o name | awk -F/  '{print $2}'); do    kubectl exec -it $pod -- bash -c "echo $pod > htdocs/index.html"; done
root@master30 ~ 11:41:04# kubectl get svc web 
NAME   TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
web    LoadBalancer   10.97.78.201   10.1.8.40     80:32306/TCP   27m
root@master30 ~ 11:41:48# for i in {1..20};do curl -s 10.97.78.201;done|sort |uniq -c
      9 web
     10 web-5885dfff8c-qvfnf
      1 web-5885dfff8c-vmj6r

开启会话保持配置

bash 复制代码
root@master30 ~ 11:42:07# kubectl patch svc web -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/web patched
# 重复访问验证会话粘性效果
root@master30 ~ 11:42:38# for i in {1..20};do curl -s 10.97.78.201;done|sort |uniq -c
     20 web-5885dfff8c-vmj6r

会话保持与 kube-proxy IPVS 模式关联逻辑

1. Service 的 sessionAffinity 配置优先级最高

当 Service 配置 ClientIP 会话粘性时,kube-proxy 会自动启用 IPVS 的 SH 调度算法

  • SH 全称 Source Hashing,即源地址哈希算法
  • 保障同一客户端 IP 的请求固定转发至同一后端 Pod
2. 未配置 sessionAffinity 的默认逻辑

kube-proxy 会采用 IPVS 预设的全局调度算法,可选策略:

  • rr:轮询调度
  • lc:最少连接调度
  • wrr:加权轮询调度

金丝雀发布

学习参考:金丝雀部署

环境初始化:

bash 复制代码
root@master30 ~ 13:26:50# mkdir web
mkdir: cannot create directory 'web': File exists
root@master30 ~ 13:46:25# echo hello nginx 1.28 > web/index28.html
root@master30 ~ 13:46:34# echo hello nginx 1.29 > web/index29.html
root@master30 ~ 13:46:41# kubectl create configmap web --from-file=./web
configmap/web created
root@master30 ~ 13:46:48# kubectl get configmaps web -o yaml |grep ^data -A4
data:
index28.html: |
hello nginx 1.28
index29.html: |
hello nginx 1.29

金丝雀发布用于灰度上线新版本应用,上线过程中保留旧版本服务同时承接部分生产真实流量,可在全量发布前完成新版本稳定性验证。

实操中可借助 track 标签区分应用不同版本:

  1. 稳定线上版本配置 track: stable

    bash 复制代码
    root@master30 ~ 13:46:57# vim webapp-1.28.yaml
    bash 复制代码
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: web
      name: web-28
    spec:
      replicas: 10
      selector:
        matchLabels:
          app: web
          tier: frontend
          track: stable
      template:
        metadata:
          labels:
            app: web
            tier: frontend
            track: stable
        spec:
          containers:
          - image: hub.laoma.cloud/library/nginx:1.28
            name: nginx
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80
            volumeMounts:
            - name: webcontent
              mountPath: "/usr/share/nginx/html"
          volumes:
          - name: webcontent
            configMap:
              name: web
              items:
                - key: index28.html
                  path: index.html
    bash 复制代码
    root@master30 ~ 13:47:23# kubectl apply -f webapp-1.28.yaml 
    deployment.apps/web-28 created
  2. 创建统一接入 Service 资源

    bash 复制代码
    root@master30 ~ 13:47:39# vim webapp-svc.yaml
    bash 复制代码
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: web
      name: web
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: web
        tier: frontend
    bash 复制代码
    root@master30 ~ 13:48:02# kubectl apply -f webapp-svc.yaml 
    service/web configured
    root@master30 ~ 13:48:18# kubectl get svc
    NAME   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    web    ClusterIP   10.97.78.201   <none>        80/TCP    154m
  3. 部署灰度新版本,新版本配置 track: canary

    bash 复制代码
    root@master30 ~ 13:48:26# vim webapp-1.29.yaml
    bash 复制代码
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: web
      name: web-29
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: web
          tier: frontend
          track: canary
      template:
        metadata:
          labels:
            app: web
            tier: frontend
            track: canary
        spec:
          containers:
          - image: hub.laoma.cloud/library/nginx:1.29
            name: nginx
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80
            volumeMounts:
            - name: webcontent
              mountPath: "/usr/share/nginx/html"
          volumes:
          - name: webcontent
            configMap:
              name: web
              items:
                - key: index29.html
                  path: index.html
    bash 复制代码
    root@master30 ~ 13:48:47# kubectl apply -f webapp-1.29.yaml 
    deployment.apps/web-29 created

    验证流量分配比例:

    bash 复制代码
    root@master30 ~ 13:49:09# kubectl scale deployment web-28 --replicas 8
    deployment.apps/web-28 scaled
    root@master30 ~ 13:49:30# kubectl scale deployment web-29 --replicas 2
    deployment.apps/web-29 scaled
    
    root@master30 ~ 13:49:39# for i in {1..50}; do curl -s 10.97.78.201; done | sort -n|uniq -c
         38 hello nginx 1.28
         12 hello nginx 1.29
  4. 总 Pod 数量保持不变,逐步缩减旧版本副本、扩容新版本副本完成全量灰度:

    bash 复制代码
    root@master30 ~ 13:50:09# kubectl scale deployment web-28 --replicas 6
    deployment.apps/web-28 scaled
    root@master30 ~ 13:50:47# kubectl scale deployment web-29 --replicas 4
    deployment.apps/web-29 scaled
    root@master30 ~ 13:50:55# for i in {1..50}; do curl -s 10.97.78.201; done | sort -n|uniq -c
         31 hello nginx 1.28
         19 hello nginx 1.29

环境资源清理

bash 复制代码
root@master30 ~ 13:51:00# kubectl delete ns services

kube-proxy

kube-proxy 是 Kubernetes 集群负责 Pod 网络转发的核心组件,核心职责是实现 Service 服务到后端 Endpoint 业务 Pod 的流量转发与负载均衡调度。

环境准备

bash 复制代码
root@master30 ~ 13:51:05# kubectl create ns services
root@master30 ~ 13:51:10# kubectl config set-context --current --namespace services

工作模式类型

kube-proxy 共提供三类工作模式,对比信息如下:

模式 定位 性能表现 适用业务场景 核心特性
iptables 默认内置模式 中等(服务数量低于 1000) 小规模测试集群、稳定静态环境 依赖内核 netfilter 模块,服务数量增多后规则匹配存在性能损耗
IPVS 生产环境推荐模式 极高(支持十万级服务) 中大型线上生产集群 基于内核 IPVS 模块,底层采用哈希表检索,转发性能大幅优于 iptables
Userspace 废弃兼容模式 性能低下 仅旧版本兼容、临时测试 全部转发逻辑运行在用户态,转发效率极差,K8s 1.25 及以上版本已彻底移除

✅ 线上生产集群强制选用 IPVS 模式,搭配 Calico CNI 网络插件,兼顾转发性能与集群稳定性。

工作模式切换操作

查看当前生效工作模式

bash 复制代码
root@master30 ~ 14:11:14# kubectl get cm -n kube-system kube-proxy -o yaml|grep mode
    mode: ""
# mode字段为空代表未手动指定模式
# 查看kube-proxy容器运行日志确认实际模式
root@master30 ~ 14:17:56# kubectl get pods -n kube-system -l k8s-app=kube-proxy -o name
pod/kube-proxy-dqpfk
pod/kube-proxy-kv6sb
pod/kube-proxy-r57jz
root@master30 ~ 14:18:27# kubectl logs -n kube-system kube-proxy-dqpfk |grep Using
I0811 00:49:00.834031       1 server_linux.go:69] "Using iptables proxy"
I0811 00:49:00.901237       1 server_linux.go:165] "Using iptables Proxier"
# 日志输出"Using iptables proxy",说明当前默认启用iptables转发模式

修改切换工作模式

bash 复制代码
# 步骤1:编辑kube-proxy全局配置ConfigMap
root@master30 ~ 14:18:59# kubectl edit configmaps -n kube-system kube-proxy 
# 找到mode配置项,修改为目标模式(示例切换为ipvs)
....
    metricsBindAddress: ""
    mode: "ipvs"
....
# 步骤2:滚动重启kube-proxy DaemonSet使配置生效
root@master30 ~ 14:19:40# kubectl rollout restart daemonset -n kube-system kube-proxy 
daemonset.apps/kube-proxy restarted
# 步骤3:验证模式切换结果
root@master30 ~ 14:20:33# kubectl get pods -n kube-system -l k8s-app=kube-proxy -o name
pod/kube-proxy-6zffc
pod/kube-proxy-gnssn
pod/kube-proxy-wqp7w
root@master30 ~ 14:21:09# kubectl logs -n kube-system kube-proxy-6zffc | grep Using
I0811 06:20:03.684316       1 server_linux.go:233] "Using ipvs Proxier"
# 日志输出"Using ipvs Proxier",代表IPVS模式已成功启用

IPVS 模式详解

IPVS 转发模式基于 netfilter 回调机制实现,底层数据结构采用哈希表存储转发规则,全部逻辑运行在内核空间。对比 iptables 模式,IPVS 具备更低的流量转发延迟,同步更新转发规则时性能损耗更小,同时可承载更高并发流量。

IPVS 内置多种负载均衡调度算法,适配不同业务需求:

  • rr:轮询调度
  • lc:最少连接调度(优先选择当前活跃连接数最少的后端)
  • dh:目标地址哈希调度
  • sh:源地址哈希调度(用于会话保持)
  • sed:最短预期延迟调度
  • nq:最少队列调度

底层工作原理

kube-proxy 会在宿主机内核中创建 IPVS 虚拟服务实例,并将所有后端业务 Pod 注册为 Real Server 真实服务节点。IPVS 依托哈希表存储转发规则,检索匹配时间复杂度为 O (1)。流量抵达宿主机后,IPVS 根据预设调度算法直接完成转发,规避了 iptables 多层规则链遍历带来的性能开销。

流量通信流程图
#mermaid-svg-gce4lZ4qGE5ZEaqn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gce4lZ4qGE5ZEaqn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gce4lZ4qGE5ZEaqn .error-icon{fill:#552222;}#mermaid-svg-gce4lZ4qGE5ZEaqn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gce4lZ4qGE5ZEaqn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gce4lZ4qGE5ZEaqn .marker.cross{stroke:#333333;}#mermaid-svg-gce4lZ4qGE5ZEaqn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gce4lZ4qGE5ZEaqn p{margin:0;}#mermaid-svg-gce4lZ4qGE5ZEaqn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gce4lZ4qGE5ZEaqn .cluster-label text{fill:#333;}#mermaid-svg-gce4lZ4qGE5ZEaqn .cluster-label span{color:#333;}#mermaid-svg-gce4lZ4qGE5ZEaqn .cluster-label span p{background-color:transparent;}#mermaid-svg-gce4lZ4qGE5ZEaqn .label text,#mermaid-svg-gce4lZ4qGE5ZEaqn span{fill:#333;color:#333;}#mermaid-svg-gce4lZ4qGE5ZEaqn .node rect,#mermaid-svg-gce4lZ4qGE5ZEaqn .node circle,#mermaid-svg-gce4lZ4qGE5ZEaqn .node ellipse,#mermaid-svg-gce4lZ4qGE5ZEaqn .node polygon,#mermaid-svg-gce4lZ4qGE5ZEaqn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gce4lZ4qGE5ZEaqn .rough-node .label text,#mermaid-svg-gce4lZ4qGE5ZEaqn .node .label text,#mermaid-svg-gce4lZ4qGE5ZEaqn .image-shape .label,#mermaid-svg-gce4lZ4qGE5ZEaqn .icon-shape .label{text-anchor:middle;}#mermaid-svg-gce4lZ4qGE5ZEaqn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gce4lZ4qGE5ZEaqn .rough-node .label,#mermaid-svg-gce4lZ4qGE5ZEaqn .node .label,#mermaid-svg-gce4lZ4qGE5ZEaqn .image-shape .label,#mermaid-svg-gce4lZ4qGE5ZEaqn .icon-shape .label{text-align:center;}#mermaid-svg-gce4lZ4qGE5ZEaqn .node.clickable{cursor:pointer;}#mermaid-svg-gce4lZ4qGE5ZEaqn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gce4lZ4qGE5ZEaqn .arrowheadPath{fill:#333333;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gce4lZ4qGE5ZEaqn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gce4lZ4qGE5ZEaqn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gce4lZ4qGE5ZEaqn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gce4lZ4qGE5ZEaqn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gce4lZ4qGE5ZEaqn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gce4lZ4qGE5ZEaqn .cluster text{fill:#333;}#mermaid-svg-gce4lZ4qGE5ZEaqn .cluster span{color:#333;}#mermaid-svg-gce4lZ4qGE5ZEaqn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gce4lZ4qGE5ZEaqn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gce4lZ4qGE5ZEaqn rect.text{fill:none;stroke-width:0;}#mermaid-svg-gce4lZ4qGE5ZEaqn .icon-shape,#mermaid-svg-gce4lZ4qGE5ZEaqn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gce4lZ4qGE5ZEaqn .icon-shape p,#mermaid-svg-gce4lZ4qGE5ZEaqn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gce4lZ4qGE5ZEaqn .icon-shape .label rect,#mermaid-svg-gce4lZ4qGE5ZEaqn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gce4lZ4qGE5ZEaqn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gce4lZ4qGE5ZEaqn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gce4lZ4qGE5ZEaqn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 访问 Service IP:Port
哈希查找+调度算法
直接路由/隧道
客户端 Pod
宿主机网卡
内核 IPVS 虚拟服务器
选择最优后端 Pod
后端 Pod IP:Port
响应流量直接返回

IPVS 模式核心优势

  • 支持多种精细化调度算法,包含轮询、加权轮询、最少连接等策略。
  • 转发性能不受集群服务总量影响,可稳定支撑十万级 Service 规模。
  • 内置端点健康检测机制,与 Kubernetes Endpoint 资源状态实时联动。

原理实操验证

前置环境要求
  1. 宿主机已安装 IPVS 配套工具(ipvsadmipset)并加载对应内核模块。
  2. kube-proxy 组件已切换至 IPVS 转发模式。
分步验证流程
1. 调整测试资源副本数量
bash 复制代码
root@master30 ~ 14:22:17# kubectl scale deployment web-28 --replicas 2
deployment.apps/web-28 scaled
root@master30 ~ 14:26:01# kubectl get all
NAME                          READY   STATUS    RESTARTS        AGE
pod/web                       1/1     Running   1 (5h37m ago)   21h
pod/web-28-7c6ffdbbd7-2k6rb   1/1     Running   0               26m
pod/web-28-7c6ffdbbd7-rwsv7   1/1     Running   0               26m
pod/web-29-5546565fbd-fhn44   1/1     Running   0               35m
pod/web-29-5546565fbd-mmbvw   1/1     Running   0               35m
NAME          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/web   ClusterIP   10.97.78.201   <none>        80/TCP    3h11m
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web-28   2/2     2            2           26m
deployment.apps/web-29   2/2     2            2           37m
NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/web-28-7c6ffdbbd7   2         2         2       26m
replicaset.apps/web-29-5546565fbd   2         2         2       37m
2. 查看内核 IPVS 转发规则

在集群任意节点执行,示例操作节点为 master30,查询 kube-proxy 生成的 IPVS 虚拟服务规则:

bash 复制代码
# 列出指定Service的IPVS虚拟服务配置
root@master30 ~ 14:26:17# ipvsadm -Ln -t 10.97.78.201:80

执行后输出内容示例,其中 10.97.78.201 为 Service 集群 IP,80 为服务端口:

bash 复制代码
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.97.78.201:80 rr
  -> 10.224.133.73:80             Masq    1      0          0         
  -> 10.224.133.109:80            Masq    1      0          0         
  -> 10.224.218.167:80            Masq    1      0          0         
  -> 10.224.218.184:80            Masq    1      0          0 

验证结论:IPVS 已为目标 Service 成功创建虚拟服务,并绑定全部后端业务 Pod 作为真实转发节点。

3. 验证负载均衡分发效果

在集群内部或外部持续访问 Service,观察流量是否均匀分发至不同 Pod 实例:

bash 复制代码
# 连续发起50次访问请求
root@master30 ~ 14:40:10# for i in {1..50}; do curl -s 10.97.78.201; done | sort -n|uniq -c
     25 hello nginx 1.28
     25 hello nginx 1.29

预期结果:新旧版本 Pod 各承接 25 次请求,证明 IPVS 轮询(rr)调度算法正常生效。

Kubernetes Ingress

学习参考:Ingress

环境准备

bash 复制代码
root@master30 ~ 14:48:46# kubectl create ns ingress
root@master30 ~ 14:49:50# kubectl config set-context --current --namespace ingress

Ingress 介绍

Ingress 能够为 Service 提供公网可访问的 URL 地址、实现流量负载均衡、终止 SSL/TLS 加密连接,同时支持基于域名的虚拟主机托管等核心能力。Ingress 控制器 是实现 Ingress 全部功能的核心组件,通常依托负载均衡器、边缘网关或前端代理完成流量处理工作。Ingress 不会直接对外开放非 HTTP/HTTPS 协议端口。若需要将其他协议服务暴露至公网,一般采用 Service.Type=NodePortService.Type=LoadBalancer 类型的 Service 实现。

Ingress 控制器

集群中必须部署并正常运行 Ingress 控制器,Ingress 资源才能生效。

与内置在 kube-controller-manager 中的其他控制器不同,Ingress 控制器不会随 Kubernetes 集群自动部署启动。你可根据集群环境,选择适配的 Ingress 控制器实现方案。

Kubernetes 官方目前维护并支持 AWS、GCE、Nginx 三款 Ingress 控制器,对应项目地址如下:

ingress-nginx 工作流程

本次实验选用 ingress-nginx 控制器作为实践载体。

项目地址:ingress-nginx

ingress-nginx 的完整工作流程如下:

  1. 部署 Ingress Controller 实体,该组件本质是前置 Nginx 代理服务
  2. 创建 Ingress 自定义资源,对应 Nginx 的路由配置文件
  3. Ingress Controller 与 Kubernetes APIServer 持续交互,动态拉取集群内所有 Ingress 规则;对规则完成解析后,生成代理服务对应的配置(即 Nginx 配置)
  4. 将生成的配置写入运行 Nginx 的 Pod,配置文件存放路径为 /etc/nginx/nginx.conf
  5. 重载 Nginx 服务,使新路由规则立即生效

Ingress 本质是七层 HTTP/HTTPS 反向代理组件。

ingress-nginx 部署前提

项目地址: kubernetes/ingress-nginx

  1. 本实验环境采用负载均衡组件处理前端流量,需提前部署 Metallb 等 LoadBalancer 实现方案
  2. 集群必须部署配套 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 部署

部署方法参考:https://kubernetes.github.io/ingress-nginx/deploy/

bash 复制代码
root@master30 ~ 14:49:53#  wget http://192.168.46.200/class/course-materials/softwares/stage03/ingress-nginx-controller-v1.11.2.tar.gz
--2026-08-11 15:09:54--  http://192.168.46.200/class/course-materials/softwares/stage03/ingress-nginx-controller-v1.11.2.tar.gz
Connecting to 192.168.46.200:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3902473 (3.7M) [application/octet-stream]
Saving to: 'ingress-nginx-controller-v1.11.2.tar.gz'
ingress-nginx-controll 100%[=========================>]   3.72M  --.-KB/s    in 0.04s   
2026-08-11 15:09:54 (91.9 MB/s) - 'ingress-nginx-controller-v1.11.2.tar.gz' saved [3902473/3902473]
root@master30 ~ 15:10:41# tar -xf ingress-nginx-controller-v1.11.2.tar.gz 

ingress-nginx 部署配置文件 deploy.yaml 包含四部分核心资源:

  1. 创建独立命名空间 ingress-nginx

  2. 创建 ConfigMap

    ConfigMap 用于统一存储通用配置变量,作用等效配置文件。它可将分布式系统各模块所需环境变量统一管理,区别于本地配置文件的是,该资源托管于集群内部,且支持 Kubernetes 标准资源操作。

Pod 启动时可绑定 ConfigMap,容器内应用能够直接读取其中配置。ConfigMap 常见使用场景包括:注入环境变量、设置程序启动参数、挂载生成配置文件,本质是为业务运行环境统一封装配置项。

  1. Ingress 相关 RBAC 权限管控,依次创建 ServiceAccount、ClusterRole、Role、RoleBinding、ClusterRoleBinding 全套权限资源
  2. 部署 ingress-controller,前文提到该组件会实时读取新增 Ingress 规则,并转换为 Nginx 代理配置
bash 复制代码
# 查看资源使用的镜像
root@master30 ~ 15:10:49# 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
# 替换镜像
root@master30 ~ 15:13:06# sed -ir 's#@sha256.*##;s/registry.k8s.io/hub.laoma.cloud/' ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
# 创建 Ingress
root@master30 ~ 15:13:58# kubectl apply -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
serviceaccount/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
configmap/ingress-nginx-controller created
service/ingress-nginx-controller created
service/ingress-nginx-controller-admission created
deployment.apps/ingress-nginx-controller created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created

== 注意 ==registry.k8s.io 官方镜像仓库国内无法直接拉取,需配置镜像加速服务;也可从 该地址 获取对应镜像。

查看部署的资源

bash 复制代码
root@master30 ~ 15:18:56# kubectl get all -n ingress-nginx 
NAME                                            READY   STATUS      RESTARTS   AGE
pod/ingress-nginx-admission-create-plk2q        0/1     Completed   0          5m5s
pod/ingress-nginx-admission-patch-xn265         0/1     Completed   0          5m5s
pod/ingress-nginx-controller-8659885ffd-gfcmp   1/1     Running     0          5m5s
NAME                                         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
service/ingress-nginx-controller             LoadBalancer   10.103.179.59   10.1.8.40     80:31688/TCP,443:32641/TCP   5m6s
service/ingress-nginx-controller-admission   ClusterIP      10.98.172.241   <none>        443/TCP                      5m6s
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           5m6s
NAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-8659885ffd   1         1         1       5m5s
NAME                                       STATUS     COMPLETIONS   DURATION   AGE
job.batch/ingress-nginx-admission-create   Complete   1/1           4s         5m5s
job.batch/ingress-nginx-admission-patch    Complete   1/1           4s         5m5s

Ingress 规则实践

Ingress 规则说明

规则示例
  • 示例 1: 无路由规则,配置默认后端

    通过指定 defaultBackend实现兜底转发,所有访问该负载均衡入口的流量,都会统一转发至配置内的 Kubernetes Service。

    bash 复制代码
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: test-ingress
    spec:
      defaultBackend:
        service: 
          name: testsvc
          port: 
            number: 80
  • 示例 2:虚拟主机配置,单域名匹配根路径

    bash 复制代码
    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:单域名多路径分流

    bash 复制代码
    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: web
                port: 
                  number: 80
  • 示例 4:HTTPS 流量透传场景

    若后端 Service 自身提供 HTTPS 服务,可配置 TLS 透传,让 Ingress 不做解密操作,直接将原始 HTTPS 流量转发至后端 Service。

    bash 复制代码
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: myingress
      annotations:
        # 关键:透传 TLS,Ingress 不解密
        nginx.ingress.kubernetes.io/ssl-passthrough: "true"
        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 配置文件必须包含 apiVersionkindmetadata 基础字段。

Ingress 的 spec 字段包含负载均衡与反向代理所需的全部配置信息,核心为一组用于匹配前端请求的路由规则,当前 Ingress 仅支持 HTTP 协议路由。

单条 HTTP 路由规则包含以下信息:

  • host 域名配置(例如 www.laoma.cloud,默认值为通配符 *
  • paths 路径匹配列表(例如 /laoma),每条路径绑定一组后端 service:port 服务。负载均衡转发流量前,会优先匹配请求的 Host 与 Path。
IngressClass

集群中可部署多款不同实现的 Ingress 控制器,各自拥有独立配置逻辑,每条 Ingress 资源都需指定对应的 IngressClass。IngressClass 资源存储控制器专属配置,同时定义该类规则由哪一款控制器处理。

支持将某一条 IngressClass 设置为集群默认类:为对应 IngressClass 添加注解 ingressclass.kubernetes.io/is-default-class: true 后,所有未填写 ingressClassName 字段的 Ingress 资源,都会自动绑定该默认 IngressClass。

路径匹配

Ingress 内每一条路径都必须声明路径类型(Path Type),未指定 pathType 的配置无法通过集群合法性校验。

当前官方定义三种路径匹配类型:

  • Prefix :基于 / 分隔的 URL 路径前缀匹配,匹配区分大小写,逐段校验路径分隔元素。仅当请求路径每一段都匹配规则前缀时,才算匹配成功。
  • Exact:严格完整匹配 URL 路径,区分大小写。
  • ImplementationSpecific:匹配逻辑由对应 IngressClass 的控制器实现决定,控制器可自定义匹配规则,或等效复用 Prefix/Exact 逻辑。

示例

类型 路径 请求路径 匹配与否?
Prefix / (所有路径)
Exact /foo /foo
Exact /foo /bar
Exact /foo /foo/
Exact /foo/ /foo
Prefix /foo /foo, /foo/
Prefix /foo/ /foo, /foo/
Prefix /aaa/bb /aaa/bbb
Prefix /aaa/bbb /aaa/bbb
Prefix /aaa/bbb/ /aaa/bbb 是,忽略尾部斜线
Prefix /aaa/bbb /aaa/bbb/ 是,匹配尾部斜线
Prefix /aaa/bbb /aaa/bbb/ccc 是,匹配子路径
Prefix /aaa/bbb /aaa/bbbxyz 否,字符串前缀不匹配
Prefix /, /aaa /aaa/ccc 是,匹配 /aaa 前缀
Prefix /, /aaa, /aaa/bbb /aaa/bbb 是,匹配 /aaa/bbb 前缀
Prefix /, /aaa, /aaa/bbb /ccc 是,匹配 / 前缀
Prefix /aaa /ccc 否,使用默认后端
混合 /foo (Prefix), /foo (Exact) /foo 是,优选 Exact 类型

多重匹配

在某些情况下,Ingress 中会有多条路径与同一个请求匹配。这时匹配路径最长者优先。 如果仍然有两条同等的匹配路径,则精确路径类型优先于前缀路径类型。

主机名匹配

Host 域名支持两种匹配模式:精确匹配、通配符匹配。精确匹配要求 HTTP 请求 Host 头部与配置字段完全一致;通配符匹配仅校验域名后缀段是否吻合。

主机 host 头部 匹配与否?
*.foo.com bar.foo.com 匹配,后缀域名段一致
*.foo.com baz.bar.foo.com 不匹配,通配符仅覆盖单级 DNS 域名标签
*.foo.com foo.com 不匹配,通配符仅覆盖单级 DNS 域名标签

Ingress 规则实践

本节主要讲解生产环境中 ingress-nginx 高频使用的路由配置方案。

环境准备
站点 webapp01
bash 复制代码
# 创建Deployment
root@master30 ~ 15:40:33# kubectl create deployment webapp01 --image=hub.laoma.cloud/library/httpd --replicas=2
deployment.apps/webapp01 created
# 查看pod标签
root@master30 ~ 15:53:43# kubectl get pod -L app
NAME                        READY   STATUS    RESTARTS   AGE   APP
webapp01-587d58c655-jssqn   1/1     Running   0          17s   webapp01
webapp01-587d58c655-s8kvk   1/1     Running   0          17s   webapp01
# 准备pod主页内容
root@master30 ~ 15:54:00# kubectl exec -it webapp01-587d58c655-jssqn -- bash -c "echo hello webapp01 pod1 > htdocs/index.html"
root@master30 ~ 15:56:19# kubectl exec -it webapp01-587d58c655-s8kvk -- bash -c "echo hello webapp01 pod2 > htdocs/index.html"
root@master30 ~ 15:57:03# kubectl expose deployment webapp01 --port=80 --target-port=80
service/webapp01 exposed
站点 webapp02
bash 复制代码
# 创建Deployment
root@master30 ~ 15:57:16# kubectl create deployment webapp02 --image=hub.laoma.cloud/library/httpd --replicas=2
deployment.apps/webapp02 created
# 查看pod标签
root@master30 ~ 15:57:36# kubectl get pod |grep webapp02
webapp02-56cfd678d6-5wlt9   1/1     Running   0          13s
webapp02-56cfd678d6-skjkf   1/1     Running   0          13s
# 准备pod主页内容
root@master30 ~ 15:57:49# kubectl exec -it webapp02-56cfd678d6-5wlt9 -- bash -c "echo hello webapp02 pod1 > htdocs/index.html
mkdir htdocs/games
echo hello webapp02 game1 > htdocs/games/index.html"
root@master30 ~ 15:58:30# kubectl exec -it webapp02-56cfd678d6-skjkf -- bash -c "echo hello webapp02 pod2 > htdocs/index.html
mkdir htdocs/games
echo hello webapp02 game2 > htdocs/games/index.html"
root@master30 ~ 15:58:32# kubectl expose deployment webapp02 --port=80 --target-port=80
service/webapp02 exposed
基础通用规则
多域名虚拟主机(多 host 路由)

场景:多个独立域名分别转发至不同业务后端

bash 复制代码
root@master30 ~ 15:58:58# vim ingress.yaml
bash 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
spec:
  # 这里一定要指定ingressClassName为nginx
  ingressClassName: nginx
  rules:
  - host: webapp01.liu.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: 
            name: webapp01
            port: 
              number: 80
  - host: webapp02.liu.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: 
            name: webapp02
            port: 
              number: 80
bash 复制代码
root@master30 ~ 15:59:38# kubectl apply -f  ingress.yaml 
ingress.networking.k8s.io/multi-host-ingress created
root@master30 ~ 15:59:50# kubectl describe ingress multi-host-ingress 
Name:             multi-host-ingress
Labels:           <none>
Namespace:        ingress
Address:          
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host                Path  Backends
  ----                ----  --------
  webapp01.liu.cloud  
                      /   webapp01:80 (10.224.133.106:80,10.224.218.158:80)
  webapp02.liu.cloud  
                      /   webapp02:80 (10.224.133.115:80,10.224.218.162:80)
Annotations:          <none>
Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  Sync    15s   nginx-ingress-controller  Scheduled for sync

访问验证

bash 复制代码
# 如果有多个域名,建议使用配置DNS-wild匹配
root@master30 ~ 16:00:05# echo '10.1.8.40 webapp01.liu.cloud'>> /etc/hosts
root@master30 ~ 16:00:52# echo '10.1.8.40 webapp02.liu.cloud'>> /etc/hosts
# 注意: 这里我们直接访问域名,没有加端口号
root@master30 ~ 16:01:00# curl webapp01.liu.cloud
hello webapp01 pod2
root@master30 ~ 16:10:17# curl webapp01.liu.cloud
hello webapp01 pod1
root@master30 ~ 16:10:19# curl webapp02.liu.cloud
hello webapp02 pod2
root@master30 ~ 16:10:25# curl webapp02.liu.cloud
hello webapp02 pod1

删除 ingress

bash 复制代码
root@master30 ~ 16:25:36# kubectl delete ingress multi-host-ingress 
ingress.networking.k8s.io "multi-host-ingress" deleted
同一域名多路径路由(path 分流)

场景:单一域名下,不同 URL 路径转发至对应微服务

bash 复制代码
root@master30 ~ 16:32:58# vim ingress.yaml
bash 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-path-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: www.liu.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: 
            name: webapp01
            port: 
              number: 80
      - path: /games
        pathType: Prefix
        backend:
          service: 
            name: webapp02
            port: 
              number: 80
bash 复制代码
root@master30 ~ 16:35:36# kubectl apply -f ingress.yaml 
ingress.networking.k8s.io/multi-path-ingress created
root@master30 ~ 16:35:57# kubectl describe ingress multi-path-ingress 
Name:             multi-path-ingress
Labels:           <none>
Namespace:        ingress
Address:          
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host           Path  Backends
  ----           ----  --------
  www.liu.cloud  
                 /        webapp01:80 (10.224.133.106:80,10.224.218.158:80)
                 /games   webapp02:80 (10.224.133.115:80,10.224.218.162:80)
Annotations:     <none>
Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  Sync    16s   nginx-ingress-controller  Scheduled for sync

访问验证

bash 复制代码
# 修改www.laoma.cloud解析,确保客户端能解析该名称
# 如果有多个域名,建议使用配置DNS-wild匹配
root@master30 ~ 16:36:13# echo '10.1.8.40 www.liu.cloud'>> /etc/hosts
# 注意: 这里我们直接访问域名,没有加端口号
root@master30 ~ 16:37:57# curl www.liu.cloud
hello webapp01 pod1
root@master30 ~ 16:38:54# curl www.liu.cloud
hello webapp01 pod2
root@master30 ~ 16:39:12# curl www.li.cloud/games/
hello webapp02 game1
root@master30 ~ 16:39:24# curl www.liu.cloud/games/
hello webapp02 game2

删除 ingress

bash 复制代码
root@master30 ~ 16:39:26# kubectl delete ingress multi-path-ingress 
ingress.networking.k8s.io "multi-path-ingress" deleted
生产核心:路径重写
路径裁剪(等价 Nginx proxy_pass /

场景 :前端请求携带 /api 统一前缀,后端程序仅识别去除前缀后的路径,通过重写规则剥离前缀

bash 复制代码
root@master30 ~ 16:39:59#  vim ingress.yaml
bash 复制代码
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.liu.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
bash 复制代码
root@master30 ~ 16:40:54# kubectl apply -f ingress.yaml 
ingress.networking.k8s.io/multi-path-ingress created
root@master30 ~ 16:41:11# 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.liu.cloud  
                 /webapp01/(.*)   webapp01:80 (10.224.133.106:80,10.224.218.158:80)
                 /webapp02/(.*)   webapp02:80 (10.224.133.115:80,10.224.218.162:80)
Annotations:     nginx.ingress.kubernetes.io/rewrite-target: /$1
                 nginx.ingress.kubernetes.io/use-regex: true
Events:
  Type    Reason  Age               From                      Message
  ----    ------  ----              ----                      -------
  Normal  Sync    3s (x2 over 20s)  nginx-ingress-controller  Scheduled for sync

访问验证

bash 复制代码
root@master30 ~ 16:41:31# curl www.liu.cloud/webapp01/
hello webapp01 pod1
root@master30 ~ 16:41:57# curl www.liu.cloud/webapp01/
hello webapp01 pod2
root@master30 ~ 16:42:09# curl www.liu.cloud/webapp02/
hello webapp02 pod2
root@master30 ~ 16:42:10# curl www.liu.cloud/webapp02/
hello webapp02 pod1

删除 ingress

bash 复制代码
root@master30 ~ 16:42:12# kubectl delete ingress multi-path-ingress 
ingress.networking.k8s.io "multi-path-ingress" deleted 
HTTPS 强制 & TLS 证书
绑定 TLS 证书 + 强制 HTTPS

环境准备

bash 复制代码
oot@master30 ~ 16:42:41# openssl genrsa -out www.key 2048  
root@master30 ~ 16:42:50# openssl req -new -key www.key -out www.csr -subj "/C=CN/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=www.liu.cloud/emailAddress=webadmin@liu.cloud" 
root@master30 ~ 16:43:15# openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt
Certificate request self-signature ok
subject=C = CN, ST = JS, L = NJ, O = LM, OU = DEVOPS, CN = www.liu.cloud, emailAddress = webadmin@liu.cloud
root@master30 ~ 16:43:24# kubectl create secret tls www-tls --cert=./www.crt --key=./www.key
secret/www-tls created

生产标配:访问 80 端口自动跳转 443 HTTPS 加密端口

bash 复制代码
root@master30 ~ 16:43:54# vim ingress.yaml 
bash 复制代码
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.liu.cloud
    secretName: www-tls
  rules:
  - host: www.liu.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp01
            port: 
              number: 80
bash 复制代码
root@master30 ~ 16:44:33# kubectl apply -f ingress.yaml 
ingress.networking.k8s.io/tls-ingress created
root@master30 ~ 16:44:47# kubectl describe ingress tls-ingress 
Name:             tls-ingress
Labels:           <none>
Namespace:        ingress
Address:          
Ingress Class:    nginx
Default backend:  <default>
TLS:
  www-tls terminates www.liu.cloud
Rules:
  Host           Path  Backends
  ----           ----  --------
  www.liu.cloud  
                 /   webapp01:80 (10.224.133.106:80,10.224.218.158: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    10s   nginx-ingress-controller  Scheduled for sync

访问验证

bash 复制代码
# 使用 -L 跟随 301/302/307/308 所有重定向
root@master30 ~ 16:45:18# curl -Lk http://www.liu.cloud/
hello webapp01 pod2
root@master30 ~ 16:45:21# curl -Lk http://www.liu.cloud/
hello webapp01 pod1
# 访问https站点
root@master30 ~ 16:45:22# curl -k https://www.liu.cloud/
hello webapp01 pod1
root@master30 ~ 16:45:34# curl -k https://www.liu.cloud/
hello webapp01 pod2

删除 ingress

bash 复制代码
root@master30 ~ 16:45:35# kubectl delete ingress tls-ingress
ingress.networking.k8s.io "tls-ingress" deleted
限流、防刷、超时优化
连接数限流、单 IP 限速
bash 复制代码
annotations:
  # 单IP最大并发连接
  nginx.ingress.kubernetes.io/limit-connections: "50"
  # 单IP每秒请求数
  nginx.ingress.kubernetes.io/limit-rps: "20"
自定义超时时间
bash 复制代码
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"
跨域配置(前后端分离必备)
全局跨域放行
bash 复制代码
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"
白名单访问控制(内网 / 后台系统)
限制指定 IP 段访问

场景:管理后台、内部业务系统,仅允许企业内网 IP 接入

bash 复制代码
annotations:
  # 只放行 10.1.8.0/24 网段
  nginx.ingress.kubernetes.io/whitelist-source-range: "10.1.8.0/24,127.0.0.1/32"
静态资源缓存、请求头透传
透传真实客户端 IP
bash 复制代码
annotations:
  nginx.ingress.kubernetes.io/x-forwarded-for: "true"
  nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "10.0.0.0/8"
静态资源缓存优化
bash 复制代码
annotations:
  nginx.ingress.kubernetes.io/proxy-cache: "true"
  nginx.ingress.kubernetes.io/proxy-cache-valid: "200 302 10m"
灰度 / 权重分流(金丝雀发布)
权重流量拆分

场景:线上灰度发布,90% 流量分配至稳定版本,10% 流量分发至测试新版本

bash 复制代码
annotations:
  nginx.ingress.kubernetes.io/canary: "true"
  nginx.ingress.kubernetes.io/canary-weight: "10"
错误页面、自定义配置
自定义后端错误页、关闭目录浏览
bash 复制代码
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

环境清理

bash 复制代码
root@master30 ~ 16:49:19# kubectl get all
No resources found in ingress namespace.
相关推荐
for_ever_love__1 小时前
python基础语法学习: 变量, 输入输出, 运算符
网络·python·学习
huainingning2 小时前
RJ DHCPV6 无状态配置成功案例
网络·智能路由器
恒拓高科WorkPlus3 小时前
从“可选项”到“必选项”——私有化部署即时通讯如何重塑企业协作新底座
大数据·网络·人工智能
上海云盾商务经理杨杨3 小时前
权限绕过漏洞渗透实战!突破登录验证访问后台功能
网络·安全
雾沉川4 小时前
Wireshark v4.4.7.0 网络抓包工具安装与实操技术教程
网络·测试工具·wireshark
Zhu7584 小时前
在docker环境部署frp
运维·docker·容器
运维行者_4 小时前
企业带宽监控工具实战:网络流量分析与异常排查的5个关键能力
运维·服务器·开发语言·网络·分布式·后端·php
zbtlink5 小时前
路由器安全深度解析:从WPA3协议到自动化审计
网络·网络安全·智能路由器·wps
艺杯羹5 小时前
LLM越狱与安全护栏攻防大演进:从奶奶漏洞到输入输出双重检测模型
网络·安全·网络安全·ai·llm·大语言模型·ai安全