Traefik 在 Kubernetes 上暴露服务的进阶指南:Middleware、Let's Encrypt、Sticky Session、多层路由与服务级中间件
本文基于仓库中的 进阶指南 整理而成,承接 入门指南 的部署基础,面向已经在 Kubernetes 中通过 Traefik Proxy 完成基础服务暴露的开发者。你将系统掌握如何用 Middleware 施加安全头与 IP 白名单、用 Let's Encrypt(IngressRoute)与 cert-manager(Gateway API)实现证书自动化、用 TraefikService 实现会话粘滞、用 IngressRoute parentRefs 构建按角色鉴权的多层路由,并在路由与服务两个层级精准编排中间件,最终打造可上生产环境的 Ingress 网关。
前置要求
- 已完成 入门指南,拥有一个可用的 Traefik + Kubernetes 部署环境;
- 一个已安装 Traefik Proxy 的 Kubernetes 集群;
- 本地
kubectl已正确配置并指向该集群; - 沿用入门指南中的
whoami示例应用及其HTTPRoute/IngressRoute配置。
后续所有 YAML 均可在集群中直接 kubectl apply,用于演示的域名 whoami.docker.localhost 可替换为你自己的真实域名。
添加 Middlewares:安全头与访问控制
Middlewares 是 Traefik 处理管道中用于修改请求或响应的中间件,是安全加固的第一道关卡。下面先创建两个典型中间件:负责安全响应头的 Headers(详见 参考文档)和负责来源控制的 IP AllowList(详见 参考文档)。
创建 Middleware 资源
将下列内容保存为 middlewares.yaml:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: secure-headers
namespace: default
spec:
headers:
frameDeny: true
sslRedirect: true
browserXssFilter: true
contentTypeNosniff: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: ip-allowlist
namespace: default
spec:
ipAllowList:
sourceRange:
- 127.0.0.1/32
- 10.0.0.0/8 # Typical cluster network range
- 192.168.0.0/16 # Common local network range
应用它:
kubectl apply -f middlewares.yaml
参数速查:
frameDeny:添加X-Frame-Options: DENY,阻止页面被第三方站点以 iframe 嵌入(防点击劫持);sslRedirect:HTTP 请求被重定向到 HTTPS;browserXssFilter:添加X-XSS-Protection: 1; mode=block;contentTypeNosniff:添加X-Content-Type-Options: nosniff,禁止浏览器猜测 MIME 类型;stsSeconds: 31536000:HSTSmax-age秒数,配合stsIncludeSubdomains(作用于子域)与stsPreload(申请加入浏览器预加载列表)构成完整 HSTS 策略;ipAllowList.sourceRange:以 CIDR 列表声明放行来源,命中即放行,其余来源返回 403。
这些选项的实现与默认值逻辑位于仓库 pkg/middlewares/headers 与 pkg/middlewares/ipallowlist 包内,阅读源码可核对每个头部字段在 Go 侧的默认行为。
Gateway API:通过 ExtensionRef 引用 Middlewares
Gateway API 的规范中,对请求的细粒度加工使用 Filters 机制。Traefik 通过 ExtensionRef 这种可扩展 filter 类型,让 HTTPRoute 能直接引用 traefik.io 组的 Middleware CRD——这是 Gateway API 场景下使用 Traefik 中间件的标准方式,与 HTTPRoute 规范天然融合,不依赖任何注解。
更新 whoami-route.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami
namespace: default
spec:
parentRefs:
- name: traefik-gateway
sectionName: websecure
hostnames:
- "whoami.docker.localhost"
rules:
- matches:
- path:
type: PathPrefix
value: /api
filters:
- type: ExtensionRef
extensionRef: # Headers Middleware Definition
group: traefik.io
kind: Middleware
name: secure-headers
- type: ExtensionRef
extensionRef: # IP AllowList Middleware Definition
group: traefik.io
kind: Middleware
name: ip-allowlist
backendRefs:
- name: whoami-api
port: 80
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: ExtensionRef
extensionRef: # Headers Middleware Definition
group: traefik.io
kind: Middleware
name: secure-headers
- type: ExtensionRef
extensionRef: # IP AllowList Middleware Definition
group: traefik.io
kind: Middleware
name: ip-allowlist
backendRefs:
- name: whoami
port: 80
应用变更:
kubectl apply -f whoami-route.yaml
注意 /api 与 / 两条规则都同时应用了两个中间件,含义是:无论走 API 还是首页路径,都先加安全头、再做来源白名单校验。
IngressRoute:通过 routes.middlewares 引用 Middlewares
若你使用 Traefik 自有的 IngressRoute CRD,更新 whoami-ingressroute.yaml,把中间件挂在每条 route 上:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: whoami
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`whoami.docker.localhost`) && Path(`/api`)
kind: Rule
middlewares: # Middleware Definition
- name: secure-headers
- name: ip-allowlist
services:
- name: whoami-api
port: 80
- match: Host(`whoami.docker.localhost`)
kind: Rule
middlewares: # Middleware Definition
- name: secure-headers
- name: ip-allowlist
services:
- name: whoami
port: 80
tls:
certResolver: le
kubectl apply -f whoami-ingressroute.yaml
此处 tls.certResolver: le 指向后续小节配置的 Let's Encrypt 证书解析器。IngressRoute CRD 结构中,routes[].middlewares(类型 []MiddlewareRef)与 spec.tls.certResolver 的定义见仓库 pkg/provider/kubernetes/crd/traefikio/v1alpha1/ingressroute.go。
验证中间件是否生效
用 curl 检查响应头是否带上安全策略:
curl -k -I -H "Host: whoami.docker.localhost" https://localhost/
预期可见类似输出:
HTTP/2 200
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
strict-transport-security: max-age=31536000; includeSubDomains; preload
content-type: text/plain; charset=utf-8
content-length: 403
验证 IP 白名单时,可临时把 sourceRange 改成不包含你当前出口 IP 的网段,再请求一次,应收到 403 被拒绝的结果,从而确认访问控制真实生效。
使用 Let's Encrypt 自动化签发证书
!!! info Traefik 内置的 Let's Encrypt 集成仅面向 IngressRoute 生效,不会为 Gateway API 的 listener 自动签发证书。Gateway API 场景请使用 cert-manager 或其他证书控制器。
!!! important "Public DNS 前提"
Let's Encrypt 需要公网可达的域名来完成所有权校验。若像示例一样使用 whoami.docker.localhost 这类本地域名,证书将保持自签名。生产环境请换成拥有公网 DNS 记录并指向 Traefik 实例的真实域名。
IngressRoute + Traefik 内置 ACME
在 Traefik 的 Helm values.yaml 中配置证书解析器(resolver):
additionalArguments:
- "--certificatesresolvers.le.acme.email=your-email@example.com" #replace with your email
- "--certificatesresolvers.le.acme.storage=/data/acme.json"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
三个参数分别声明:ACME 账户邮箱、证书存储文件路径(持久化挂载的关键,证书与账户密钥都写入该 json 文件)、使用 HTTP-01 challenge 并指定走名为 web 的入口点完成质询。
升级 Traefik 使其加载上述配置:
helm upgrade traefik traefik/traefik -n traefik --reuse-values -f values.yaml
随后让 IngressRoute 使用该解析器申请证书:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: whoami
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`whoami.docker.localhost`) && Path(`/api`)
kind: Rule
middlewares:
- name: secure-headers
- name: ip-allowlist
services:
- name: whoami-api
port: 80
- match: Host(`whoami.docker.localhost`)
kind: Rule
middlewares:
- name: secure-headers
- name: ip-allowlist
services:
- name: whoami
port: 80
tls:
certResolver: le
kubectl apply -f whoami-ingressroute.yaml
Traefik 会在配置热加载后,按 Host 规则自动为匹配的域名申请并续期证书,全程无需手工管理 Secret。
Gateway API + cert-manager
Gateway API 一侧先安装 cert-manager:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.yaml
随后创建 Issuer 与 Certificate(保存为 letsencrypt-issuer-andwhoami-certificate.yaml):
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt
spec:
acme:
email: your-email@example.com # replace with your email
server: https://acme-v02-staging.api.letsencrypt.org/directory # Replace with the production server in production
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- name: traefik
namespace: default
kind: Gateway
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: whoami
namespace: default
spec:
secretName: whoami-tls-le # Name of secret where the generated certificate will be stored.
dnsNames:
- "whoami.docker.localhost" # Replace a real domain
issuerRef:
name: letsencrypt
kind: Issuer
要点解读:
solvers[].http01.gatewayHTTPRoute.parentRefs告诉 cert-manager:用 HTTP-01 质询时,把挑战请求经名为traefik、位于default命名空间的 Gateway(HTTPRoute)发布出去,由其转发到 ACME 验证服务器;- 示例使用 staging 环境(
acme-v02-staging),便于反复调试且不消耗生产配额;上线前请替换为生产目录https://acme-v02.api.letsencrypt.org/directory; Certificate.secretName指定证书落地 Secret 名,即下一步 Gateway 引用的whoami-tls-le。
!!! important "Public DNS 前提"
Let's Encrypt 必须通过公网验证域名所有权。使用 whoami.docker.localhost 之类的本地域名时,cert-manager 会发起质询但无法完成,证书仍将保持自签名。生产环境请改用指向集群入口的公网域名。
应用上述资源:
kubectl apply -f letsencrypt-issuer-andwhoami-certificate.yaml
更新 Gateway,让 websecure listener 引用 cert-manager 生成的证书:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: traefik-gateway
namespace: default
spec:
gatewayClassName: traefik
listeners:
- name: web
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: websecure
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: All
tls:
certificateRefs:
- name: whoami-tls-le # References the secret created by cert-manager
kubectl apply -f gateway.yaml
此后,既有 HTTPRoute 在访问 websecure listener 时将自动使用这份证书完成 TLS 握手。
验证证书签发结果
# Check certificate status
kubectl get certificate -n default
# Verify the certificate chain
curl -v https://whoami.docker.localhost/ 2>&1 | grep -i "server certificate"
当签发成功后,可从返回的证书链中看到 issuer 为 Let's Encrypt。若使用 staging 环境,证书链中会体现其 staging 根,属正常现象。
配置 Sticky Sessions(会话粘滞)
会话粘滞保证同一用户的多次请求始终落在同一个后端 Pod 上,是带本地会话状态应用(如含内存 Session 的 Web 服务)的必备能力。Traefik 通过加权负载均衡的 sticky.cookie 实现:首次请求时种下一个 Cookie,后续请求依据该 Cookie 计算同后端转发。
先把副本扩容到 3
kubectl scale deployment whoami --replicas=3
多副本才能直观对比"粘滞"与"普通负载均衡"的差异。
Gateway API + TraefikService
Gateway API 本身只认识原生 Service 后端;要让其使用 Traefik 的负载均衡能力(加权、粘滞),需要借助 Traefik 扩展出的 TraefikService CRD。先创建粘滞服务(保存为 whoami-sticky-service.yaml):
apiVersion: traefik.io/v1alpha1
kind: TraefikService
metadata:
name: whoami-sticky
namespace: default
spec:
weighted:
services:
- name: whoami
port: 80
weight: 1
sticky:
cookie:
name: sticky_cookie
secure: true
httpOnly: true
kubectl apply -f whoami-sticky-service.yaml
weighted 分组只放一个成员也可启用粘滞——粘滞语义与权重互不冲突。接着在 HTTPRoute 中,把对应 backendRefs 指向该 TraefikService(通过 group: traefik.io + kind: TraefikService 显式告知 Gateway API 这是扩展后端类型):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami
namespace: default
spec:
parentRefs:
- name: traefik-gateway
sectionName: websecure
hostnames:
- "whoami.docker.localhost"
rules:
- matches:
- path:
type: PathPrefix
value: /api
filters:
- type: ExtensionRef
extensionRef: # Headers Middleware Definition
group: traefik.io
kind: Middleware
name: secure-headers
- type: ExtensionRef
extensionRef: # IP AllowList Middleware Definition
group: traefik.io
kind: Middleware
name: ip-allowlist
backendRefs:
- name: whoami-api
port: 80
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: traefik.io # <── tell Gateway this is a TraefikService
kind: TraefikService
name: whoami-sticky
filters:
- type: ExtensionRef
extensionRef: # Headers Middleware Definition
group: traefik.io
kind: Middleware
name: secure-headers
- type: ExtensionRef
extensionRef: # IP AllowList Middleware Definition
group: traefik.io
kind: Middleware
name: ip-allowlist
backendRefs:
- name: whoami
port: 80
kubectl apply -f whoami-route.yaml
仓库 Gateway API provider 在解析 HTTPRoute 时,对这类指向 Traefik 扩展资源的 backendRef 会转换为对应的 Traefik 服务模型,其解析逻辑见 pkg/provider/kubernetes/gateway/httproute.go。
IngressRoute + TraefikService
IngressRoute 同样可把某条 route 的服务替换为粘滞版 TraefikService:
apiVersion: traefik.io/v1alpha1
kind: TraefikService
metadata:
name: whoami-sticky
namespace: default
spec:
weighted:
services:
- name: whoami
port: 80
sticky:
cookie:
name: sticky_cookie
secure: true
httpOnly: true
kubectl apply -f whoami-sticky-service.yaml
更新 IngressRoute,在 services 项中指明 kind: TraefikService:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: whoami
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`whoami.docker.localhost`) && Path(`/api`)
kind: Rule
middlewares: # Middleware Definition
- name: secure-headers
- name: ip-allowlist
services:
- name: whoami-api
port: 80
- match: Host(`whoami.docker.localhost`)
kind: Rule
middlewares: # Middleware Definition
- name: secure-headers
- name: ip-allowlist
services:
- name: whoami-sticky # Changed from whoami to whoami-sticky
kind: TraefikService # Added kind: TraefikService
tls:
certResolver: le
kubectl apply -f whoami-ingressroute.yaml
底层实现上,CRD provider 会把 TraefikService 的 spec.weighted.sticky.cookie 字段翻译成动态配置中的负载均衡 Sticky(含 Cookie 名称、Secure、HTTPOnly 以及可选的 SameSite、MaxAge、Domain、Path),并写入 LoadBalancer 服务;映射逻辑集中在 pkg/provider/kubernetes/crd/kubernetes_http.go。CRD 的类型定义则见 pkg/provider/kubernetes/crd/traefikio/v1alpha1/ingressroute.go。
验证粘滞会话
带 Cookie 连续请求,应始终命中同一后端 Pod:
# First request - save cookies to a file
curl -k -c cookies.txt -H "Host: whoami.docker.localhost" https://localhost/
# Subsequent requests - use the cookies
curl -k -b cookies.txt -H "Host: whoami.docker.localhost" https://localhost/
curl -k -b cookies.txt -H "Host: whoami.docker.localhost" https://localhost/
观察每次响应的 Hostname 字段:使用同一 cookie 文件时它应保持不变,即粘滞生效。
对照实验——不带 Cookie 请求,应被轮询到不同 Pod:
# Requests without cookies should be load-balanced across different pods
curl -k -H "Host: whoami.docker.localhost" https://localhost/
curl -k -H "Host: whoami.docker.localhost" https://localhost/
此时各次响应的 Hostname 会不同。
!!! important "浏览器测试注意"
浏览器中测试需保持同一浏览器会话以维持 Cookie。示例 Cookie 带有 httpOnly 与 secure 标记:前者保证脚本(JavaScript)无法读取,后者保证仅通过 HTTPS 传输,因此只能用同一 HTTPS 会话持续访问。
更完整的粘滞与加权配置说明见 负载均衡 Service 参考文档。
搭建 Multi-Layer Routing(多层路由)
多层路由让 Router 之间形成父子层级:父 Router 先经过中间件处理请求(如完成鉴权、注入头部),再由子 Router 依据加工后的请求做最终路由决策。典型场景包括"先鉴权、再按角色分发",以及分层逐步叠加中间件(父层做限流/CORS,子层做更具体的处理)。
!!! info "IngressRoute 专属能力"
多层路由由 Kubernetes IngressRoute(CRD)通过 spec.parentRefs 字段原生支持,标准 Kubernetes Ingress 与 Gateway API 资源不提供该能力。从源码结构看,Gateway API provider 解析 HTTPRoute 时不具备 parentRefs 语义,而 multi-layer-routing.md 明确指出其受支持面为 File、KV 存储与 Kubernetes CRD provider。
基于认证的多层路由示例
设计:父 IngressRoute api-parent 负责 Host(api.docker.localhost) && PathPrefix(/api) 匹配并施加 BasicAuth;两个子 IngressRoute 依据中间件写入的 X-Auth-User 头分别路由到 admin 与 user 后端。
!!! important "父 Router 约束"
多层路由中的父 Router 不得定义 services,服务选择完全交由子 Router 依据各自规则完成。所有子 IngressRoute 必须通过 parentRefs 正确引用父级。
先部署两个后端服务(保存为 whoami-backends.yaml):
# whoami-backends.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: admin-backend
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: admin-backend
template:
metadata:
labels:
app: admin-backend
spec:
containers:
- name: whoami
image: traefik/whoami
env:
- name: WHOAMI_NAME
value: "Admin Backend"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: admin-backend
namespace: default
spec:
selector:
app: admin-backend
ports:
- port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-backend
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: user-backend
template:
metadata:
labels:
app: user-backend
spec:
containers:
- name: whoami
image: traefik/whoami
env:
- name: WHOAMI_NAME
value: "User Backend"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: user-backend
namespace: default
spec:
selector:
app: user-backend
ports:
- port: 80
kubectl apply -f whoami-backends.yaml
接着创建 Secret(存放 htpasswd 账号)、BasicAuth 中间件与三份 IngressRoute(保存为 mlr-ingressroute.yaml):
# mlr-ingressroute.yaml
apiVersion: v1
kind: Secret
metadata:
name: auth-secret
namespace: default
type: Opaque
stringData:
users: |
admin:$apr1$DmXR3Add$wfdbGw6RWIhFb0ffXMM4d0
user:$apr1$GJtcIY1o$mSLdsWYeXpPHVsxGDqadI.
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: auth-middleware
namespace: default
spec:
basicAuth:
secret: auth-secret
headerField: X-Auth-User
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: api-parent
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`api.docker.localhost`) && PathPrefix(`/api`)
kind: Rule
middlewares:
- name: auth-middleware
# Note: No services and no TLS config - this is a parent IngressRoute
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: api-admin
namespace: default
spec:
parentRefs:
- name: api-parent
namespace: default # Optional, defaults to same namespace
routes:
- match: HeadersRegexp(`X-Auth-User`, `admin`)
kind: Rule
services:
- name: admin-backend
port: 80
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: api-user
namespace: default
spec:
parentRefs:
- name: api-parent
namespace: default # Optional, defaults to same namespace
routes:
- match: HeadersRegexp(`X-Auth-User`, `user`)
kind: Rule
services:
- name: user-backend
port: 80
配置要点:
- BasicAuth 中间件的
headerField: X-Auth-User让认证通过后把用户名写入请求头,供下游规则匹配——这是"先鉴权、再分流"的枢纽; - 父 IngressRoute 的 route 只挂中间件、无 services、无 TLS;
- 子 IngressRoute 不声明 entryPoints,仅凭
parentRefs挂接到父级,其中namespace省略时默认同命名空间。
!!! note "生成密码哈希"
上文哈希由 Apache 工具 htpasswd 生成。需要自建账号时执行:
```bash
# Using htpasswd (Apache utils)
htpasswd -nb admin yourpassword
```
应用整份配置:
kubectl apply -f mlr-ingressroute.yaml
在 CRD 层,spec.parentRefs []IngressRouteRef 即为多层路由入口字段(见 ingressroute.go);HTTP provider 会读取每个子路由的 parentRefs 建立父子拓扑并把这些引用并入"父路由器名"集合,处理逻辑见 kubernetes_http.go。
验证多层路由
# Request goes through parent router → auth middleware → admin child router
curl -k -u admin:test -H "Host: api.docker.localhost" https://localhost/api
以 admin:test 认证应得到 admin-backend 的响应;改用 user:test 则命中 user-backend。
工作原理
- 请求到达
api.docker.localhost/api; - 父 IngressRoute(
api-parent)按 host + path 命中; - BasicAuth 中间件完成认证并把用户名写入
X-Auth-User头; - 子 IngressRoute(
api-admin或api-user)按该头的值匹配; - 请求被转发到对应的 Kubernetes Service。
跨命名空间引用父级
在子路由 parentRefs 中显式给出父级所在命名空间即可:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: api-child
namespace: app-namespace
spec:
parentRefs:
- name: api-parent
namespace: shared-namespace # Parent in different namespace
routes:
- match: Path(`/child`)
kind: Rule
services:
- name: child-service
port: 80
!!! important "跨命名空间开关"
使用跨命名空间父引用必须先在 Traefik Helm values 中开启 allowCrossNamespace:
```yaml
providers:
kubernetesCRD:
allowCrossNamespace: true
```
该开关即 CRD provider 配置结构中的 `AllowCrossNamespace` 字段(见 [kubernetes.go](https://gitcode.com/GitHub_Trending/tr/traefik/blob/14bc52dd1f1d1c08cedd1da531a527fc04d79c19/pkg/provider/kubernetes/crd/kubernetes.go?utm_source=gitcode_repo_files)),开启时 Traefik 会打印一条警示日志,提醒你已允许跨命名空间引用资源、请确认符合安全预期。
一个子路由挂接多个父级
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: api-child
namespace: default
spec:
parentRefs:
- name: parent-one
- name: parent-two
routes:
- match: Path(`/api`)
kind: Rule
services:
- name: child-service
port: 80
同一份路由逻辑可被多个入口域/路径共享,减少重复配置。仓库集成测试中也有同构用例(integration/fixtures/routing/multi_layer_auth.toml 即文件 provider 下的多层鉴权示例)。更完整语义参见 多层路由参考文档。
Service Middlewares(服务级中间件)
路由级中间件只在命中某条路由规则时生效;服务级中间件则挂在"服务"上,对流向该服务的所有请求生效——无论流量来自哪个 Router。适合把同一套 headers / 限流 / 鉴权统一下沉到服务层,避免在每个 Router 上重复声明。
何时使用服务级中间件
- 多个 Router 转发到同一服务,且都需要施加同一中间件;
- 需要确保无论流量从何而来,该服务始终经过某个中间件;
- 希望把中间件配置集中在服务层统一管理。
!!! info "服务级 vs 路由级" - 路由级:仅当流量命中该 Router 规则时执行; - 服务级:对该服务收到的全部流量执行; - 两者同时配置时,先执行路由级中间件,再执行服务级中间件。这一顺序由动态配置的服务引用机制保证:请求先穿过路由构建的中间件链,再进入服务内的负载均衡处理器链。
IngressRoute:在 services 项内嵌中间件
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: service-headers
namespace: default
spec:
headers:
customRequestHeaders:
X-Service-Middleware: "applied"
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: whoami
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`whoami.docker.localhost`)
kind: Rule
services:
- name: whoami
port: 80
middlewares:
- name: service-headers
tls: {}
保存为 service-middleware-ingressroute.yaml 并应用:
kubectl apply -f service-middleware-ingressroute.yaml
CRD 类型中,ServiceSpec.middlewares []MiddlewareRef 正是该内嵌引用的定义位置(见 ingressroute.go)。
Gateway API:backendRefs 内置 Filters
Gateway API 支持在单个后端上直接施加 filter:既可用 Traefik 扩展的 ExtensionRef 引用任意 Middleware CRD,也可用原生 RequestHeaderModifier 完成纯增删改头的场景。
ExtensionRef 方式:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: service-headers
namespace: default
spec:
headers:
customRequestHeaders:
X-Service-Middleware: "applied"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami
namespace: default
spec:
parentRefs:
- name: traefik-gateway
sectionName: websecure
hostnames:
- "whoami.docker.localhost"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: whoami
port: 80
filters:
- type: ExtensionRef
extensionRef:
group: traefik.io
kind: Middleware
name: service-headers
原生 RequestHeaderModifier 方式:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami
namespace: default
spec:
parentRefs:
- name: traefik-gateway
sectionName: websecure
hostnames:
- "whoami.docker.localhost"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: whoami
port: 80
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Backend-Header
value: "gateway-api-filter"
保存为 service-middleware-gateway.yaml 并应用:
kubectl apply -f service-middleware-gateway.yaml
标准 Ingress:服务注解方式
使用标准 Kubernetes Ingress 时,用 Service 注解声明服务级中间件:
apiVersion: v1
kind: Service
metadata:
name: whoami
namespace: default
annotations:
traefik.ingress.kubernetes.io/service.middlewares: default-service-headers@kubernetescrd
spec:
selector:
app: whoami
ports:
- port: 80
注解值格式为 <namespace>-<middleware-name>@kubernetescrd,其中 @kubernetescrd 表明中间件来源为 Kubernetes CRD provider。
验证服务级中间件
curl -k -H "Host: whoami.docker.localhost" https://localhost/
whoami 返回体中应能看到由服务级中间件注入的自定义请求头:
X-Service-Middleware: applied
服务级中间件更完整的字段语义见 service.md 中 middlewares 一节。
总结
完成本篇后,你已具备生产级 Traefik on Kubernetes 的关键能力:
- 用 Middleware 施加安全头(HSTS、X-Frame-Options、nosniff 等)与 IP 白名单,在 Gateway API(
ExtensionRef)与 IngressRoute(routes.middlewares)两条路径上都可编排; - 证书自动化双方案:IngressRoute 走内置 Let's Encrypt resolver,Gateway API 走 cert-manager + Gateway
certificateRefs,并理解本地域名下证书保持自签名的约束; - 通过 TraefikService 的加权粘滞 Cookie 为有状态应用启用会话保持,覆盖 Gateway API 与 IngressRoute 两种后端引用形态;
- 用
parentRefs构建"父层鉴权、子层按角色分流"的多层路由,包括跨命名空间(需开启allowCrossNamespace)与多父级引用; - 把中间件下沉到服务层(IngressRoute services 内嵌 / HTTPRoute
backendRefs.filters/ Ingress Service 注解),实现集中化管理。
延伸方向
在 入门指南 与本文基础上,可继续探索:
- 更精细的路由规则与优先级,如按查询参数、请求头、HTTP 方法匹配;
- 更多中间件能力,如鉴权(Basic/Digest/Forward)、限流(ratelimit 等)、请求改写(StripPrefix、AddPrefix 等);
- Kubernetes CRD 与 Gateway API provider 的完整配置项(分别对应
providers.kubernetesCRD与providers.kubernetesGateway),可用于调整命名空间隔离、标签选择器、入口点绑定等行为。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00