K8S Ingress 流量治理全解:Traefik 从入门到实战完全指南
导读:在 Kubernetes 集群中,Service 资源实现了集群内部服务的四层负载均衡,但当我们需要将服务暴露给外部用户,并基于域名、路径进行七层(HTTP/HTTPS)路由分发时,Ingress 就成了不二之选。本文将从 Ingress 的核心概念出发,结合 Traefik 这一现代化云原生 Ingress Controller,带你从零完成 HTTP 代理、域名路由、URI 多路径匹配、HTTPS 证书配置、IngressRoute/TCP/UDP 四层代理、以及 IP 白名单和 BasicAuth 中间件等全套实战,一文掌握 K8S 流量治理的核心技能。
一、为什么需要 Ingress?
1.1 Service 的局限性
在 K8S 中,Service 提供了三种对外暴露方式:
| 类型 | 特点 | 局限性 |
|---|---|---|
| NodePort | 在每个节点上开放端口(30000-32767) | 端口数量有限,需要客户端维护节点 IP 列表 |
| LoadBalancer | 云厂商自动分配外部 IP | 依赖云厂商,每个 Service 独占一个 LB,成本高昂 |
| ClusterIP | 仅集群内部访问 | 无法直接暴露给外部用户 |
核心问题 :无论哪种类型,Service 本质上工作在 四层(TCP/UDP),无法感知 HTTP 协议层的 Host、Path、Header 等信息。
1.2 Ingress 的定位
Ingress 是 K8S 中专门用于七层(HTTP/HTTPS)流量路由的资源对象,它相当于集群的"智能网关",能够:
- 基于 域名(Host) 路由:
v1.example.com→ Service A,v2.example.com→ Service B - 基于 URI 路径 路由:
example.com/api→ Service A,example.com/web→ Service B - 终止 TLS 并将请求转发到后端 HTTP Service
- 统一入口,避免每个 Service 都需要外部负载均衡器
1.3 Ingress vs Service 对比
Service(四层代理):
客户端 → Service(负载均衡) → Pod
特点: 仅基于 IP + Port 转发, 不感知 HTTP 内容
Ingress(七层代理):
客户端 → Ingress Controller(七层路由) → Service → Pod
特点: 基于 Host/Path/Header 路由, 支持 TLS 终止, 中间件增强
二、Ingress 与 IngressClass 详解
2.1 核心概念
一个完整的 Ingress 架构涉及三个关键组件:
- Ingress 资源:定义路由规则(域名、路径、后端 Service 映射)
- Ingress Controller:实际执行路由转发的组件(如 Traefik、Nginx-Ingress)
- IngressClass:定义 Ingress Controller 的"类别",让不同 Controller 各司其职
类比理解:Ingress 资源好比"快递单"(写明收件人、地址),Ingress Controller 好比"快递员"(实际配送),IngressClass 好比"快递公司分类"(顺丰、中通各自处理自己的单子)。
2.2 IngressClass 的作用
在 K8S 1.22+ 版本中,IngressClass 取代了此前通过 kubernetes.io/ingress.class 注解的方式来指定 Ingress Controller。
yaml
# 查看 IngressClass 资源
kubectl get ingressclass
在 Ingress 资源中通过 ingressClassName 字段绑定对应的 Controller:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
ingressClassName: traefik-server # 指定由 Traefik 处理
rules:
- host: app.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: my-service
port:
number: 80
注意:如果集群中存在多个 Ingress Controller(如同时部署了 Nginx 和 Traefik),正确配置 IngressClass 至关重要,否则可能导致路由规则被错误的 Controller 处理。
三、Traefik 简介与 Helm 部署
3.1 为什么选择 Traefik?
Traefik 是一个现代化的云原生边缘路由器,与传统的 Nginx Ingress 相比,具有以下优势:
| 特性 | Traefik | Nginx Ingress |
|---|---|---|
| 配置热更新 | 自动检测 K8S 资源变化,无需 Reload | 需要 Reload 才能生效 |
| 服务发现 | 原生支持 K8S CRD、Docker、Consul 等 | 主要依赖 Ingress 注解 |
| 扩展性 | CRD 自定义路由规则(IngressRoute/TCP/UDP) | 依赖注解,配置复杂 |
| Dashboard | 内置 W eb UI,实时查看路由状态 | 需要额外部署 |
| 中间件 | 声明式 Middleware CRD | 需要配置 ConfigMap |
3.2 Helm 部署 Traefik
以下是基于 Helm 3 的 Traefik 部署完整流程:
第一步:添加 Helm 仓库
bash
helm repo add traefik https://traefik.github.io/charts
helm repo update
第二步:创建命名空间并安装
bash
kubectl create ns traefik
helm -n traefik install traefik-server traefik
第三步:验证部署状态
bash
# 查看 Pod 运行状态
kubectl get pods -n traefik -o wide
# 查看 Service(LoadBalancer 类型,由 MetalLB 分配外部 IP)
kubectl get svc -n traefik
# 预期输出:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# traefik-server LoadBalancer 10.200.x.x 10.0.0.154 80:xxxxx/TCP,443:xxxxx/TCP
第四步:验证 IngressClass
bash
kubectl get ingressclass
Traefik 部署成功后,会自动创建对应的 IngressClass 资源,后续所有 Ingress 资源通过 ingressClassName: traefik-server 来引用。
四、实战一:基于域名的 HTTP 代理
4.1 场景说明
模拟三个版本的应用(v1/v2/v3),通过不同的域名分别访问,实现基于域名的七层路由分发。
4.2 创建测试环境
编写 Deployment + Service 资源清单:
yaml
# 01-deploy-svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-app-v1
spec:
replicas: 3
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-app-v2
spec:
replicas: 3
selector:
matchLabels:
apps: v2
template:
metadata:
labels:
apps: v2
spec:
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/aliyun-container-service/nginx-welcome-page:latest
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-app-v3
spec:
replicas: 3
selector:
matchLabels:
apps: v3
template:
metadata:
labels:
apps: v3
spec:
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/liumapp/piwigo:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-app-v1
spec:
type: ClusterIP
selector:
apps: v1
ports:
- port: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-app-v2
spec:
type: ClusterIP
selector:
apps: v2
ports:
- port: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-app-v3
spec:
type: ClusterIP
selector:
apps: v3
ports:
- port: 80
bash
kubectl apply -f 01-deploy-svc.yaml
4.3 编写 Ingress 规则
yaml
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-app
spec:
ingressClassName: traefik-server
rules:
- host: v1.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: svc-app-v1
port:
number: 80
- host: v2.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: svc-app-v2
port:
number: 80
- host: v3.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: svc-app-v3
port:
number: 80
bash
kubectl apply -f ingress.yaml
4.4 验证测试
bash
# 查看 Ingress 资源
kubectl get ingress
# NAME CLASS HOSTS ADDRESS PORTS AGE
# ingress-app traefik-server v1.example.com,v2.example.com,v3.example.com 10.0.0.154 80 53s
# 基于域名测试(注意:不能直接用 IP 访问,Ingress 必须通过 Host 头匹配)
curl -H "HOST: v1.example.com" http://10.0.0.154/
curl -H "HOST: v2.example.com" http://10.0.0.154/
curl -H "HOST: v3.example.com" http://10.0.0.154/
# 直接用 IP 访问会返回 404
curl http://10.0.0.154/
# 404 page not found
关键要点:Ingress 工作在七层,必须通过 Host 头或域名访问。直接用 IP 访问时,因为没有匹配的 Host 规则,Traefik 会返回 404。
五、实战二:URI 多路径匹配
5.1 场景说明
同一个域名下,通过不同的 URI 路径将流量分发到不同的后端 Service:
example.com/v1→ v1 版本服务example.com/v2→ v2 版本服务
这种模式在实际开发中非常常见,比如前端应用和后端 API 共用同一个域名。
5.2 创建测试环境
为了更好地区分路径,使用 InitContainer 将 Pod 信息注入到各自路径下的 index.html:
yaml
# deploy-svc-uri.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-app-v1
spec:
replicas: 3
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
volumes:
- name: data
emptyDir: {}
initContainers:
- name: init-data
image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
command:
- /bin/sh
- -c
- echo "${POD_NAME} --- ${POD_IP}" > /data/index.html
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
volumeMounts:
- name: ·
mountPath: /data
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html/v1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-app-v2
spec:
replicas: 3
selector:
matchLabels:
apps: v2
template:
metadata:
labels:
apps: v2
spec:
volumes:
- name: data
emptyDir: {}
initContainers:
- name: init-data
image: registry.cn-hangzhou.aliyuncs.com/aliyun-container-service/nginx-welcome-page:latest
command:
- /bin/sh
- -c
- echo "${POD_NAME} --- ${POD_IP}" > /data/index.html
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
volumeMounts:
- name: data
mountPath: /data
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/aliyun-container-service/nginx-welcome-page:latest
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html/v2
---
apiVersion: v1
kind: Service
metadata:
name: svc-uri-v1
spec:
type: ClusterIP
selector:
apps: v1
ports:
- port: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-uri-v2
spec:
type: ClusterIP
selector:
apps: v2
ports:
- port: 80
5.3 编写 Ingress 规则
yaml
# ingress-uri.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-uri
spec:
ingressClassName: traefik-server
rules:
- host: example.com
http:
paths:
- pathType: Prefix
path: /v1
backend:
service:
name: svc-uri-v1
port:
number: 80
- pathType: Prefix
path: /v2
backend:
service:
name: svc-uri-v2
port:
number: 80
bash
kubectl apply -f deploy-svc-uri.yaml
kubectl apply -f ingress-uri.yaml
5.4 验证路径分发
bash
# 验证不同路径返回不同版本的 Pod 信息
for i in $(seq 3); do curl -H "HOST: example.com" http://10.0.0.154/v1/index.html; done
# deploy-app-v1-xxxxx --- 10.100.x.x
# deploy-app-v1-xxxxx --- 10.100.x.x
# deploy-app-v1-xxxxx --- 10.100.x.x
for i in $(seq 3); do curl -H "HOST: example.com" http://10.0.0.154/v2/index.html; done
# deploy-app-v2-xxxxx --- 10.100.x.x
# deploy-app-v2-xxxxx --- 10.100.x.x
# deploy-app-v2-xxxxx --- 10.100.x.x
pathType 说明:
Prefix:基于路径前缀匹配(最常用)Exact:精确匹配完整路径ImplementationSpecific:由 Ingress Controller 自行解释
六、实战三:HTTPS 证书配置
6.1 场景说明
生产环境中,HTTPS 是标配。通过 Ingress 的 TLS 配置,可以在 Ingress Controller 层面终止 SSL,后端 Service 无需关心证书管理。
6.2 生成证书并创建 Secret
bash
# 自建证书(生产环境请使用权威 CA 颁发的证书)
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=www.example.com"
# 将证书存储为 K8S Secret
kubectl create secret tls ca-secret \
--cert=tls.crt --key=tls.key
# 验证
kubectl get secrets ca-secret
# NAME TYPE DATA AGE
# ca-secret kubernetes.io/tls 2 6s
6.3 部署后端服务
yaml
# deploy-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-apple
spec:
replicas: 3
selector:
matchLabels:
apps: apple
template:
metadata:
labels:
apps: apple
spec:
containers:
- name: apple
image: registry.cn-hangzhou.aliyuncs.com/chenhw/filebrowser:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-apple
spec:
selector:
apps: apple
ports:
- protocol: TCP
port: 80
targetPort: 80
6.4 配置 Ingress TLS
yaml
# ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tls
spec:
ingressClassName: traefik-server
rules:
- host: www.example.com
http:
paths:
- backend:
service:
name: svc-apple
port:
number: 80
path: /
pathType: ImplementationSpecific
# 配置 TLS 证书
tls:
- hosts:
- www.example.com
secretName: ca-secret
bash
kubectl apply -f deploy-app.yaml
kubectl apply -f ingress-tls.yaml
6.5 验证 HTTPS 访问
bash
# 查看端口已同时监听 80 和 443
kubectl get ingress ingress-tls
# NAME CLASS HOSTS ADDRESS PORTS AGE
# ingress-tls traefik-server www.example.com 10.0.0.154 80, 443 5s
# HTTPS 访问测试
curl -k https://www.example.com/
Chrome 自签证书处理 :Chrome 浏览器不信任自签证书时,可在页面空白处输入
thisisunsafe后回车即可访问。推荐使用 Firefox 浏览器进行测试。
七、Traefik 核心架构与 IngressRoute
7.1 Traefik 架构全景
Traefik 作为一个边缘路由器,其内部架构由三个核心层次组成:
外部请求 → [Entrypoint 入口点] → [Router 前端路由] → [Middleware 中间件] → [Backend 后端服务]
各层职责:
| 组件 | 职责 | 类比 |
|---|---|---|
| Entrypoint(入口点) | 定义网络入口,监听端口、协议(TCP/UDP) | 大楼的入口大门 |
| Router(路由器) | 基于 Host、Path、Header 等规则匹配请求 | 大楼的导引牌 |
| Middleware(中间件) | 在请求到达后端前进行修改(认证、限流、改写 Header 等) | 安检门 |
| Backend/Service(后端) | 负责将请求转发到最终的 Pod | 目标办公室 |
7.2 Traefik 的三种路由创建方式
| 方式 | 说明 | 适用场景 |
|---|---|---|
| 原生 Ingress | K8S 标准资源,跨 Ingress Controller 通用 | 简单的 HTTP 路由 |
| CRD IngressRoute | Traefik 自定义资源,功能更强 | 需要中间件、高级路由规则 |
| Gateway API | K8S 官方新一代 API | 未来趋势,当前逐步成熟 |
7.3 Providers 与动态发现
Traefik 通过 Providers 机制实现配置的自动发现和热更新。当 K8S 中的 Ingress、IngressRoute 等 CRUD 资源发生变化时,Provider 会自动感知并动态更新路由规则,无需重启或 Reload。
八、实战四:IngressRoute HTTP/HTTPS 代理
8.1 IngressRoute vs 原生 Ingress
IngressRoute 是 Traefik 提供的 CRD,相比原生 Ingress 具有更强的表达能力:
yaml
# IngressRoute 资源定义(注意 API Group 是 traefik.io/v1alpha1)
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-ingressroute
spec:
entryPoints: # 指定入口点(web=80, websecure=443)
- web
routes: # 路由规则
- match: Host(`app.example.com`) && PathPrefix(`/`)
kind: Rule
services: # 后端服务
- name: svc-app
port: 80
middlewares: # 中间件(IngressRoute 独有的优势)
- name: my-middleware
namespace: default
8.2 暴露 Traefik Dashboard
yaml
# ingressroute-dashboard.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-traefik-server
namespace: traefik
spec:
selector:
app.kubernetes.io/instance: traefik-server-traefik
ports:
- port: 8080
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-traefik
namespace: traefik
spec:
entryPoints:
- web
routes:
- match: Host(`traefik.example.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: svc-traefik-server
port: 8080
bash
kubectl apply -f ingressroute-dashboard.yaml
# 添加 DNS 解析: 10.0.0.154 traefik.example.com
# 访问: http://traefik.example.com/dashboard/
8.3 IngressRoute HTTPS 配置
yaml
# ingressroute-https.yaml
# 先创建证书 Secret
# kubectl create secret tls whoami-tls --cert=tls.crt --key=tls.key
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-https
namespace: default
spec:
tls:
secretName: whoami-tls # 证书存储在 Secret 中
entryPoints:
- websecure # 监听 443 端口
routes:
- match: Host(`ssl.example.com`)
kind: Rule
services:
- name: svc-app
port: 80
bash
kubectl apply -f ingressroute-https.yaml
# 验证 HTTPS 访问
curl -H "HOST: ssl.example.com" https://10.0.0.154 -k
对比原生 Ingress :IngressRoute 的 TLS 配置嵌入在 spec 中,更加直观;而原生 Ingress 需要在顶层
spec.tls中单独声明。
九、实战五:IngressRouteTCP 四层代理
9.1 为什么需要 TCP 代理?
Ingress 和 IngressRoute 只能处理 HTTP/HTTPS 协议,而数据库(MySQL、Redis)、消息队列(RabbitMQ)等中间件使用的是 四层 TCP 协议 ,无法通过 Ingress 路由。Traefik 提供了 IngressRouteTCP 资源来解决这个问题。
9.2 自定义 Entrypoint
默认情况下 Traefik 只开放 web(80)和 websecure(443)两个入口点。代理 MySQL/Redis 需要先添加自定义入口点。
修改 Helm 的 values.yaml:
yaml
# values.yaml (ports 部分)
ports:
web:
port: 80
websecure:
port: 443
# 添加 MySQL 入口点
mysql:
port: 3306
# 添加 Redis 入口点
redis:
port: 6379
升级 Traefik:
bash
helm -n traefik upgrade traefik-server -f traefik/values.yaml traefik
9.3 代理 MySQL 服务
yaml
# deploy-mysql.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-mysql
spec:
replicas: 1
selector:
matchLabels:
apps: mysql
template:
metadata:
labels:
apps: mysql
spec:
containers:
- image: mysql:8.0.36
name: db
ports:
- containerPort: 3306
env:
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_ALLOW_EMPTY_PASSWORD
value: "yes"
- name: MYSQL_USER
value: admin
- name: MYSQL_PASSWORD
value: mypassword
args:
- --character-set-server=utf8
- --collation-server=utf8_bin
- --default-authentication-plugin=mysql_native_password
---
apiVersion: v1
kind: Service
metadata:
name: svc-mysql
spec:
ports:
- port: 3306
selector:
apps: mysql
yaml
# 04-ingressroutetcp-mysql.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: ingressroutetcp-mysql
namespace: default
spec:
entryPoints:
- mysql
routes:
- match: HostSNI(`*`) # TCP 路由使用 HostSNI 匹配(非 TLS 必须用 *)
services:
- name: svc-mysql
port: 3306
bash
kubectl apply -f deploy-mysql.yaml
kubectl apply -f 04-ingressroutetcp-mysql.yaml
修改 Traefik Service 暴露 MySQL 端口:
bash
kubectl edit svc traefik-server -n traefik
# 在 ports 中添加:
# - name: mysql
# port: 3306
客户端连接测试:
bash
# 通过 Traefik 外部 IP 连接集群内部的 MySQL
mysql -h 10.0.0.154 -u admin -pmypassword wordpress
# 在 K8S 集群内验证数据
kubectl exec -it deploy-mysql-xxxxx -- mysql -e "SELECT * FROM wordpress.student;"
9.4 代理 Redis 服务
yaml
# deploy-redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-redis
spec:
replicas: 1
selector:
matchLabels:
apps: redis
template:
metadata:
labels:
apps: redis
spec:
containers:
- image: redis:7.2.8-alpine
name: db
ports:
- containerPort: 6379
env:
- name: REDIS_PASSWORD
value: "mypassword"
---
apiVersion: v1
kind: Service
metadata:
name: svc-redis
spec:
ports:
- port: 6379
selector:
apps: redis
yaml
# ingressroutetcp-redis.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: ingressroutetcp-redis
namespace: default
spec:
entryPoints:
- redis
routes:
- match: HostSNI(`*`)
services:
- name: svc-redis
port: 6379
bash
kubectl apply -f deploy-redis.yaml
kubectl apply -f ingressroutetcp-redis.yaml
# 客户端测试
redis-cli -h 10.0.0.154
10.0.0.154:6379> SET mykey "Hello Traefik TCP"
OK
10.0.0.154:6379> GET mykey
"Hello Traefik TCP"
HostSNI 注意事项:
- SNI(Server Name Indication)是 TLS 协议的扩展,只有 TLS 加密的连接才能使用域名匹配
- 非 TLS 的 TCP 路由必须使用
HostSNI(\*`)`,表示匹配所有请求- 这意味着同一入口点上的非 TLS TCP 路由只能有一个(或通过不同入口点区分)
十、实战六:IngressRouteUDP 代理
10.1 场景说明
某些场景下需要代理 UDP 协议(如 DNS、日志采集、游戏服务器等),Traefik 提供了 IngressRouteUDP 支持。
10.2 配置入口点
yaml
# values.yaml 添加 UDP 入口点
ports:
udpcase:
port: 8081
protocol: UDP
bash
helm -n traefik upgrade traefik-server -f traefik/values.yaml traefik
10.3 创建 IngressRouteUDP
yaml
# ingressrouteudp.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteUDP
metadata:
name: ingressrouteudp-app
namespace: default
spec:
entryPoints:
- udpcase
routes:
- services:
- name: svc-whoamiudp
port: 8080
bash
kubectl apply -f ingressrouteudp.yaml
测试 UDP 转发 (需要安装 socat 工具):
bash
# 安装 socat
apt -y install socat
# 发送 UDP 数据包
echo "Hello UDP" | socat - udp4-datagram:10.0.0.154:8081
注意 :修改 Traefik Service 暴露 UDP 端口时,需要明确指定
protocol: UDP:
yamlports: - name: udpcase port: 8081 protocol: UDP
十一、实战七:Traefik 中间件(Middleware)
11.1 中间件概述
中间件是 Traefik 最强大的特性之一。它可以在请求到达后端 Service 之前 或响应返回客户端 之前 对流量进行修改或拦截。
常见中间件类型:
| 中间件 | 功能 | 典型场景 |
|---|---|---|
| ipAllowList | IP 白名单访问控制 | 限制管理后台仅内网可访问 |
| basicAuth | HTTP 基础认证 | 保护内部工具页面 |
| rateLimit | 请求速率限制 | 防止 API 被滥用 |
| headers | 添加/修改/删除 HTTP Header | 添加安全 Header |
| redirectScheme | HTTP→HTTPS 重定向 | 强制 HTTPS |
| stripPrefix | 去除 URI 前缀 | /api/v1/users → /users |
重要:多个相同协议的中间件可以组成链(Chain),按顺序依次执行。
11.2 IP 白名单中间件
场景:限制某个域名只允许特定 IP 网段访问(如内网管理后台)。
yaml
# middleware-ipallowlist.yaml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: ip-allow-list
namespace: default
spec:
ipAllowList:
sourceRange:
- 127.0.0.1 # 本机
- 10.0.0.0/8 # 内网网段
- 192.168.0.0/16 # RFC1918 私有地址
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-protected
spec:
entryPoints:
- web
routes:
- match: Host(`admin.example.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: svc-admin
port: 80
# 引用中间件
middlewares:
- name: ip-allow-list
namespace: default
bash
kubectl apply -f middleware-ipallowlist.yaml
# 白名单 IP 访问 → 正常返回内容
curl -H "HOST: admin.example.com" http://10.0.0.154/
# 非
# 白名单 IP 访问 → 返回 403 Forbidden
curl -H "HOST: admin.example.com" http://外部IP/
# Forbidden
# HTTP 状态码
curl -I -H "HOST: admin.example.com" http://外部IP/
# HTTP/1.1 403 Forbidden
验证技巧 :可以通过注释掉白名单中的某个网段来快速验证 IP 限制是否生效。在生产环境中,推荐将
sourceRange设置为公司公网出口 IP 或 VPN 网段。
11.3 BasicAuth 中间件
场景:为内部工具页面添加用户名/密码认证。
yaml
# middleware-basicauth.yaml
apiVersion: v1
kind: Secret
metadata:
name: login-info
namespace: default
type: kubernetes.io/basic-auth
stringData:
username: admin
password: mypassword
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: basic-auth
spec:
basicAuth:
secret: login-info
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-auth
spec:
entryPoints:
- web
routes:
- match: Host(`auth.example.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: svc-admin
port: 80
middlewares:
- name: basic-auth
namespace: default
bash
kubectl apply -f middleware-basicauth.yaml
# 无认证访问 → 401 Unauthorized
curl -I auth.example.com
# HTTP/1.1 401 Unauthorized
# Www-Authenticate: Basic realm="traefik"
# 正确认证访问 → 200 OK
curl -u admin:mypassword auth.example.com
# 正常返回页面内容
# 错误密码访问 → 401 Unauthorized
curl -u admin:wrongpassword auth.example.com
# 401 Unauthorized
11.4 多中间件链式组合
Traefik 的中间件支持链式组合,可以同时挂载多个中间件,按声明顺序依次执行。例如同时启用 IP 白名单 + BasicAuth 双重防护:
yaml
# 10-middleware-chain.yaml
apiVersion: v1
kind: Secret
metadata:
name: login-info
namespace: default
type: kubernetes.io/basic-auth
stringData:
username: admin
password: mypassword
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: basic-auth
spec:
basicAuth:
secret: login-info
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: ip-allow-list
namespace: default
spec:
ipAllowList:
sourceRange:
- 127.0.0.1
- 10.0.0.0/8
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-double-protect
spec:
entryPoints:
- web
routes:
- match: Host(`secure.example.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: svc-admin
port: 80
# 中间件按顺序执行: 先 IP 白名单, 再 BasicAuth
middlewares:
- name: ip-allow-list
namespace: default
- name: basic-auth
namespace: default
执行顺序示意:
客户端请求 → [ip-allow-list 检查 IP] → [basicAuth 检查认证] → 后端 Service
│ │
├─ 不在白名单 → 403 ├─ 认证失败 → 401
└─ 通过 └─ 通过
安全最佳实践:对于生产环境的管理后台(如 Grafana、Prometheus、Kuboard 等),强烈建议同时配置 IP 白名单和 BasicAuth,实现双重防护。
十二、完整实战:暴露 Traefik Dashboard(Ingress 方式)
除了使用 IngressRoute 暴露 Traefik Dashboard,也可以使用原生 Ingress 资源:
yaml
# 11-ingress-traefik-dashboard.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-traefik-server
namespace: traefik
spec:
selector:
app.kubernetes.io/instance: traefik-server-traefik
ports:
- port: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-traefik-server
namespace: traefik
spec:
ingressClassName: traefik-server
rules:
- host: traefik.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: svc-traefik-server
port:
number: 8080
bash
kubectl apply -f 11-ingress-traefik-dashboard.yaml
# 添加解析: 10.0.0.154 traefik.example.com
# 访问: http://traefik.example.com/dashboard/
十三、生产环境最佳实践
13.1 配置默认 404 页面
当访问未匹配的域名或路径时,Traefik 默认返回简单的 404。可以配置自定义的错误页面提升用户体验:
yaml
# 使用 Middleware 的 errors 配置(需 Traefik 2.x+)
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: custom-errors
spec:
errors:
status:
- "404"
query: "/{status}.html"
service:
name: svc-error-pages
port: 80
13.2 HTTPS 重定向
强制所有 HTTP 请求跳转到 HTTPS:
yaml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: https-redirect
spec:
redirectScheme:
scheme: https
permanent: true
13.3 常见问题排查
| 问题 | 可能原因 | 排查方法 |
|---|---|---|
| 访问返回 404 | 未匹配到 Host 规则 | 检查请求的 Host 头是否与 Ingress 规则一致 |
| 访问返回 503 | 后端 Service 无可用 Endpoint | kubectl describe ing 查看后端地址 |
default-http-backend not found |
未配置默认后端 | 正常现象,不影响路由 |
| HTTPS 证书不生效 | Secret 类型或名称错误 | 确认 Secret 为 kubernetes.io/tls 类型 |
| TCP 连接被拒绝 | 入口点未开放或端口未暴露 | 检查 Traefik values.yaml 和 Service ports |
十四、总结
本文从 Ingress 的核心概念出发,系统讲解了 K8S 流量治理的完整知识体系:
| 模块 | 核心内容 |
|---|---|
| 基础概念 | Ingress vs Service(七层 vs 四层)、IngressClass 路由分配 |
| 原生 Ingress | 域名路由、URI 多路径匹配、HTTPS/TLS 证书配置 |
| Traefik 架构 | Entrypoint → Router → Middleware → Backend 四层模型 |
| IngressRoute | Traefik CRD 增强,支持中间件绑定和 HTTPS 内联配置 |
| 四层代理 | IngressRouteTCP 代理 MySQL、Redis 等数据库服务 |
| UDP 代理 | IngressRouteUDP 支持 DNS、游戏等 UDP 协议 |
| 中间件 | ipAllowList 白名单、basicAuth 认证、多中间件链式组合 |
扩展方向:Gateway API 是 K8S 官方正在推进的下一代流量管理标准,Traefik 已支持。建议在掌握 Ingress + IngressRoute 之后,关注 Gateway API 的发展动态。