K8S-Ingress流量治理全解-Traefik从入门到实战完全指南

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

yaml 复制代码
ports:
- 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 的发展动态。

相关推荐
marsh020610 小时前
51 openclaw自定义中间件:解决特定业务需求的扩展方案
中间件·ai编程
万里侯10 小时前
Kubernetes网络性能优化:提升集群网络效率
微服务·容器·k8s
阿里-于怀10 小时前
告别 Ingress Nginx:云原生 API 网关 Gateway API 使用指引
nginx·云原生·gateway
万里侯11 小时前
技术人的人际关系:建立良好的职业网络
微服务·容器·k8s
AI云原生11 小时前
容器网络模型与服务发现:从踩坑到精通,Kubernetes 网络问题排查全指南
服务器·网络·云原生·容器·kubernetes·云计算·服务发现
石小千11 小时前
Docker-排查占用磁盘空间大问题
运维·docker·容器
仙柒41511 小时前
Docker 网络
运维·docker·容器
木雷坞11 小时前
vLLM 服务启动慢排查:NAS 模型目录、Docker 镜像和 GPU Runtime
docker·容器·vllm
古怪今人11 小时前
WSL和Hyper-V Ubuntu安装docker Docker安装Reids、MySQL、PostgreSQL和RabbitMQ
运维·docker·容器