SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-28

Міграція Traefik v2 на v3: що зламається

Traefik v3 не запускається з swarmMode або pilot у static config. Дізнайтеся, як виправити помилку incompatible deprecated static option found і мігрувати rules.

Що змінюється між Traefik v2 і v3

Перехід із Traefik v2 на v3 здебільшого зводиться до перейменування. Найвідоміша зміна — middleware ipWhiteList перейменовано на ipAllowList. Крім цього, v3 посилює синтаксис правил маршрутизаторів: PathPrefix більше не підтримує можливості regex, а кілька matchers перейменовано або видалено. Деякі providers і параметри також повністю вилучено. Решта продовжує працювати: entrypoints, налаштування сертифікатів ACME, робочий процес із Docker labels і ваш acme.json. У v3 також є режим сумісності, який зберігає підтримку синтаксису правил v2. Тому спочатку можна оновити binary, а правила переписувати для кожного сервісу окремо, а не змінювати все за один ризикований вечір.

Цей посібник передбачає налаштування Docker Compose на основі labels із посібника з reverse proxy Traefik. Та сторінка орієнтована на v3. Ця — для сервера, на якому ще використовується tag traefik:v2.

Перейменування та видалення

  • ipWhiteList тепер має назву ipAllowList для HTTP- і TCP-middleware. Вкладені параметри не змінилися, тому sourcerange зберігає точне значення. Поточні релізи v3, зокрема v3.5, і далі приймають стару назву як deprecated alias і продовжують застосовувати цей список, тому саме це перейменування не спричинить простою під час перемикання. Усе одно перейменуйте її: alias заплановано до видалення, і він зникне зі списку deprecated без окремого повідомлення.
  • providers.docker.swarmMode=true видалено. Swarm отримав власний provider, який налаштовується як providers.swarm.endpoint.
  • Розділ pilot повністю видалено.
  • experimental.http3 видалено. HTTP/3 вмикається безпосередньо на entrypoint.
  • tls.caOptional видалено з providers і middleware forwardAuth. Якщо цей middleware проксуює self-hosted SSO Authentik, видалення рядка caOptional є всією необхідною міграцією, оскільки адреса forwardAuth, довірені заголовки та outpost за ними працюють у v3 так само.
  • Metrics provider для InfluxDB v1, provider Rancher і provider Marathon видалено.
  • Трасування перенесено до OpenTelemetry. Спеціалізовані бекенди трасування, зокрема інтеграції Jaeger і Zipkin, видалено, а v3 натомість експортує OTLP (протокол OpenTelemetry).
  • Застарілі параметри ssl* у headers middleware (sslRedirect, sslHost та решту) видалено. Їх замінили редиректи entrypoint і middleware redirectScheme.

Ці видалення важливіші, ніж може здаватися, оскільки Traefik відмовляється запускатися, якщо його static configuration містить невідомий параметр. Залишений рядок pilot або swarmMode зупиняє контейнер під час запуску з повідомленням incompatible deprecated static option found, у якому вказано залишений параметр; параметр, про який Traefik взагалі не знає (помилка в назві або tls.caOptional), спричиняє повідомлення field not found. Очистьте static configuration до зміни image tag.

Якщо Traefik справді не знає назви middleware (через помилку в назві або тому, що назву видалено, а не замінено alias), помилка має інший вигляд: router, який посилається на цей middleware, завантажується з помилкою замість маршруту, dashboard позначає його, а API повертає middleware "offce@docker" does not exist. Запити до цього hostname отримують 404, оскільки router не запустився. Врахуйте, що ipwhitelist НЕ належить до цієї категорії в поточній v3: він зберігається як deprecated alias, тому label без перейменування продовжує непомітно працювати.

Синтаксис правил змінюється

Саме в правилах виконується основна частина переписування. Зміни у v3:

  • Значення всередині matchers потрібно брати в backticks. v2 також приймала подвійні лапки, а v3 — ні. Тому Host("app.example.com") потрібно замінити на Host(app.example.com).
  • PathPrefix більше не підтримує регулярні вирази або заповнювачі у стилі {id}. Правило v2 на кшталт PathPrefix(/api/{version:v[0-9]+}) потрібно замінити на matcher PathRegexp, записаний у синтаксисі регулярних виразів Go.
  • Тепер matchers приймають одне значення. 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 відповідає тому самому.
  • Додано два matchers: QueryRegexp і ClientIP для зіставлення адреси клієнта всередині правила.

Добра новина: звичайне правило Host(app.example.com), записане з backticks, уже має коректний синтаксис v3. Більшість невеликих Compose-конфігурацій використовує саме такий варіант, тому для більшості labels не потрібно змінювати правила.

Audit your labels before you start

You can measure the size of your migration with one search, because every breaking label change leaves a pattern grep can find:

grep -rnE 'ipwhitelist|HostHeader|Headers\(|PathPrefix\(`[^`]*\{|Host\(`[^`]*`,' docker-compose*.yml

Every hit is one line to edit. ipwhitelist becomes ipallowlist. HostHeader becomes Host. Headers becomes Header. A {...} placeholder inside PathPrefix becomes a PathRegexp matcher. A comma inside Host() becomes two Host() matchers joined by ||. Zero hits means your labels are already valid v3 syntax, and the migration shrinks to the static configuration plus the image tag. A screen full of hits is also a fair moment to ask whether this is still the right proxy for the box, and how Traefik compares with Nginx and Caddy sets that rewriting cost against what the other two ask of you per app.

Що залишається без змін

Точки входу та їхній редирект із HTTP на HTTPS, ACME-resolver із обома типами challenge, exposedByDefault, labels роутера й сервісу, loadbalancer.server.port, а також dashboard у v3 працюють так само, як у v2. Ваші сертифікати також збережуться, оскільки v3 продовжує читати acme.json, створений у v2. Перед початком усе одно зробіть резервну копію цього файла, оскільки відкат із його втратою одразу призведе до досягнення ліміту Let's Encrypt на видачу дублікатів сертифікатів:

cp ./letsencrypt/acme.json ./letsencrypt/acme.json.v2-backup

Шлях міграції

Крок 1: зафіксуйте те, що використовується зараз. Замініть будь-який тег traefik:latest або traefik:v2 на точний реліз, який у вас запущено, наприклад traefik:v2.11, і додайте весь каталог compose до git. Кожен наступний крок можна буде скасувати за допомогою checkout. Якщо відтворення окремого сервісу за допомогою docker compose up -d <service> ще не стало для вас звичною операцією, посібник з основ Docker Compose описує операції, на яких ґрунтується ця міграція.

Крок 2: очистьте статичну конфігурацію та ввімкніть режим сумісності. Видаліть усі параметри, які v3 вилучив (pilot, swarmMode, tls.caOptional, experimental.http3), а потім вкажіть v3 використовувати синтаксис правил v2 за замовчуванням. У traefik.yml:

core:
  defaultRuleSyntax: v2

Або передайте це як прапорець у списку compose command:: --core.defaultRuleSyntax=v2. Режим сумісності охоплює лише синтаксис правил. Він не повертає вилучені параметри й не перейменовує middleware автоматично.

Крок 3: підготуйте перейменування middleware. Знайдіть у файлах compose старі назви: grep -rn ipwhitelist docker-compose*.yml. Змініть кожен label ipwhitelist на ipallowlist, але поки не застосовуйте цю зміну, оскільки нова назва не існує у v2. Ці зміни потрібно застосувати разом із перемиканням у наступному кроці. (Якщо якась назва залишиться, поточний v3 усе ще підтримує стару назву як застарілий псевдонім, тому список і далі застосовуватиметься; виправте це під час наступного проходу, а не о 2-й ночі.)

Крок 4: змініть тег образу. Встановіть для образу Traefik поточний реліз v3, traefik:v3.5 на момент написання цього матеріалу, а потім виконайте:

docker compose up -d
docker compose logs -f traefik

Оскільки режим сумісності ввімкнено, ваші правила v2 і далі працюватимуть. Крім того, up -d повторно створив сервіси, для яких ви перейменували labels middleware, тому ці routers запустяться без помилок. У справному журналі немає рядка field not found і немає рядка does not exist.

Реалістично оцініть вікно простою, яке відкриває цей крок. Router, що посилається на назву middleware, якої v3 справді не знає (через помилку в написанні або вилучений параметр), буде недоступним від моменту запуску нового Traefik до повторного створення його app-контейнера. На одному сервері це триватиме кілька секунд, поки docker compose up -d обробляє список. Якщо певний маршрут справді не може перериватися, перед перемиканням видаліть перейменоване middleware з його label middlewares і додайте його знову після перемикання. Заздалегідь визначте, чи може цей маршрут протягом цієї хвилини працювати без свого списку дозволених IP-адрес.

Крок 5: мігруйте правила для кожного сервісу окремо. Працюйте з одним застосунком за раз: перепишіть його правило на синтаксис v3, повторно створіть лише цей сервіс за допомогою docker compose up -d app і перевірте його перед переходом до наступного. Якщо для певного сервісу ви ще не можете переписати правило, додайте цьому router label для обходу обмеження traefik.http.routers.app.ruleSyntax=v2 і продовжуйте роботу.

Крок 6: вимкніть режим сумісності. Коли всі правила використовуватимуть синтаксис v3, видаліть defaultRuleSyntax та всі labels ruleSyntax, перезапустіть Traefik і переконайтеся, що всі routers і далі позначені зеленим у dashboard. Не залишайте режим сумісності ввімкненим: 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. Точка входу, засіб отримання сертифікатів, зв’язок маршрутизатора з проміжним програмним забезпеченням і порт сервісу не змінилися.

Перевірте кожен сервіс через dashboard

Після кожної зміни відкривайте сторінку HTTP routers у dashboard. Усі routers мають бути зеленими. Router зі значком помилки вказує точну проблему. Зазвичай це middleware, якого немає під новою назвою, або правило, яке v3 не може розібрати. Потім перевірте доступ ззовні, по одному hostname:

curl -sI https://app.example.com/api/v1/status

200 або стандартний redirect вашого застосунку означає, що маршрутизація й TLS працюють. 404 від Traefik означає, що router не запустився. Поверніться до dashboard і прочитайте його помилку. Під час роботи тримайте docker compose logs -f traefik відкритим у другому терміналі, оскільки кожна помилка розбору з’являється там одразу після перезапуску контейнера.

Чесний відкат

Зберігайте compose-файл v2, його статичну конфігурацію та резервну копію acme.json, доки всі сервіси не маршрутизуватимуться через v3 і не будуть перевірені в реальних умовах. Відкат означає переключення на коміт до міграції та запуск docker compose up -d. Потрібно відновити весь файл, а не лише тег образу, оскільки labels, доступні тільки у v3, так само некоректні у v2, як labels v2 були некоректними у v3: ipallowlist не існує у v2, а matcher PathRegexp там також не розбиратиметься. Якщо acme.json було втрачено або пошкоджено під час міграції, відновіть резервну копію перед запуском v2. Так відкат не витратить ліміт Let's Encrypt на повторну видачу п’яти сертифікатів одночасно.

FAQ

Чи потрібно переписувати кожне правило маршрутизатора для Traefik v3?

Ні. Просте правило Host(app.example.com), записане у зворотних апострофах, дійсне в обох версіях і охоплює більшість конфігурацій Compose. Переписування потрібне лише там, де правило використовувало функції, доступні тільки у v2: регулярні вирази або заповнювачі всередині Path і PathPrefix, кілька імен хостів в одному Host(), лапки замість зворотних апострофів або видалені зіставники Headers, HeadersRegexp і HostHeader.

Що сталося з ipWhiteList у Traefik v3?

Його перейменували на ipAllowList, а конфігурація залишилася без змін. Тому мітка v2 на кшталт traefik.http.middlewares.office.ipwhitelist.sourcerange=10.0.0.0/24 перетворюється на той самий рядок із ipallowlist у ньому. Поточні випуски v3, зокрема v3.5, усе ще приймають стару назву як застарілий псевдонім, тому неперейменована мітка продовжує непомітно застосовувати список дозволених адрес. Вважайте це лише тимчасовою можливістю, а не причиною відкладати перейменування: псевдонім планують видалити. Якщо Traefik справді не знає назви middleware, він натомість завершує обробку з помилкою: маршрутизатор повідомляє про помилку, а клієнт отримує 404. Помилку видно на dashboard, а запити до цього імені хоста повертають 404.

Чи може Traefik v3 і далі читати синтаксис правил v2?

Так. У статичній конфігурації задайте core.defaultRuleSyntax: v2, щоб під час міграції синтаксис v2 залишався типовим. Після повернення типового синтаксису до v3 використовуйте мітку ruleSyntax=v2 для окремих маршрутизаторів, які ще не мігрували. Обидва параметри слід вважати тимчасовими: Traefik оголосив їх застарілими у v3.4 і видалить у наступній основній версії.

Чи збережуться мої сертифікати Let's Encrypt після оновлення?

Так. Traefik v3 продовжує читати файл acme.json, створений v2, тому сертифікати не перевидаються лише через зміну бінарного файлу. Проте перед початком роботи скопіюйте цей файл у безпечне місце. Відкат або видалення тому, через яке втрачається acme.json, змушує перевидати всі сертифікати одночасно. Let's Encrypt дозволяє не більше п’яти дублікатів сертифікатів на тиждень для того самого набору імен хостів.

Чому Traefik v3 не запускається після оновлення?

Майже завжди причина в тому, що статична конфігурація все ще містить параметр, видалений у v3. Traefik відмовляється запускатися, якщо конфігурація містить невідомі параметри. Для відомих застарілих параметрів (pilot, providers.docker.swarmMode, experimental.http3) у журналі з’являється incompatible deprecated static option found із назвою проблемного параметра. Для параметра, про який v3 взагалі не знає, наприклад tls.caOptional, з’являється field not found із зазначенням вузла конфігурації. Видаліть або замініть кожен такий параметр, а потім знову запустіть контейнер.