Migrar Traefik v2 a v3: qué deja de funcionar
Traefik v3 no arranca si swarmMode o pilot siguen en la configuración estática. Corrige el error exacto y migra las reglas con compatibilidad para v2.
Qué cambia entre Traefik v2 y v3
La migración de Traefik v2 a v3 consiste principalmente en cambiar nombres. El cambio más conocido es que el middleware ipWhiteList pasa a llamarse ipAllowList. Además, v3 endurece la sintaxis de las reglas de los routers: PathPrefix pierde sus funciones de expresiones regulares y se renombran o eliminan varios matchers. También elimina algunos proveedores y opciones. El resto sigue funcionando: los entrypoints, la configuración de certificados ACME, el flujo de trabajo basado en etiquetas de Docker y su acme.json se mantienen. v3 también incluye un modo de compatibilidad que mantiene la sintaxis de reglas de v2. Así puede actualizar primero el binario y reescribir las reglas servicio por servicio, en lugar de hacerlo todo en una tarde con riesgo.
Esta guía presupone la configuración de Docker Compose basada en etiquetas descrita en la guía del proxy inverso Traefik. Esa página usa v3 de forma nativa. Esta guía está dirigida al servidor que todavía ejecuta una etiqueta traefik:v2.
Los cambios de nombre y las eliminaciones
ipWhiteListahora esipAllowList, tanto para el middleware HTTP como para el middleware TCP. Las opciones internas no cambian, por lo quesourcerangeconserva exactamente el mismo significado. Las versiones actuales de v3, incluida v3.5, todavía aceptan el nombre anterior como alias obsoleto y siguen aplicando la lista, por lo que este cambio de nombre no interrumpe nada al actualizar. Cámbielo de todos modos: está previsto eliminar el alias y desaparecerá de la lista de elementos obsoletos sin generar un aviso explícito.providers.docker.swarmMode=trueha desaparecido. Swarm tiene su propio provider, configurado comoproviders.swarm.endpoint.- La sección
pilotha desaparecido por completo. experimental.http3ha desaparecido. HTTP/3 se habilita directamente en el entrypoint.tls.caOptionalha desaparecido de los providers y del middleware forwardAuth. Si ese middleware está delante de un SSO de Authentik autohospedado, eliminar la líneacaOptionalcompleta la migración, porque la dirección de forwardAuth, las cabeceras de confianza y el outpost que hay detrás se comportan igual en v3.- El provider de métricas de InfluxDB v1, el provider de Rancher y el provider de Marathon han desaparecido.
- El tracing se ha trasladado a OpenTelemetry. Los backends de tracing dedicados, incluidas las integraciones con Jaeger y Zipkin, han desaparecido, y v3 exporta OTLP (el protocolo de OpenTelemetry) en su lugar.
- Las opciones obsoletas
ssl*dentro del middleware headers (sslRedirect,sslHosty las demás) han desaparecido. Las redirecciones del entrypoint y el middleware redirectScheme las han sustituido.
Estas eliminaciones son más importantes de lo que parece, porque Traefik no arranca cuando su configuración estática contiene una opción que no reconoce. Una línea pilot o swarmMode que haya quedado detiene el contenedor durante el arranque con un mensaje incompatible deprecated static option found que identifica el elemento sobrante. Una opción que Traefik nunca ha reconocido (un error tipográfico o tls.caOptional) lo detiene con field not found. Limpie la configuración estática antes de cambiar el tag de la imagen.
Un nombre de middleware que Traefik realmente no reconoce (un error tipográfico o un nombre eliminado en lugar de convertido en alias) falla de otra forma: el router que lo referencia se carga con un error en lugar de crear una ruta, el dashboard lo marca y la API devuelve middleware "offce@docker" does not exist. Las peticiones a ese hostname reciben un 404 porque el router nunca se inició. Tenga en cuenta que ipwhitelist NO pertenece a esta categoría en la versión actual de v3: se mantiene como alias obsoleto, por lo que una label que no se haya renombrado sigue funcionando sin avisos.
La sintaxis de las reglas cambia
Las reglas permiten realizar las reescrituras. Estos son los cambios de v3:
- Los valores dentro de los matchers deben estar entre comillas invertidas. v2 también aceptaba comillas dobles; v3 no. Por tanto,
Host("app.example.com")debe convertirse enHost(app.example.com). PathPrefixya no admite expresiones regulares ni marcadores de posición con el formato{id}. Una regla de v2 comoPathPrefix(/api/{version:v[0-9]+})debe convertirse en un matcherPathRegexpescrito con la sintaxis de expresiones regulares de Go.- Los matchers ahora reciben un solo valor. v2 permitía
Host(app.example.com,www.example.com); v3 requiereHost(app.example.com) || Host(www.example.com). Las excepciones sonHeader,HeaderRegexp,QueryyQueryRegexp, que siguen recibiendo un nombre y un valor. HeadersyHeadersRegexpcambian de nombre aHeaderyHeaderRegexp.HostHeaderse elimina. UseHost, que coincide con lo mismo en v3.- Se añaden dos matchers:
QueryRegexpyClientIP, para comprobar la dirección del cliente dentro de una regla.
La ventaja es que una regla Host(app.example.com) sencilla escrita con comillas invertidas ya tiene una sintaxis válida en v3. La mayoría de las configuraciones pequeñas de Compose usan exactamente esta sintaxis, por lo que la mayoría de las etiquetas migran sin modificar las reglas.
Audite sus etiquetas antes de empezar
Puede medir el alcance de la migración con una búsqueda, porque cada cambio incompatible en una etiqueta deja un patrón que grep puede encontrar:
grep -rnE 'ipwhitelist|HostHeader|Headers\(|PathPrefix\(`[^`]*\{|Host\(`[^`]*`,' docker-compose*.ymlCada coincidencia corresponde a una línea que debe editar. ipwhitelist se convierte en ipallowlist. HostHeader se convierte en Host. Headers se convierte en Header. Un marcador de posición {...} dentro de PathPrefix se convierte en un comparador PathRegexp. Una coma dentro de Host() se convierte en dos comparadores Host() unidos mediante ||. Cero coincidencias significa que sus etiquetas ya usan una sintaxis v3 válida y que la migración se reduce a la configuración estática y a la etiqueta de imagen. Una pantalla llena de coincidencias también es un buen momento para preguntarse si este sigue siendo el proxy adecuado para el servidor. cómo se compara Traefik con Nginx y Caddy relaciona ese coste de reescritura con lo que los otros dos le exigen por aplicación.
Qué permanece igual
Los puntos de entrada y su redirección de HTTP a HTTPS, los resolutores ACME con ambos tipos de desafío, exposedByDefault, las etiquetas del router y del servicio, loadbalancer.server.port y el panel siguen funcionando en v3 igual que en v2. Los certificados también se conservan porque v3 sigue leyendo el acme.json que escribió v2. De todos modos, haga una copia de seguridad del archivo antes de empezar. Una reversión que lo pierda activa directamente el límite de tasa de Let's Encrypt para certificados duplicados:
cp ./letsencrypt/acme.json ./letsencrypt/acme.json.v2-backupRuta de migración
Paso 1: fije lo que ejecuta hoy. Cambie cualquier etiqueta traefik:latest o traefik:v2 por la versión exacta que utiliza, por ejemplo traefik:v2.11, y confirme todo el directorio de compose en git. Cada paso posterior se podrá revertir con un checkout. Si todavía no domina la recreación de un solo servicio con docker compose up -d <service>, la guía básica de Docker Compose explica las operaciones en las que se basa esta migración.
Paso 2: limpie la configuración estática y active el modo de compatibilidad. Elimine todas las opciones que v3 eliminó (pilot, swarmMode, tls.caOptional, experimental.http3) y haga que v3 interprete las reglas como sintaxis de v2 de forma predeterminada. En traefik.yml:
core:
defaultRuleSyntax: v2También puede especificarlo como una opción en la lista de compose command:: --core.defaultRuleSyntax=v2. El modo de compatibilidad sólo cubre la sintaxis de las reglas. No recupera las opciones eliminadas ni cambia los nombres de los middlewares.
Paso 3: prepare los cambios de nombre de los middlewares. Busque los nombres antiguos en los archivos de compose: grep -rn ipwhitelist docker-compose*.yml. Edite cada etiqueta ipwhitelist para convertirla en ipallowlist, pero no aplique todavía el cambio, porque el nombre nuevo no existe en v2. Estos cambios se aplican junto con la activación del paso siguiente. (Si alguno se queda atrás, la versión actual de v3 todavía reconoce el nombre antiguo como alias obsoleto, por lo que la lista seguirá aplicándose; corríjalo en la siguiente pasada y no a las 2 de la madrugada).
Paso 4: cambie la etiqueta de la imagen. Establezca la imagen de Traefik en la versión actual de v3, traefik:v3.5 en el momento de redactar este texto, y ejecute:
docker compose up -d
docker compose logs -f traefikComo el modo de compatibilidad está activo, las reglas de v2 seguirán coincidiendo. Además, como up -d también recreó los servicios cuyos labels de middleware cambió, esos routers se iniciarán correctamente. En un registro correcto no aparece ninguna línea field not found ni ninguna línea does not exist.
Sea consciente del intervalo de riesgo que abre este paso. Un router que haga referencia a un nombre de middleware que v3 realmente no reconoce (por un error tipográfico o por una opción eliminada) queda inactivo desde el momento en que se inicia el Traefik nuevo hasta que se recrea su contenedor de aplicación. En un único servidor, esto dura los pocos segundos que docker compose up -d necesita para procesar la lista. Si una ruta no puede interrumpirse, elimine el middleware renombrado de la etiqueta middlewares de ese router antes del cambio y vuelva a añadirlo después. Decida de antemano si esa ruta puede funcionar sin su lista de direcciones IP permitidas durante el minuto intermedio.
Paso 5: migre las reglas servicio por servicio. Trabaje con una aplicación cada vez: reescriba su regla con la sintaxis de v3, recree sólo ese servicio con docker compose up -d app y pruébelo antes de continuar. Si un servicio tiene una regla que todavía no puede reescribir, asígnele a ese router la etiqueta de excepción traefik.http.routers.app.ruleSyntax=v2 y continúe.
Paso 6: desactive el modo de compatibilidad. Cuando todas las reglas usen la sintaxis de v3, elimine defaultRuleSyntax y cualquier etiqueta ruleSyntax, reinicie Traefik y confirme que todos los routers sigan apareciendo en verde en el dashboard. No mantenga el modo de compatibilidad activado: Traefik declaró obsoletas ambas opciones en v3.4 y las eliminará en la siguiente versión principal. Son un puente, no un destino.
Antes y después: las etiquetas de un servicio
Esta es una aplicación que incorpora todos los cambios conocidos a la vez: un Host con varios valores, un marcador de posición PathPrefix y un middleware ipWhiteList. El bloque de 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=8080Y el mismo servicio migrado a 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=8080Cambiaron dos etiquetas. La regla dividió su Host con varios valores en dos matchers unidos mediante || y sustituyó el marcador de posición por PathRegexp. La etiqueta del middleware sustituyó ipwhitelist por ipallowlist. El entrypoint, el certificate resolver, la conexión entre el router y el middleware, y el puerto del servicio no cambiaron.
Pruebe cada servicio con el dashboard
Después de cada cambio, abra la página de routers HTTP del dashboard. Todos los routers deben aparecer en verde. Un router con una insignia de error muestra el problema exacto. Normalmente se trata de un middleware que no existe con su nuevo nombre o de una regla v3 que no se puede analizar. Después, confirme el funcionamiento desde fuera, un nombre de host cada vez:
curl -sI https://app.example.com/api/v1/statusUn 200 o la redirección habitual de su aplicación indica que el enrutamiento y TLS siguen funcionando. Un 404 de Traefik indica que el router no se inició. Vuelva al dashboard y lea el error. Mantenga docker compose logs -f traefik abierto en un segundo terminal mientras trabaja, porque todos los errores de análisis aparecen allí en cuanto se reinicia un contenedor.
Honestidad del rollback
Conserve el archivo compose de v2, su configuración estática y la copia de seguridad de acme.json hasta que todos los servicios se enruten mediante v3 y se hayan probado en condiciones reales. Hacer rollback significa recuperar el commit anterior a la migración y ejecutar docker compose up -d. Debe recuperarse el archivo completo, no sólo la etiqueta de la imagen, porque las etiquetas exclusivas de v3 son incorrectas en v2, igual que las etiquetas de v2 eran incorrectas en v3: ipallowlist no existe en v2, y un comparador PathRegexp tampoco se puede analizar allí. Si acme.json se perdió o se dañó durante el proceso, restaure la copia de seguridad antes de iniciar v2. Así, el rollback no consumirá el límite de solicitudes de Let's Encrypt al volver a emitir cinco certificados a la vez.
FAQ
¿Tengo que reescribir todas las reglas de los routers para Traefik v3?
No. Una regla simple Host(app.example.com) escrita con comillas invertidas es válida en ambas versiones y cubre la mayoría de las configuraciones de Compose. Sólo es necesario reescribir las reglas que usaban funciones exclusivas de v2: expresiones regulares o marcadores de posición dentro de `Path y PathPrefix, varios nombres de host dentro de un mismo Host(), comillas en lugar de comillas invertidas, o los matchers eliminados Headers, HeadersRegexp y HostHeader`.
¿Qué ocurrió con ipWhiteList en Traefik v3?
Se cambió su nombre a `ipAllowList, sin modificar la configuración interna. Por tanto, una etiqueta de v2 como traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24 se convierte en la misma línea con ipallowlist`. Las versiones actuales de v3, incluida v3.5, todavía aceptan el nombre antiguo como alias obsoleto. Por eso, una etiqueta sin renombrar sigue aplicando la lista de permitidos sin mostrar errores. Considérelo una solución temporal, no un motivo para omitir el cambio de nombre: está previsto eliminar el alias, y un nombre de middleware que Traefik realmente no reconoce falla de forma explícita, con un error del router y un 404. El dashboard muestra el error y las peticiones a ese nombre de host devuelven 404.
¿Traefik v3 todavía puede leer la sintaxis de reglas de v2?
Sí. Establezca `core.defaultRuleSyntax: v2 en la configuración estática para mantener la sintaxis de v2 como valor predeterminado durante la migración. Después de restaurar el valor predeterminado, use la etiqueta ruleSyntax=v2` por router para los casos individuales que queden pendientes. Ambas opciones son temporales: Traefik las declaró obsoletas en v3.4 y las eliminará en la siguiente versión principal.
¿Mis certificados de Let's Encrypt sobrevivirán a la actualización?
Sí. Traefik v3 sigue leyendo el archivo `acme.json que escribió v2, por lo que los certificados no se vuelven a emitir sólo porque haya cambiado el binario. Aun así, copie el archivo en una ubicación segura antes de empezar. Una reversión o un volumen eliminado que pierda acme.json` obliga a volver a emitir todos los certificados a la vez. Let's Encrypt permite sólo cinco certificados duplicados por semana para el mismo conjunto de nombres de host.
¿Por qué Traefik v3 no se inicia después de la actualización?
Casi siempre se debe a que la configuración estática todavía contiene una opción que v3 eliminó. Traefik se niega a iniciarse cuando encuentra opciones que no reconoce. Para las opciones obsoletas conocidas (`pilot, providers.docker.swarmMode, experimental.http3), el registro muestra incompatible deprecated static option found y señala la causa. Para cualquier opción que v3 nunca haya reconocido, como tls.caOptional, muestra field not found` junto con el nodo correspondiente. Elimine o sustituya cada opción y vuelva a iniciar el contenedor.