Migração do Traefik v2 para v3: o que quebra
O Traefik v3 falha ao iniciar com swarmMode ou pilot na configuração estática. Remova a opção incompatível e migre as regras dos routers.
O que muda entre o Traefik v2 e o v3
A migração do Traefik v2 para o v3 consiste sobretudo em renomear componentes. A alteração mais conhecida é a mudança do middleware ipWhiteList para ipAllowList. Além disso, o v3 torna a sintaxe das regras dos routers mais rigorosa. PathPrefix deixa de aceitar funcionalidades de expressões regulares, e vários matchers são renomeados ou removidos. Alguns providers e opções também deixam de existir. O restante continua a funcionar: entrypoints, a configuração de certificados ACME, o fluxo de trabalho com labels do Docker e o seu acme.json são mantidos. O v3 também inclui um modo de compatibilidade que mantém o funcionamento da sintaxe de regras do v2. Assim, pode atualizar primeiro o binário e reescrever as regras de um serviço de cada vez, em vez de fazer toda a alteração numa única sessão com risco elevado.
Este guia pressupõe a configuração baseada em labels do Docker Compose descrita em o guia do reverse proxy Traefik. Essa página usa o v3 de forma nativa. Este guia destina-se ao servidor que ainda executa uma tag traefik:v2.
Os renomeamentos e as remoções
ipWhiteListpassa a seripAllowList, tanto para o middleware HTTP como para o middleware TCP. As opções internas não mudam, por issosourcerangemantém exatamente o mesmo significado. As versões v3 atuais, incluindo a v3.5, ainda aceitam o nome antigo como alias obsoleto e continuam a aplicar a lista. Este renomeamento, por si só, não interrompe nada durante a mudança. Faça o renomeamento mesmo assim: o alias está programado para ser removido e desaparece silenciosamente da lista de obsolescências, sem aviso explícito.providers.docker.swarmMode=truefoi removido. O Swarm tem agora o seu próprio provider, configurado comoproviders.swarm.endpoint.- A secção
pilotfoi removida por completo. experimental.http3foi removido. O HTTP/3 é ativado diretamente no entrypoint.tls.caOptionalfoi removido dos providers e do middleware forwardAuth. Se esse middleware estiver à frente de um SSO Authentik alojado por si, eliminar a linhacaOptionalé toda a migração necessária, porque o endereço forwardAuth, os cabeçalhos de confiança e o outpost por trás deles funcionam da mesma forma na v3.- O provider de métricas InfluxDB v1, o provider Rancher e o provider Marathon foram removidos.
- O tracing foi transferido para OpenTelemetry. Os backends de tracing dedicados, incluindo as integrações Jaeger e Zipkin, foram removidos. A v3 exporta OTLP (o protocolo OpenTelemetry) em vez disso.
- As opções
ssl*obsoletas dentro do middleware headers (sslRedirect,sslHoste as restantes) foram removidas. Os redirecionamentos do entrypoint e o middleware redirectScheme substituíram-nas.
Estas remoções são mais importantes do que parecem, porque o Traefik recusa iniciar quando a configuração estática contém uma opção que não conhece. Uma linha pilot ou swarmMode esquecida interrompe o contentor durante o arranque com uma mensagem incompatible deprecated static option found que identifica o elemento restante. Uma opção que o Traefik nunca reconheceu, como um erro de escrita ou tls.caOptional, interrompe o arranque com field not found. Limpe a configuração estática antes de alterar a tag da imagem.
Um nome de middleware que o Traefik realmente não conhece, devido a um erro de escrita ou porque foi removido em vez de receber um alias, falha de outra forma: o router que o referencia é carregado com um erro em vez de uma rota, o dashboard assinala-o e a API devolve middleware "offce@docker" does not exist. Os pedidos para esse hostname recebem um 404 porque o router nunca foi iniciado. Tenha em atenção que ipwhitelist NÃO pertence a esta categoria na v3 atual: continua disponível como alias obsoleto, por isso um label sem renomeação continua a funcionar silenciosamente.
A sintaxe das regras muda
As regras permitem fazer o reescrita efetiva. Estas são as alterações na v3:
- Os valores dentro dos matchers têm de estar entre acentos graves. A v2 também aceitava aspas duplas; a v3 não aceita. Por isso,
Host("app.example.com")tem de passar aHost(app.example.com). PathPrefixjá não interpreta expressões regulares nem marcadores no estilo{id}. Uma regra da v2 comoPathPrefix(/api/{version:v[0-9]+})tem de passar a usar um matcherPathRegexpescrito com a sintaxe de expressões regulares do Go.- Os matchers agora aceitam um único valor. A v2 permitia
Host(app.example.com,www.example.com); a v3 requerHost(app.example.com) || Host(www.example.com). As exceções sãoHeader,HeaderRegexp,QueryeQueryRegexp, que continuam a aceitar um nome e um valor. HeaderseHeadersRegexppassam a chamar-seHeadereHeaderRegexp.HostHeaderfoi removido. UseHost, que corresponde ao mesmo na v3.- Foram adicionados dois matchers:
QueryRegexpeClientIP, para corresponder ao endereço do cliente dentro de uma regra.
A boa notícia é que uma regra simples Host(app.example.com) escrita com acentos graves já é válida na sintaxe da v3. A maioria das configurações pequenas do Compose usa exatamente esse formato. Por isso, a maioria dos labels migra sem alterações nas regras.
Audite os seus labels antes de começar
Pode medir a dimensão da migração com uma pesquisa, porque cada alteração incompatível de um label deixa um padrão que o grep consegue encontrar:
grep -rnE 'ipwhitelist|HostHeader|Headers\(|PathPrefix\(`[^`]*\{|Host\(`[^`]*`,' docker-compose*.ymlCada ocorrência corresponde a uma linha para editar. ipwhitelist passa a ipallowlist. HostHeader passa a Host. Headers passa a Header. Um placeholder {...} dentro de PathPrefix passa a ser um matcher PathRegexp. Uma vírgula dentro de Host() passa a ser dois matchers Host() ligados por ||. Zero ocorrências significa que os seus labels já usam uma sintaxe v3 válida, e a migração fica limitada à configuração estática e à tag da imagem. Uma tela cheia de ocorrências também é um bom momento para perguntar se este ainda é o proxy certo para o servidor, e como o Traefik se compara com o Nginx e o Caddy relaciona esse custo de reescrita com o que os outros dois exigem de si por aplicação.
O que permanece igual
Os entrypoints e o respetivo redirecionamento de HTTP para HTTPS, os resolvers ACME com os dois tipos de desafio, exposedByDefault, os labels de routers e serviços, loadbalancer.server.port e o dashboard continuam a funcionar na v3 como funcionavam na v2. Os seus certificados também são mantidos, porque a v3 continua a ler o acme.json criado pela v2. Faça uma cópia de segurança do ficheiro antes de começar. Assim, evita que um rollback que o perca atinja diretamente o limite de taxa de certificados duplicados da Let's Encrypt:
cp ./letsencrypt/acme.json ./letsencrypt/acme.json.v2-backupO caminho de migração
Passo 1: fixe o que executa atualmente. Altere qualquer etiqueta traefik:latest ou traefik:v2 para a release exata que está a utilizar, por exemplo, traefik:v2.11, e faça commit de todo o diretório do compose no git. Todos os passos seguintes podem ser revertidos com um checkout. Se ainda não recria um único serviço com docker compose up -d <service> de forma natural, o guia básico do Docker Compose explica as operações utilizadas nesta migração.
Passo 2: limpe a configuração estática e ative o modo de compatibilidade. Remova todas as opções que a v3 deixou de suportar (pilot, swarmMode, tls.caOptional, experimental.http3) e configure a v3 para interpretar as regras como sintaxe da v2 por predefinição. Em traefik.yml:
core:
defaultRuleSyntax: v2Também pode utilizar uma flag na lista command: do compose: --core.defaultRuleSyntax=v2. O modo de compatibilidade abrange apenas a sintaxe das regras. Não recupera opções removidas nem renomeia middlewares.
Passo 3: prepare a renomeação dos middlewares. Procure nos ficheiros do compose os nomes antigos: grep -rn ipwhitelist docker-compose*.yml. Edite cada etiqueta ipwhitelist para ipallowlist, mas não aplique ainda a alteração, porque o novo nome não existe na v2. Estas edições devem ser aplicadas juntamente com a mudança do modo no passo seguinte. (Se algum nome ficar por alterar, a v3 atual continua a aceitar o nome antigo como alias obsoleto, pelo que o encaminhamento continua a funcionar; corrija-o na passagem seguinte, e não às 2 da manhã.)
Passo 4: altere a etiqueta da imagem. Defina a imagem do Traefik para a release atual da v3, traefik:v3.5 no momento da redação, e execute:
docker compose up -d
docker compose logs -f traefikComo o modo de compatibilidade está ativo, as regras da v2 continuam a corresponder. Além disso, up -d recriou os serviços cujas etiquetas de middleware renomeou, pelo que esses routers arrancam corretamente. Um log saudável não contém nenhuma linha field not found nem nenhuma linha does not exist.
Seja realista quanto à janela de indisponibilidade que este passo abre. Um router que referencia um nome de middleware que a v3 realmente não reconhece, por exemplo, devido a um erro de escrita ou a uma opção removida, fica indisponível desde o arranque do novo Traefik até à recriação do respetivo contentor da aplicação. Num único servidor, isto corresponde aos poucos segundos de que docker compose up -d precisa para processar a lista. Se uma rota não puder ficar indisponível nem por instantes, remova o middleware renomeado da etiqueta middlewares desse router antes da alteração e volte a adicioná-lo depois. Decida antecipadamente se essa rota pode funcionar sem a lista de IPs permitidos durante o minuto intermédio.
Passo 5: migre as regras serviço a serviço. Trabalhe numa aplicação de cada vez: reescreva a regra para a sintaxe da v3, recrie apenas esse serviço com docker compose up -d app e teste-o antes de continuar. Se um serviço tiver uma regra que ainda não consegue reescrever, atribua a esse router a etiqueta de escape traefik.http.routers.app.ruleSyntax=v2 e continue.
Passo 6: desative o modo de compatibilidade. Quando todas as regras estiverem na sintaxe da v3, elimine defaultRuleSyntax e quaisquer etiquetas ruleSyntax, reinicie o Traefik e confirme que todos os routers continuam verdes no dashboard. Não mantenha o modo de compatibilidade ativo: o Traefik marcou ambas as opções como obsoletas na v3.4 e irá removê-las na próxima versão principal. São uma ponte, não o destino.
Antes e depois: os labels de um serviço
Esta é uma aplicação com todas as alterações mais comuns ao mesmo tempo: um Host com vários valores, um placeholder PathPrefix e um middleware ipWhiteList. O bloco 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=8080E o mesmo serviço migrado para 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=8080Dois labels foram alterados. A regra dividiu o Host com vários valores em dois matchers ligados por || e substituiu o placeholder por PathRegexp. O label do middleware substituiu ipwhitelist por ipallowlist. O entrypoint, o resolver de certificados, a ligação entre o router e o middleware e a porta do serviço não foram alterados.
Teste cada serviço com o dashboard
Depois de cada alteração, abra a página de routers HTTP do dashboard. Todos os routers devem estar verdes. Um router com um indicador de erro identifica o problema exato. Normalmente, trata-se de um middleware que não existe com o novo nome ou de uma regra v3 que não pode ser analisada. Em seguida, confirme o acesso a partir do exterior, um hostname de cada vez:
curl -sI https://app.example.com/api/v1/statusUm 200 ou o redirecionamento normal da sua aplicação indica que o encaminhamento e o TLS continuam a funcionar. Um 404 do Traefik indica que o router não iniciou. Volte ao dashboard e leia o erro. Mantenha docker compose logs -f traefik aberto num segundo terminal enquanto trabalha, porque todas as falhas de análise aparecem nesse local assim que um container é reiniciado.
Honestidade no rollback
Mantenha o ficheiro Compose da v2, a respetiva configuração estática e o backup acme.json até todos os serviços serem encaminhados pela v3 e terem sido testados em condições reais. Fazer rollback significa consultar o commit anterior à migração e executar docker compose up -d. É necessário reverter o ficheiro completo, e não apenas a tag da imagem, porque os labels exclusivos da v3 são inválidos na v2, tal como os labels da v2 eram inválidos na v3: ipallowlist não existe na v2, e um matcher PathRegexp também não será analisado nessa versão. Se acme.json tiver sido perdido ou danificado durante o processo, restaure a cópia de backup antes de iniciar a v2. Assim, o rollback não consumirá o seu limite de requisições da Let's Encrypt ao emitir novamente cinco certificados de uma só vez.
FAQ
Tenho de reescrever todas as regras dos routers para o Traefik v3?
Não. Uma regra simples Host(app.example.com) escrita com crases é válida nas duas versões e cobre a maioria das configurações do Compose. Só é necessário reescrever regras que usavam funcionalidades exclusivas da v2: expressões regulares ou placeholders dentro de Path e PathPrefix, vários nomes de host dentro de um único Host(), aspas em vez de crases ou os matchers removidos Headers, HeadersRegexp e HostHeader.
O que aconteceu ao ipWhiteList no Traefik v3?
Foi renomeado para ipAllowList. A configuração interna não mudou, por isso um label da v2 como traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24 passa a ser a mesma linha com ipallowlist. As versões atuais da v3, incluindo a v3.5, ainda aceitam o nome antigo como alias obsoleto. Assim, um label não renomeado continua a aplicar silenciosamente a allowlist. Considere isto uma solução temporária, não uma razão para adiar a renomeação: o alias está programado para ser removido. Um nome de middleware que o Traefik realmente não conhece falha explicitamente, com um erro no router e uma resposta 404. O dashboard apresenta o erro, e os pedidos para esse hostname devolvem 404.
O Traefik v3 ainda consegue ler a sintaxe de regras da v2?
Sim. Defina core.defaultRuleSyntax: v2 na configuração estática para manter a sintaxe da v2 como predefinição durante a migração. Depois de voltar a mudar a predefinição, use o label ruleSyntax=v2 por router para os casos individuais que ainda não foram migrados. Considere ambas as opções temporárias: o Traefik marcou-as como obsoletas na v3.4 e irá removê-las na próxima versão principal.
Os meus certificados Let's Encrypt vão continuar disponíveis depois da atualização?
Sim. O Traefik v3 continua a ler o ficheiro acme.json criado pela v2. Por isso, os certificados não são emitidos novamente apenas porque o binário mudou. Ainda assim, copie o ficheiro para um local seguro antes de começar. Um rollback ou um volume eliminado que perca acme.json obriga a emitir novamente todos os certificados de uma só vez. O Let's Encrypt permite apenas cinco certificados duplicados por semana para o mesmo conjunto de hostnames.
Porque é que o Traefik v3 não inicia depois da atualização?
Quase sempre porque a configuração estática ainda contém uma opção removida na v3. O Traefik recusa iniciar quando encontra opções que não reconhece. Para as opções antigas mais conhecidas (pilot, providers.docker.swarmMode, experimental.http3), o log apresenta incompatible deprecated static option found e identifica a opção problemática. Para algo que a v3 nunca suportou, como tls.caOptional, apresenta field not found juntamente com o nó correspondente. Elimine ou substitua cada opção e inicie novamente o container.