Traefik v2 升级 v3:哪些配置会失效?
Traefik v3 启动时报错“incompatible deprecated static option found”怎么办?删除静态配置中的 swarmMode 或 pilot,再迁移路由规则与中间件。
Traefik v2 和 v3 有哪些变化
从 Traefik v2 迁移到 v3 主要是重命名工作,最典型的变更是将 ipWhiteList 中间件重命名为 ipAllowList。除此之外,v3 收紧了路由规则语法(PathPrefix 不再支持正则表达式功能,部分匹配器已重命名或移除),并直接删除了部分 provider 和选项,但其他配置仍可继续使用:entrypoints、ACME 证书配置、Docker 标签工作流以及您的 acme.json 都可以沿用。v3 还提供兼容模式,可继续使用 v2 规则语法。这样您可以先升级二进制文件,再逐个服务重写规则,而不必在一个高风险的晚上一次性完成全部变更。
本指南假设您使用 Traefik 反向代理指南 中基于标签的 Docker Compose 配置。该页面采用 v3 原生配置;本指南适用于仍在运行 traefik:v2 标签的服务器。
重命名和移除项
ipWhiteList现在改为ipAllowList,HTTP 和 TCP 中间件都一样。内部选项未变,因此sourcerange的含义完全不变。当前 v3 版本(包括 v3.5)仍接受旧名称作为已弃用别名,并继续强制执行列表,因此这次重命名不会在切换时导致服务中断。但仍应完成重命名:该别名计划移除,届时会从弃用列表中静默消失,而不会发出明显提示。providers.docker.swarmMode=true已移除。Swarm 现在使用独立的 provider,配置项为providers.swarm.endpoint。pilot部分已完全移除。experimental.http3已移除。HTTP/3 现在直接在 entrypoint 上启用。tls.caOptional已从 providers 和 forwardAuth 中间件中移除。如果该中间件代理 自托管的 Authentik SSO,迁移时只需删除caOptional行,因为 v3 中 forwardAuth 地址、受信任标头及其背后的 outpost 行为都不变。- InfluxDB v1 metrics provider、Rancher provider 和 Marathon provider 已移除。
- tracing 已迁移到 OpenTelemetry。专用 tracing 后端(包括 Jaeger 和 Zipkin 集成)已移除,v3 改为导出 OTLP(OpenTelemetry 协议)。
- headers 中间件中的已弃用
ssl*选项(sslRedirect、sslHost及其他选项)已移除。现在应使用 entrypoint 重定向和 redirectScheme 中间件。
这些移除项的影响比表面看起来更大,因为静态配置包含 Traefik 不识别的选项时,Traefik 会拒绝启动。遗留的 pilot 或 swarmMode 行会在容器启动时停止启动,并显示包含遗留配置名称的 incompatible deprecated static option found 消息;Traefik 从未识别过的选项(例如拼写错误或 tls.caOptional)则会显示 field not found。更换镜像标签前,先清理静态配置。
Traefik 确实不识别的中间件名称(例如拼写错误,或已移除而不是保留别名的名称)会以另一种方式失败:引用它的 router 会加载失败,而不是生成路由;dashboard 会标记该问题,API 会报告 middleware "offce@docker" does not exist。由于 router 从未启动,发送到该主机名的请求会获得 404。请注意,在当前 v3 中,ipwhitelist 不属于此类:它仍作为已弃用别名保留,因此未重命名的 label 仍可正常工作。
规则语法发生变化
规则是实际执行重写的地方。v3 的变化如下:
- 匹配器中的值必须使用反引号。v2 也接受双引号;v3 不再接受。因此,Host("app.example.com") 必须改为 Host(
app.example.com)。 PathPrefix不再理解正则表达式或{id}样式的占位符。v2 中的 PathPrefix(/api/{version:v[0-9]+}) 规则必须改为使用 Go 正则表达式语法编写的PathRegexp匹配器。- 匹配器现在只接受一个值。v2 允许 Host(
app.example.com,www.example.com);v3 要求使用 Host(app.example.com) || Host(www.example.com)。例外是Header、HeaderRegexp、Query和QueryRegexp,它们仍然接受名称和值。 Headers和HeadersRegexp重命名为Header和HeaderRegexp。HostHeader已移除。请使用Host;它在 v3 中匹配相同的内容。- 新增了两个匹配器:
QueryRegexp,以及用于在规则中匹配客户端地址的ClientIP。
好消息是:使用反引号编写的普通 Host(app.example.com) 规则已经符合 v3 语法。大多数小型 Compose 部署正是这样配置的,因此大多数标签无需修改规则即可完成迁移。
开始前审计标签
只需执行一次搜索,即可估算迁移规模,因为每个不兼容的标签变更都会留下可由 grep 查找的模式:
grep -rnE 'ipwhitelist|HostHeader|Headers\(|PathPrefix\(`[^`]*\{|Host\(`[^`]*`,' docker-compose*.yml每个匹配结果对应一行需要修改的配置。ipwhitelist 改为 ipallowlist。HostHeader 改为 Host。Headers 改为 Header。{...} 中的 PathPrefix 占位符改为 PathRegexp 匹配器。Host() 中的逗号改为两个由 || 连接的 Host() 匹配器。没有匹配结果,表示标签已经符合 v3 语法,迁移工作可缩减为静态配置和镜像标签。若匹配结果充满整个屏幕,也可以借此评估该代理是否仍适合这台主机;Traefik 与 Nginx 和 Caddy 的比较 会将这部分重写成本,与另外两者要求您为每个应用完成的工作进行对比。
保持不变的部分
入口点及其 HTTP 到 HTTPS 的重定向、支持两种质询类型的 ACME 解析器、exposedByDefault、路由器和服务标签、loadbalancer.server.port 以及仪表板,在 v3 中的工作方式与 v2 相同。证书也会继续保留,因为 v3 仍会读取 v2 写入的 acme.json。不过,开始前仍应备份该文件,因为回滚时如果丢失它,就会直接触发 Let's Encrypt 的重复证书速率限制:
cp ./letsencrypt/acme.json ./letsencrypt/acme.json.v2-backup迁移路径
Step 1:固定当前运行的版本。 将所有 traefik:latest 或 traefik:v2 标签改为当前使用的确切版本,例如 traefik:v2.11,并将整个 compose 目录提交到 git。之后的每一步都可以通过 checkout 回滚。如果你还不熟悉使用 docker compose up -d <service> 重建单个服务,请参阅Docker Compose 基础指南,其中介绍了本次迁移所依赖的操作。
Step 2:清理静态配置并启用兼容模式。 删除 v3 已移除的所有选项(pilot、swarmMode、tls.caOptional、experimental.http3),然后让 v3 默认按 v2 语法处理规则。在 traefik.yml 中:
core:
defaultRuleSyntax: v2也可以在 compose 的 command: 列表中通过标志启用:--core.defaultRuleSyntax=v2。兼容模式只覆盖规则语法。它不会恢复已移除的选项,也不会自动重命名中间件。
Step 3:准备中间件重命名。 在 compose 文件中搜索旧名称:grep -rn ipwhitelist docker-compose*.yml。将每个 ipwhitelist 标签编辑为 ipallowlist,但暂时不要应用更改,因为 v2 中不存在新名称。这些编辑将在下一步与版本切换一起发布。(如果有遗漏,当前 v3 仍会将旧名称作为已弃用别名处理,因此列表仍会继续生效;在下一轮修复即可,不必等到凌晨 2 点处理。)
Step 4:切换镜像标签。 将 Traefik 镜像设置为当前 v3 版本,撰写本文时为 traefik:v3.5,然后执行:
docker compose up -d
docker compose logs -f traefik由于已启用兼容模式,现有 v2 规则仍会匹配;由于 up -d 也重建了中间件标签已重命名的服务,这些路由器可以正常启动。健康的日志中不应出现 field not found 行,也不应出现 does not exist 行。
请认真评估这一步产生的中断窗口。只要新 Traefik 启动,引用了 v3 实际无法识别的中间件名称的路由器就会停止工作。这可能是拼写错误,也可能是已移除的选项。直到重新创建其应用容器前,它都会保持停止状态。在单机环境中,docker compose up -d 通常只需几秒即可处理完列表。如果某条路由确实不能中断,请在切换前从该路由的 middlewares 标签中删除已重命名的中间件,切换后再加回,并提前决定这条路由是否可以在中间这 1 分钟内不使用其 IP allow 列表。
Step 5:逐个服务迁移规则。 一次处理一个应用:将其规则改写为 v3 语法,使用 docker compose up -d app 仅重建该服务,并在继续下一个服务前完成测试。如果某个服务的规则暂时无法改写,请为该路由器添加逃生标签 traefik.http.routers.app.ruleSyntax=v2,然后继续迁移。
Step 6:关闭兼容模式。 当所有规则都已使用 v3 语法后,删除 defaultRuleSyntax 以及所有 ruleSyntax 标签,重启 Traefik,并确认仪表板中的每个路由器仍显示绿色。不要长期启用兼容模式:Traefik 已在 v3.4 中将这两个选项标记为已弃用,并会在下一个主版本中移除它们。因此,兼容模式只是过渡方案,不是最终配置。
迁移前后:一个服务的标签
下面是一个一次性包含所有典型变更的应用:多值 Host、PathPrefix 占位符,以及 ipWhiteList 中间件。v2 配置块:
app:
image: app:1.4
restart: unless-stopped
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`app.example.com`,`www.example.com`) && PathPrefix(`/api/{version:v[0-9]+}`)
- traefik.http.routers.app.entrypoints=websecure
- traefik.http.routers.app.tls.certresolver=le
- traefik.http.routers.app.middlewares=office
- traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24
- traefik.http.services.app.loadbalancer.server.port=8080同一服务迁移到 v3 后:
app:
image: app:1.4
restart: unless-stopped
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=(Host(`app.example.com`) || Host(`www.example.com`)) && PathRegexp(`^/api/v[0-9]+`)
- traefik.http.routers.app.entrypoints=websecure
- traefik.http.routers.app.tls.certresolver=le
- traefik.http.routers.app.middlewares=office
- traefik.http.middlewares.office.ipallowlist.sourcerange=10.0.0.0/24
- traefik.http.services.app.loadbalancer.server.port=8080有两个标签发生了变化。规则将多值 Host 拆分为两个由 || 连接的匹配器,并将占位符替换为 PathRegexp;中间件标签则将 ipwhitelist 替换为 ipallowlist。入口点、证书解析器、路由器到中间件的关联关系,以及服务端口均未改变。
使用控制面板测试每项服务
每次切换后,打开控制面板的 HTTP 路由页面。所有路由都应显示为绿色。带有错误标记的路由会指出具体问题。通常是中间件在更名后不存在,或规则 v3 无法解析。然后从外部逐个主机名确认:
curl -sI https://app.example.com/api/v1/status出现 200 或应用的正常重定向,表示路由和 TLS 均正常。Traefik 返回 404,表示路由未启动;返回控制面板并查看错误信息。操作期间,在第二个终端中保持 docker compose logs -f traefik 打开,因为每次容器重启时,所有解析失败都会立即记录在那里。
回滚必须完整可靠
在所有服务都已通过 v3 路由并经过实际验证之前,请保留 v2 compose 文件、其静态配置以及 acme.json 备份。回滚意味着检出迁移前的提交并运行 docker compose up -d。必须回滚整个文件,不能只修改镜像标签,因为仅适用于 v3 的标签在 v2 下同样无效,正如 v2 标签在 v3 下无效一样:v2 中不存在 ipallowlist,PathRegexp 匹配器在那里也无法解析。如果 acme.json 在过程中丢失或损坏,请在启动 v2 之前恢复备份副本,避免回滚一次性重新签发 5 个证书,耗尽 Let's Encrypt 的速率限制。
FAQ
是否必须为 Traefik v3 重写每条路由规则?
不必。使用反引号编写的普通 Host(app.example.com) 规则在两个版本中都有效,足以覆盖大多数 Compose 配置。只有在规则使用 v2 专属功能时才需要重写,例如在 Path 和 PathPrefix 中使用正则表达式或占位符、在一个 Host() 中写入多个主机名、使用引号而不是反引号,或使用已移除的 Headers、HeadersRegexp 和 HostHeader 匹配器。
Traefik v3 中的 ipWhiteList 怎么了?
它已重命名为 ipAllowList,配置内容保持不变。因此,v2 标签 traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24 会变成其中包含 ipallowlist 的同一行。当前的 v3 版本(包括 v3.5)仍将旧名称作为已弃用的别名接受,因此未重命名的标签仍会静默执行允许列表。应将其视为临时兼容,而不是跳过重命名的理由:该别名计划移除;如果中间件名称是 Traefik 确实不认识的名称,系统会直接报错,并返回路由错误和 404。控制面板会显示错误,向该主机名发送的请求也会返回 404。
Traefik v3 仍能读取 v2 规则语法吗?
可以。在静态配置中设置 core.defaultRuleSyntax: v2,即可在迁移期间继续将 v2 语法设为默认值;恢复使用 v3 默认语法后,可通过各路由器的 ruleSyntax=v2 标签处理个别遗留规则。两者都应视为临时配置:Traefik 已在 v3.4 中将其弃用,并会在下一个主版本中移除。
升级后,我的 Let's Encrypt 证书还能保留吗?
可以。Traefik v3 会继续读取 v2 写入的 acme.json 文件,因此不会仅因二进制文件发生变化就重新签发证书。不过,开始升级前仍应将该文件复制到安全位置,因为回滚或删除卷导致 acme.json 丢失时,必须一次性重新签发所有证书;而 Let's Encrypt 对同一组主机名每周最多允许 5 个重复证书。
为什么升级后 Traefik v3 无法启动?
几乎总是因为静态配置仍包含 v3 已移除的选项,而 Traefik 遇到无法识别的选项时会拒绝启动。对于常见的遗留选项(pilot、providers.docker.swarmMode、experimental.http3),日志会显示 incompatible deprecated static option found 并指出问题选项;对于 v3 从未支持的选项(例如 tls.caOptional),日志会显示 field not found 及其配置节点。删除或替换每个选项,然后重新启动容器。