Docker: Правила маршрутів Traefik, що мовчки не працюють — як правильно виправити мітки

Було корисно?

Ви задеплоїли. Контейнери здорові. Порти відкриті. DNS вказує правильно. І все одно Traefik повертає спокійний, байдужий 404 ніби це йому послуга.

Цей режим відмови — причина, через яку люди називають зворотні проксі «простими»: вони спрощують систему, зосереджуючи всі ваші помилки в одному місці. Traefik + Docker-мітки потужні, але це також річ, яка може вистрілити в ногу. Вони не завжди кричать, коли ваші правила маршрутизації не збігаються. Вони просто… не маршрутизують нічого.

Що насправді означає «мовчазна відмова» в Traefik

«Мовчазна відмова» не означає, що Traefik зламався. Це означає, що Traefik робить саме те, що ви йому наказали — на основі міток, які ви випадково вказали.

Типові симптоми:

  • Traefik повертає 404 page not found для хоста, у якому ви впевнені.
  • Ви звертаєтесь на entrypoint Traefik, але роутер ніколи не матчує, тому спрацьовує обробник за замовчуванням (404).
  • Контейнер запущений і слухає, але Traefik маршрутизує на неправильний внутрішній порт (або взагалі нікуди).
  • Middlewares не застосовуються, TLS не піднімається, редіректи не відбуваються — і ви відчуваєте привид.

Traefik не «мовчить», якщо ви знаєте, куди дивитись: дашборд, конфіг провайдера, перегляд динамічної конфігурації та логи. Мовчання на вашому терміналі викликане тим, що Docker-мітки легко помилитись і складно візуально перевірити.

Цікаві факти та трохи контексту

  1. Traefik популяризував «відкриття конфігурації» в епоху контейнерів: слідкування за Docker-подіями, динамічне побудування маршрутів, уникнення ручних проксі-конфігів.
  2. Docker-мітки передували домінуванню Traefik; це була загальна метадані-фіча, яку зворотні проксі перетворили на повноцінну контрольну площину.
  3. Traefik v2 змінив модель мислення: роутери, сервіси, middlewares замінили простішу v1 модель frontend/backend. Багато конфігів «що працювали торік» перестали працювати.
  4. Парсинг правил став суворішим з часом: дрібні синтаксичні помилки в Host(), лапках або backtick-ах часто призводять до того, що роутер взагалі не створюється.
  5. EntryPoints — це не порти; це іменовані слухачі. Роутер, прив’язаний до websecure, не матчитиме трафік, що приходить на web, навіть якщо обидва налаштовані на тому ж контейнері.
  6. Типи YAML у Docker Compose куса́ють: мітка, що виглядає як рядок, може парситись дивно, якщо ви її не взяли в лапки.
  7. За замовчуванням Traefik може приховувати ваші наміри: якщо exposedByDefault увімкнено, ви можете випадково маршрутизувати контейнери, які не марковані — поки не вимкнете цю опцію, і тоді все зникне.
  8. Експерименти з HTTP/3 змінили очікування: нові стекові рішення підштовхують до QUIC; невідповідні entrypoints і TLS-настройки тепер помітніші через іншу поведінку клієнтів.

Швидкий план діагностики (робіть у цьому порядку)

Якщо ви на виклику і секунди дорогоцінні, припиніть гадати. Перевірте систему так, як її бачить Traefik.

1) Traefik отримує запит на той entrypoint, який ви вважаєте?

  • Підтвердіть, що клієнт б’є по правильній IP/домену.
  • Підтвердіть, що запит доходить до Traefik (а не до сторінки здоров’я хмарного LB або старого IP).
  • Підтвердіть HTTP vs HTTPS та SNI-хост.

2) Чи має Traefik роутер, який може співпасти?

  • Перевірте дашборд або API на наявність роутерів.
  • Знайдіть ім’я вашого роутера; перевірте правило, entrypoints, TLS і прив’язку до сервісу.

3) Якщо роутер існує — чи він матчитиме?

  • Порівняйте хост/шлях запиту з правилом точно.
  • Шукайте конфлікти пріоритетів і «catch-all» роутери.

4) Якщо він матчить — чи може Traefik дістатися до сервісу?

  • Перевірте мережеву доступність Docker: Traefik має бути в тій же мережі, що й цільовий контейнер.
  • Перевірте порт, який використовує Traefik: явний порт в load balancer краще за авто-виявлення.

5) Якщо він дістатися до сервісу — чи роблять middleware і TLS те, що ви очікуєте?

  • Підтвердіть імена ланцюжка middleware та область провайдера (@docker vs @file).
  • Перевірте TLS-настройки: tls=true, certresolver, домени та entrypoint.

Ось цей порядок. Не міняйте його. Більшість часу витрачають на налагодження «сертифікатів», коли роутер взагалі не матчився.

Як Traefik вирішує, куди йде трафік (і чому мітки важливі)

У Traefik v2 потік запиту виглядає так:

  1. EntryPoint приймає з’єднання (приклад: web на :80, websecure на :443).
  2. Router матчит запит (правило: host/path/headers, плюс entrypoints, плюс вимога TLS).
  3. Middlewares змінюють запит/відповідь (редірект, автентифікація, заголовки, rate-limit тощо).
  4. Service визначає апстрім (IP:порт контейнера, опції балансування).

Docker-мітки — це джерело динамічної конфігурації. Провайдер Docker слідкує за контейнерами та транслює мітки у роутери/сервіси/middlewares.

Ось ключове: Traefik охоче працюватиме з частковою конфігурацією. Якщо мітка роутера має синтаксичну помилку, Traefik може зовсім не створити цей роутер. Якщо роутер існує, але посилається на неіснуючий middleware, він може не під’єднати його. Якщо відсутня мітка з портом сервісу й Docker експонує кілька портів, Traefik може вибрати невірний.

І якщо жоден роутер не матчитиме, Traefik поверне 404, який виглядає саме як «Traefik працює». Ось чому люди втрачають години.

Є одна цитата, яку варто запам’ятати, бо це суть:

«Надія — не стратегія.» — Gene Kranz

Налагодження міток Traefik — це місце, куди йде помирати надія. Добре. Замініть її на спостережність і конвенції.

Виправляємо мітки правильно: шаблони, що не гниють

Принцип 1: Завжди явно іменуйте роутери, сервіси й middlewares

Покладання на неявні імена — це шлях до «чому Traefik приєднує невірний сервіс?» о 2 ночі. Використовуйте стабільні імена. Використовуйте їх скрізь.

Принцип 2: Завжди вказуйте порт сервісу

Так, Traefik може авто-виявляти порти. Ні, не дозволяйте йому цього робити, якщо не любите ймовірнісну маршрутизацію.

Правило пальця: якщо контейнер експонує кілька портів або ви використовуєте health/admin порти, завжди встановлюйте:

  • traefik.http.services.<service>.loadbalancer.server.port

Принцип 3: Використовуйте один роутер на hostname + entrypoint, а поведінку складайте через middlewares

Не напихайте занадто багато в одне правило роутера. Тримайте матчинг простим; тримайте поведінку модульною.

Принцип 4: Кавички для значень міток у Compose (і консистентність з backtick)

Compose — це YAML. YAML має свої правила. Синтаксис правил Traefik теж має свої правила. Ви застрягли між двома парсерами з різними визначеннями «рядок». Бережіть значення в лапках. Використовуйте backtick всередині правил послідовно.

Добре (в лапках): "Host(`app.example.com`) && PathPrefix(`/api`)"
Погано (без лапок): Host(`app.example.com`) (іноді працює, іноді ні)

Принцип 5: Визначте, чи хочете ви експонувати контейнери за замовчуванням. І дотримуйтеся цього.

В продакшені встановіть провайдер Docker exposedByDefault=false і явно вмикайте для сервісу через traefik.enable=true. Це зменшує випадкове відкриття й робить відмови явнішими: якщо не включено, воно не з’явиться.

Жарт #1: Якщо ви тримаєте exposedByDefault=true, ви не керуєте зворотним проксі — ви управляєте генератором сюрпризів.

Канонічний приклад Compose, що уникає мовчазних відмов

Цей шаблон має менше рухомих частин і помилки тут голосніші:

cr0x@server:~$ cat docker-compose.yml
version: "3.9"

networks:
  edge:
    external: true

services:
  traefik:
    image: traefik:v2.11
    command:
      - --api.dashboard=true
      - --api.insecure=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=edge
      - --log.level=INFO
      - --accesslog=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - edge
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.tls=true"
      - "traefik.http.routers.traefik.service=api@internal"

  app:
    image: ghcr.io/example/app:latest
    environment:
      - PORT=8080
    networks:
      - edge
    labels:
      - "traefik.enable=true"

      - "traefik.http.routers.app.rule=Host(`app.example.com`)"
      - "traefik.http.routers.app.entrypoints=websecure"
      - "traefik.http.routers.app.tls=true"
      - "traefik.http.routers.app.service=app-svc"

      - "traefik.http.services.app-svc.loadbalancer.server.port=8080"

      - "traefik.http.middlewares.app-headers.headers.framedeny=true"
      - "traefik.http.routers.app.middlewares=app-headers"

Зверніть увагу на те, що явно вказано:

  • Traefik використовує певну Docker-мережу (--providers.docker.network=edge).
  • Порт сервісу додатку прив’язано до 8080.
  • Імена роутера/сервісу/middleware стабільні та явно посилаються одне на одне.
  • Traefik сам маршрутизований через api@internal, що зменшує плутанину «чому дашборд не працює?».

Практичні завдання: команди, виводи та рішення (12+)

Ось перевірки, які я реально виконую. Кожне завдання включає: команду, типовий вивід, що це означає та рішення, яке потрібно прийняти.

Завдання 1: Підтвердити, що контейнер Traefik запущений і яка версія образу

cr0x@server:~$ docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
NAMES      IMAGE          STATUS          PORTS
traefik    traefik:v2.11  Up 2 hours      0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
app        ghcr.io/example/app:latest  Up 2 hours

Значення: Traefik запущений і прив’язаний до :80/:443 на хості.

Рішення: Якщо Traefik не запущений або порти не проброшені, зупиніться. Виправте життєвий цикл контейнера або фаєрвол хоста перед тим, як торкатись міток.

Завдання 2: Перевірити startup-флаги Traefik (провайдери, exposedByDefault, network)

cr0x@server:~$ docker inspect traefik --format '{{json .Config.Cmd}}'
["--api.dashboard=true","--entrypoints.web.address=:80","--entrypoints.websecure.address=:443","--providers.docker=true","--providers.docker.exposedbydefault=false","--providers.docker.network=edge","--log.level=INFO","--accesslog=true"]

Значення: Docker-провайдер увімкнений, експозиція за замовчуванням вимкнена, і Traefik шукатиме бекенди в мережі edge.

Рішення: Якщо встановлено --providers.docker.network, ваш застосунок повинен бути приєднаний до цієї мережі або маршрутизація не спрацює.

Завдання 3: Перевірити, чи додаток у тій же Docker-мережі, яку очікує Traefik

cr0x@server:~$ docker inspect app --format '{{json .NetworkSettings.Networks}}'
{"edge":{"IPAMConfig":null,"Links":null,"Aliases":["app","3e9c1b7b4a2d"],"MacAddress":"02:42:ac:18:00:05","DriverOpts":null,"NetworkID":"b7b9d6c3b34a","EndpointID":"f2b59b5f8e67","Gateway":"172.24.0.1","IPAddress":"172.24.0.5","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"DNSNames":["app","3e9c1b7b4a2d"]}}

Значення: Додаток у мережі edge з IP, до якого Traefik може маршрутувати.

Рішення: Якщо додаток не в цій мережі, приєднайте його. Не «просто відкривайте порт», якщо не хочете обходити проксі повністю.

Завдання 4: Підтвердити мітки, які Traefik прочитає (та швидко помітити опечатки)

cr0x@server:~$ docker inspect app --format '{{json .Config.Labels}}' | jq -r 'to_entries[] | "\(.key)=\(.value)"' | sort
traefik.enable=true
traefik.http.routers.app.entrypoints=websecure
traefik.http.routers.app.rule=Host(`app.example.com`)
traefik.http.routers.app.service=app-svc
traefik.http.routers.app.tls=true
traefik.http.routers.app.middlewares=app-headers
traefik.http.middlewares.app-headers.headers.framedeny=true
traefik.http.services.app-svc.loadbalancer.server.port=8080

Значення: Мітки присутні і правильно написані. Тепер можна детерміністично мислити про конфіг Traefik.

Рішення: Якщо бачите traefik.http.router (без «s»), або невідповідні імена — виправте мітки перед тим, як чіпати щось інше.

Завдання 5: Подивитись логи Traefik на помилки провайдера (парсинг, відсутні middleware)

cr0x@server:~$ docker logs traefik --since 15m | tail -n 20
time="2026-01-03T09:18:41Z" level=info msg="Configuration loaded from flags."
time="2026-01-03T09:21:10Z" level=info msg="Skipping same configuration for provider docker"
time="2026-01-03T09:22:07Z" level=error msg="middleware \"app-auth@docker\" does not exist" routerName=app@docker entryPointName=websecure
time="2026-01-03T09:22:07Z" level=error msg="error while adding middleware: middleware \"app-auth@docker\" does not exist" entryPointName=websecure routerName=app@docker

Значення: Роутер існує, але посилається на middleware, якого немає. Це часто все ще маршрутизує, просто без middleware — це теж «мовчазна відмова» іншого типу.

Рішення: Або визначте middleware через мітку, або приберіть його з роутера. Не лишайте зламаних посилань; вони перетворюються на дірки в безпеці.

Завдання 6: Підтвердити, що роутери існують через API Traefik (всередині контейнера)

cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/routers | head -n 20'
[{"entryPoints":["websecure"],"service":"app-svc@docker","rule":"Host(`app.example.com`)","status":"enabled","using":["websecure"],"name":"app@docker"},{"entryPoints":["websecure"],"service":"api@internal","rule":"Host(`traefik.example.com`)","status":"enabled","using":["websecure"],"name":"traefik@docker"}]

Значення: Ваш роутер реальний у динамічній конфігурації Traefik, а не тільки в уяві.

Рішення: Якщо роутер відсутній тут, Traefik його не завантажив. Це проблема міток, обмежень провайдера або налаштування exposedByDefault.

Завдання 7: Підтвердити порт сервісу, який Traefik використовуватиме

cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/services | jq -r ".[] | select(.name==\"app-svc@docker\") | .loadBalancer.servers"'
[
  {
    "url": "http://172.24.0.5:8080"
  }
]

Значення: Traefik вказує на правильний IP і порт.

Рішення: Якщо бачите неправильний порт (часто 80), явно вкажіть loadbalancer.server.port і перевдеплойте.

Завдання 8: Протестувати бекенд безпосередньо з контейнера Traefik (перевірка мережевого шляху)

cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qSO- http://172.24.0.5:8080/health -O /dev/null'
  HTTP/1.1 200 OK
  Content-Type: application/json
  Date: Sat, 03 Jan 2026 09:25:01 GMT
  Content-Length: 17

Значення: Зв’язність у порядку; відмови в маршрутизації/матчингу/TLS/middleware, а не в мережевій доступності.

Рішення: Якщо це не проходить, виправте Docker-мережі, порт прослуховування контейнера або прив’язку застосунку (0.0.0.0 vs 127.0.0.1).

Завдання 9: Перевірити, що Host-заголовок запиту відповідає правилу роутера

cr0x@server:~$ curl -sS -D- -o /dev/null -H 'Host: app.example.com' http://127.0.0.1/
HTTP/1.1 301 Moved Permanently
Location: https://app.example.com/
Date: Sat, 03 Jan 2026 09:25:28 GMT
Content-Length: 17
Content-Type: text/plain; charset=utf-8

Значення: Щось матчилось на HTTP і, ймовірно, було перенаправлено на HTTPS (через middleware або редірект entrypoint).

Рішення: Якщо ви отримуєте 404 тут, правило роутера не матчит. Перевірте лапки у правилі Host, домен і entrypoints.

Завдання 10: Підтвердити маршрутизацію HTTPS і поведінку сертифікатів (SNI важливе)

cr0x@server:~$ curl -sS -D- -o /dev/null https://app.example.com/
HTTP/2 200
content-type: text/html; charset=utf-8
date: Sat, 03 Jan 2026 09:26:02 GMT
server: traefik

Значення: TLS працює і роутер матчит на websecure.

Рішення: Якщо TLS-хендшейк падає або ви бачите неправильний сертифікат, перевірте TLS-флаги роутера, certresolver і чи ви звертаєтесь до правильної інстанції Traefik.

Завдання 11: Виявити конфлікти правил і проблеми з пріорітетами

cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/routers | jq -r ".[] | [.name,.rule,(.priority|tostring)] | @tsv" | sort -k2'
app@docker	Host(`app.example.com`)	
catchall@docker	HostRegexp(`{any:.+}`)	1

Значення: У вас є catch-all роутер, який може вкрасти трафік, якщо його пріоритет вищий або якщо ваш роутер не матчит точно.

Рішення: Встановіть явні пріоритети. Не покладайтеся на «воно й так само розставиться». Не розставиться.

Завдання 12: Подивитись Docker-події, щоб побачити, чи Traefik помічає зміни контейнера

cr0x@server:~$ docker events --since 5m --filter type=container --filter event=start
2026-01-03T09:24:10.128722391Z container start 3e9c1b7b4a2d (image=ghcr.io/example/app:latest, name=app)

Значення: Docker випромінює lifecycle-події; Traefik повинен їх підхоплювати, якщо має доступ до сокета.

Рішення: Якщо Traefik не оновлюється, підтвердіть, що Docker-сокет змонтовано і дозволи читання вистачають.

Завдання 13: Підтвердити, що Traefik може читати Docker-сокет (поширено в жорсткій безпеці)

cr0x@server:~$ docker exec -it traefik sh -lc 'ls -l /var/run/docker.sock'
srw-rw----    1 root     docker           0 Jan  3 08:01 /var/run/docker.sock

Значення: Сокет існує. Дозволи можуть ще бути проблемою в залежності від користувача Traefik.

Рішення: Якщо Traefik працює не від root і не може читати сокет, ви побачите помилки провайдера і відсутні роутери. Виправте user/group або запустіть з відповідними правами.

Завдання 14: Перевірити Compose-файл, який ви фактично задеплоїли (не той, який редагували)

cr0x@server:~$ docker compose config | sed -n '1,120p'
services:
  app:
    image: ghcr.io/example/app:latest
    labels:
      traefik.enable: "true"
      traefik.http.routers.app.entrypoints: websecure
      traefik.http.routers.app.rule: Host(`app.example.com`)
      traefik.http.routers.app.service: app-svc
      traefik.http.routers.app.tls: "true"
      traefik.http.services.app-svc.loadbalancer.server.port: "8080"
networks:
  edge:
    external: true

Значення: Це відрендерена конфігурація після того, як Compose об’єднав файли, підставив змінні середовища і розпарсив YAML. Це — істина.

Рішення: Якщо відрендерені мітки відрізняються (відсутні лапки, усічені рядки), виправте початковий Compose-файл. Налагоджувати не той файл — класична самоспростування.

Три міні-історії з корпоративного світу

Міні-історія 1: Інцидент через хибне припущення

Вони мігрували клієнтський додаток з ручної конфігурації Nginx на Traefik з Docker-мітками. План виглядав добре: у кожного сервісу були мітки, і була акуратна мережа «edge». Хтось навіть написав README — зазвичай це поганий знак.

Хибне припущення: «Якщо контейнер доступний з хоста, Traefik теж може до нього дістатися.» Вони експонували додаток на 0.0.0.0:8080 для тесту і підтвердили роботу через curl http://host:8080. Потім прибрали проброс порту, бо «Traefik тепер керує входом».

Деплой в продакшн: Traefik повернув 404 для хосту. Люди шукали причину в DNS, потім у сертифікатах, потім «можливо балансувальник». Тим часом сервіс був здоровий і логи спокійні. Команда додатку пропонувала rollback. Платформна команда пропонувала молитви.

Проблема була прозаїчна: Traefik був налаштований з --providers.docker.network=edge, але контейнер додатка був лише в дефолтній мережі Compose. Traefik ніколи не побачив endpoint, який міг би використати. Ні мережі — немає сервісу — немає маршруту.

Виправлення зайняло п’ять хвилин: приєднати додаток до edge і перевдеплойнути. Постмортем зайняв довше, бо найскладніше було визнати, що вони «тестували» інший мережевий шлях, ніж у продакшн.

Міні-історія 2: Оптимізація, що відбилася бумерангом

Інша компанія мала ініціативу «мінімізувати мітки». Ідея була не дурна: забагато міток важко читати, і помилки копіювання-вставки реальні. Вони прибрали явні мітки порту сервісу й поклалися на авто-виявлення Traefik. Це працювало для більшості сервісів. Ось у чому пастка: частковий успіх — найдорожча форма відмови.

Пізніше один сервіс додав другий експонований порт для метрик. Тепер Docker показував два кандидати. Traefik вибрав один. Це був неправильний. Запити потрапляли на метрики, які швидко відповідали, але не корисно. Клієнти бачили 404 і «not found». Технічно нічого не впало; практично все було зламано.

На черговому виклику звинувачували неправильний деплой. Rollback не допомагав, бо експозиція порту метрик залишалася. Звинувачували Traefik. Підвищували ресурси. Змінювали таймаути. Додавали ретраї (що робило шум гіршим).

Справжнє виправлення — скасувати «оптимізацію» і зафіксувати порт через мітку. Урок не в тому, що авто-виявлення погане. Урок у тому, що в продакшені невизначеність — це баг, який ще не проявився.

Міні-історія 3: Нудна, але правильна практика, що врятувала день

Фінтех-команда мала звичку, що виглядала нудно церемоніальною: кожна зміна зворотного проксі вимагала «репетиції маршруту» на staging, включно зі скриптом, що опитує API роутерів і сервісів Traefik. Вони не покладалися на дашборд. Вони не дивились на мітки в очі. Вони запускали скрипт і архівували вивід у тикеті змін.

Під час рутинного деплою розробник перейменував роутер з billing на billing-app, але забув оновити посилання на middleware. Traefik записав помилку про відсутній middleware, але маршрут все ще обслуговував трафік — просто без автентифікації, що обмежувала доступ внутрішнім користувачам.

У багатьох організаціях це саме так починається інцидент з безпеки: «ми не думали, що це буде доступно». Тут staging-репетиція зловила помилку, бо скрипт перевіряв, що роутер має очікуваний ланцюжок middleware.

Вони виправили мітку до потрапляння в продакшн. Нудний ритуал виглядав як бюрократія до того моменту, поки не запобіг інциденту, що міг би стати дорогим і принизливим. Ось як виглядає культура надійності, коли вона працює.

Поширені помилки: симптом → корінь → виправлення

Ось повторювані злочинці. Якщо Traefik «мовчки відмовляє», зазвичай це один з них у маскараді.

1) Симптом: 404 від Traefik для правильного хосту

Корінь: Правило роутера не матчит (неправильний домен, неправильні лапки, клієнт відправляє інший Host), або роутер прив’язаний до неправильного entrypoint.

Виправлення: Перевірте, що роутер існує в API, потім порівняйте правило з фактичним запитом. Переконайтеся, що traefik.http.routers.<name>.entrypoints включає entrypoint, на який ви б’єте.

2) Симптом: Роутер зовсім відсутній у дашборді/API

Корінь: traefik.enable відсутній при exposedByDefault=false; або обмеження провайдера його виключають; або ключі міток пошкоджені.

Виправлення: Додайте traefik.enable=true; перевірте флаги провайдера; валідируйте мітки через docker inspect і docker compose config.

3) Симптом: Роутер існує, але запити йдуть до неправильного сервісу

Корінь: Колізія імен сервісів, неявний вибір сервісу або кілька роутерів випадково вказують на спільний дефолтний сервіс.

Виправлення: Встановіть traefik.http.routers.<router>.service=<service> явно і використовуйте унікальні імена сервісів для кожного додатку.

4) Симптом: TLS працює іноді; іноді ви бачите сертифікат за замовчуванням

Корінь: Роутер не прив’язаний до websecure або відсутній tls=true; або невідповідність SNI; або кілька інстанцій Traefik за LB.

Виправлення: Переконайтесь, що роутер має entrypoints=websecure і tls=true. Перевірте, що клієнт використовує правильний хост і потрапляє на потрібну інстанцію.

5) Симптом: Middleware «не застосовано», але маршрутизація працює

Корінь: Несумісність імен middleware, область провайдера (@docker vs @file), або middleware визначено на іншому контейнері та неправильно посилається.

Виправлення: Перевірте логи Traefik на повідомлення «middleware does not exist». Використовуйте одне джерело правди: визначайте middlewares поруч з роутерами або у file provider і посилайтесь з суфіксом.

6) Симптом: 502 Bad Gateway від Traefik

Корінь: Traefik матчит роутер, але не може дістатися апстріму (не та мережа, неправильний порт, аплікація слухає лише localhost, контейнер перезапускається).

Виправлення: Тестуйте з контейнера Traefik до апстріму IP:порт. Зафіксуйте порт сервісу. Переконайтесь, що додаток біндиться на 0.0.0.0.

7) Симптом: Все працює на HTTP, але падає на HTTPS

Корінь: Роутер визначено лише для web, або HTTPS-роутер немає TLS-конфіг/сертифікатор.

Виправлення: Створіть окремий роутер websecure, встановіть tls=true і переконайтесь, що certresolver налаштований, якщо потрібно.

8) Симптом: Ви змінили мітки, але поведінка Traefik не змінилася

Корінь: Ви відредагували Compose-файл, але не перевдеплойнули; або Traefik не підхопив події через права на сокет; або ви дивитесь на неправильну інстанцію Traefik.

Виправлення: Перезадеплойте сервіс; перевірте Docker-події; перегляньте логи Traefik на оновлення провайдера; підтвердіть, що дивитесь на потрібну інстанцію через access-логи.

Жарт #2: Traefik не «ігнорує» ваші мітки. Він просто інтерпретує їх так, щоб ваш майбутній я подав скаргу.

Контрольні списки / покроковий план

Покроково: Зробити маршрут на мітках, що не мовчатиме при відмові

  1. Виберіть одну Docker-мережу для edge-трафіку (наприклад, edge). Помістіть Traefik і кожен сервіс, що маршрутизують, в неї.
  2. Явно встановіть поведінку провайдера Traefik:
    • --providers.docker=true
    • --providers.docker.exposedbydefault=false
    • --providers.docker.network=edge
  3. Для кожного сервісу:
    • Додайте traefik.enable=true.
    • Створіть роутер зі стабільним ім’ям: traefik.http.routers.<router>.*.
    • Прив’яжіть його до правильних entrypoint(ів).
    • Встановіть tls=true для HTTPS-роутерів.
    • Явно вкажіть service=<service-name>.
    • Явно встановіть loadbalancer.server.port.
  4. Запустіть docker compose config і перевірте, що відрендерені мітки правильні.
  5. Після деплою перевірте роутери та сервіси через API Traefik.
  6. Протестуйте зсередини контейнера Traefik до апстріму IP:порт.
  7. Лише потім налагоджуйте TLS/серти/мажорні middleware.

Чекліст: Перед тим, як звинувачувати Traefik

  • Контейнер і Traefik ділять мережу, яку Traefik налаштовано використовувати.
  • Роутер існує в API Traefik.
  • Правило роутера відповідає Host і Path запиту.
  • Роутер прив’язаний до entrypoint, який приймає запит.
  • Порт сервісу зафіксовано і правильний.
  • Апстрім доступний з контейнера Traefik.
  • Немає catch-all роутера, що краде трафік через пріоритети.
  • Посилання на middleware існують і правильно областьовані.

FAQ

1) Чому я отримую Traefik 404 замість помилки, коли мітки неправильні?

Тому що 404 — це коректна відповідь, коли жоден роутер не матчит запит. Відсутній роутер — це не runtime-виключення; це відсутня конфігурація.

2) Роутер існує, але все одно не матчит. Який найшвидший спосіб це довести?

Відправте запит з явним Host-заголовком на той же entrypoint, який тестуєте, потім порівняйте з правилом роутера з API Traefik.

3) Чи справді треба брати значення міток у лапки в Docker Compose?

Так. Парсинг YAML і спеціальні символи (backtick, коми, двокрапки) — саме там народжується «вона працювала на моєму ноуті». Зачіпайте в лапки і живіть далі.

4) Коли використовувати PathPrefix проти Path?

Path збігається точно. PathPrefix матчит піддерево. Для API зазвичай використовують PathPrefix(`/api`). Будьте явними і уникайте випадкових перекриттів з іншими роутерами.

5) Чому Traefik маршрутизує на неправильний порт?

Через авто-виявлення. Якщо Docker експонує кілька портів (або образ декларує кілька), Traefik обирає один. Зафіксуйте порт через loadbalancer.server.port.

6) У чому різниця між web/websecure та портами 80/443?

web і websecure — це імена entrypoint-ів. Вони зазвичай корелюють з портами, але роутери прив’язуються до імен. Ви можете зв’язати entrypoints з будь-якими портами.

7) Чому middleware іноді «пів-падає», не зламавши маршрутизацію?

Traefik може приєднати те, що існує, і логувати помилки для того, чого немає. Це добре для доступності, але небезпечно для контролю безпеки. Розглядайте помилки middleware як помилку деплою.

8) Чи ставити всі middlewares в контейнер Traefik, щоб централізувати конфіг?

Тільки якщо ви дисципліновані. Централізація може зменшити дублювання, але також збільшує радіус ураження і заохочує заплутані залежності. Для невеликих стеків тримайте middlewares поруч із сервісами, які вони впливають.

9) Чи безпечно відкривати дашборд Traefik?

Не за замовчуванням. Маршрутизуйте його через websecure, додайте auth-middleware і уникайте api.insecure=true в продакшні. Трактуйте його як адмінський інтерфейс — бо він ним і є.

10) Як зупинити випадкове відкриття незв’язаних контейнерів?

Встановіть exposedByDefault=false і вимагайте traefik.enable=true. Додайте CI-прохідку, що падає, якщо сервіс позбавлений явних router/service/port міток.

Наступні кроки, які ви можете зробити сьогодні

Якщо правила маршрутів Traefik «мовчки відмовляють», виправлення рідко магічне. Це гігієна:

  1. Зробіть маршрутизацію явною: імена роутерів, імена сервісів, entrypoints, TLS-флагі та порт апстріму.
  2. Уніфікуйте шаблон міток, щоб кожен сервіс виглядав однаково. Послідовність — це інструмент налагодження.
  3. Прийміть швидкий порядок діагностики: entrypoint → існування роутера → співпадіння → доступність апстріму → middleware/TLS.
  4. Додайте один нудний запобіжник: скрипт, що опитує роутери/сервіси Traefik після деплою і стверджує очікувані правила та порти.

Коли Traefik налаштований чисто, він перестає бути таємницею. Це маршрутизатор запитів з сильними уподобаннями й обмеженим терпінням. Зустріньте його посередині: будьте явними, перевіряйте через API і припиніть довіряти тому, що «має працювати».

← Попередня
Резервні копії Docker-томів, які справді відновлюються
Наступна →
Безпека сокета Docker: один маунт, що рівноцінний root (і безпечніші альтернативи)

Залишити коментар