CodeWorlds
Powrót do kolekcji
Przewodnik14 min czytaniaZespół CodeWorlds

Traefik, reverse proxy wykrywający usługi sam

Traefik czyta konfigurację tras z Dockera i Kubernetesa bez przeładowania. Wersja 3.7.11, licencja MIT, pułapka pakietu npm i granica między Proxy a Hub.

Traefik, reverse proxy, który sam znajduje usługi

Traefik to napisany w Go reverse proxy i load balancer, który konfigurację tras czyta wprost z Dockera, Kubernetesa, Consula czy Nomada, zamiast z pliku pisanego ręcznie. Bieżące wydanie to 3.7.11, licencja MIT, a certyfikaty od Let's Encrypt zamawia i odnawia sam proces serwera.

Skąd Traefik bierze konfigurację

Różnica między Traefikiem a klasycznym proxy sprowadza się do jednego pojęcia: provider. W nginxie albo w HAProxy plik konfiguracyjny jest jedynym źródłem prawdy o trasach, a każda zmiana wymaga edycji tego pliku i przeładowania procesu. Traefik dzieli konfigurację na dwie warstwy o zupełnie innym cyklu życia.

Warstwa statyczna to rzeczy, które ustala się przy starcie procesu i których nie da się zmienić bez restartu: jakie porty nasłuchują, jakie źródła konfiguracji są włączone, jak wygląda dostęp do urzędu certyfikacji. Warstwa dynamiczna to trasy, usługi i middleware, czyli wszystko, co zmienia się przy każdym wdrożeniu. Ta druga warstwa nie pochodzi z pliku, tylko z providera.

Provider to adapter do konkretnego systemu. Provider Docker podpina się do gniazda demona i obserwuje zdarzenia o startach i zatrzymaniach kontenerów, czytając z nich etykiety zaczynające się od traefik.. Provider Kubernetes CRD czyta zasoby IngressRoute z grupy traefik.io/v1alpha1. Są też providery dla Consula, Nomada, ECS, Redisa oraz zwykły provider plikowy, gdy trasy chce się jednak wpisać ręcznie. Kilka providerów może działać naraz i ich wyniki się sumują.

Skutek praktyczny jest taki, że nowy kontener z odpowiednim zestawem etykiet zaczyna odbierać ruch bez dotykania proxy. Nie ma polecenia reload, nie ma szablonu generującego plik, nie ma kroku w potoku wdrożeniowym, który mógłby ten plik zepsuć. Za wygładzenie serii zdarzeń odpowiada providers.providersThrottleDuration z domyślną wartością 2 sekund, więc dziesięć kontenerów wstających jednocześnie daje jedną przebudowę tablicy tras, a nie dziesięć.

Cena tego wygodnego mechanizmu też jest realna. Konfiguracja przestaje mieszkać w jednym miejscu. Rozjeżdża się po plikach docker-compose.yml, manifestach Kubernetesa i adnotacjach, a odpowiedź na pytanie „dlaczego ten host trafia tam, gdzie trafia" wymaga zajrzenia do panelu Traefika albo do API, a nie do jednego pliku tekstowego.

Wersja, licencja i trzeci dowód

Bieżące wydanie z gałęzi trzeciej to 3.7.11 z 21 sierpnia 2026 roku. Że utrzymywane są równolegle trzy linie, widać po 3 sierpnia, kiedy jednego dnia ukazały się 3.7.10, 3.6.25 oraz 2.11.55, czyli po jednym wydaniu z każdej z nich. Kod buduje się z go 1.26.0 zadeklarowanym w go.mod.

Licencję sprawdziłem w trzech miejscach, bo to najczęstsze źródło pomyłek w audytach zależności.

Pierwsze źródło to plik w repozytorium. github.com/traefik/traefik trzyma go pod nazwą LICENSE.md, nie LICENSE, i zawiera pełny tekst MIT z notą „Copyright (c) 2016-2020 Containous SAS; 2020-2025 Traefik Labs". Containous to dawna nazwa firmy, która przemianowała się na Traefik Labs w 2020 roku, i ten ślad widać wprost w nagłówku.

Drugie źródło to rejestr pakietów. Tu robi się nieprzyjemnie i temu poświęcam osobną sekcję poniżej, bo pakiet npm o nazwie traefik nie pochodzi od Traefik Labs.

Trzecie źródło to zawartość faktycznie dystrybuowanego artefaktu i tutaj wynik jest podzielony. Archiwum traefik_v3.7.11_linux_amd64.tar.gz z sekcji wydań waży około 48 MB i zawiera dokładnie trzy wpisy: CHANGELOG.md, LICENSE.md oraz binarium traefik o rozmiarze około 176 MB po rozpakowaniu. Tekst licencji jest więc na miejscu, w przeciwieństwie do wielu projektów dystrybuujących same binaria. Natomiast oficjalny obraz kontenera go nie zawiera. Dockerfile z repozytorium traefik/traefik-library-image dla wariantu alpine rozpakowuje archiwum poleceniem, które wyciąga z niego wyłącznie jeden wpis: tar xzvf /tmp/traefik.tar.gz -C /usr/local/bin traefik. LICENSE.md i CHANGELOG.md zostają w odrzuconym archiwum. Jeśli Twój skaner obrazów szuka pliku licencyjnego wewnątrz warstw, dla traefik:v3.7.11 go nie znajdzie, mimo że projekt jest czysto MIT. Trzeba wtedy wpisać licencję ręcznie albo wziąć ją z etykiet OCI, które obraz ustawia, w tym org.opencontainers.image.source wskazującej na repozytorium.

Pułapka nazwy: pakiet npm traefik

Pakiet traefik w rejestrze npm nie jest wydawany przez Traefik Labs. Najnowsza wersja to 1.0.0 opublikowana 2 sierpnia 2021 roku, całe repozytorium wpisu w rejestrze nie zmieniło się od maja 2022, a pole repository.url wskazuje na github.com/hello-seam/node-traefik. To nieoficjalna nakładka jednej osoby.

W odróżnieniu od kilku innych podszywek, ta ma kod: czternaście plików i około 14,8 kB po rozpakowaniu. index.js eksportuje funkcję start, która zamienia obiekt konfiguracji na TOML przez json2toml i uruchamia binarium jako proces potomny. Problem leży gdzie indziej. Plik download-traefik.js ma zaszytą na sztywno wersję do pobrania i pyta o nią interfejs programistyczny GitHuba bez uwierzytelnienia.

JSnode_modules/traefik/download-traefik.js
JavaScript
// node_modules/traefik/download-traefik.js, wersja 1.0.0 z 2021 roku
const releaseVersionToUse = "2.4.9"

const releaseAPIUrl =
  `https://api.github.com/repos/traefik/traefik/releases/tags/v${releaseVersionToUse}`

Instalacja pakietu w 2026 roku ściąga zatem Traefika 2.4.9 z 2021 roku, czyli wydanie starsze o pięć lat i o dwie gałęzie główne od tego, co jest utrzymywane. Pobieranie odbywa się w skrypcie install, więc dzieje się automatycznie podczas npm install, a niewierzytelnione zapytanie do GitHuba wpada w limit szybkości przy pierwszym zbiegu okoliczności w środowisku ciągłej integracji.

Osobna ciekawostka dotyczy licencji. Paczka npm deklaruje "license": "MIT" i zawiera plik LICENSE.md, ale jego treść to skopiowany tekst licencji Traefika z notą „Copyright (c) 2016-2020 Containous SAS; 2020-2021 Traefik Labs". Narzędzie zbierające metadane licencyjne z node_modules zaraportuje więc, że w projekcie jest komponent objęty prawami Traefik Labs, mimo że kod nakładki napisał ktoś inny. To sytuacja, w której wszystkie trzy źródła mówią „MIT", a mimo to obraz jest mylący.

Code
Bash
# to NIE jest pakiet od Traefik Labs
npm view traefik version          # 1.0.0
npm view traefik repository.url   # git+https://github.com/hello-seam/node-traefik.git
npm view traefik time.modified    # 2022-05-22T03:25:33.105Z

# tak instaluje się prawdziwy Traefik
docker pull traefik:v3.7.11

curl -sL https://github.com/traefik/traefik/releases/download/v3.7.11/traefik_v3.7.11_linux_amd64.tar.gz \
  | tar -xz traefik LICENSE.md

Traefik jest programem w Go dystrybuowanym jako pojedyncze binarium albo obraz kontenera. Nie ma oficjalnego kanału npm, nie ma oficjalnego pakietu w PyPI i nie ma powodu, żeby proxy wjeżdżało do projektu przez package.json.

Konfiguracja statyczna i dynamiczna

Konfiguracja statyczna trafia do pliku, do zmiennych środowiskowych albo do flag wiersza poleceń. Domyślnie proces szuka pliku pod czterema ścieżkami bazowymi, w tej kolejności: /etc/traefik/traefik, $XDG_CONFIG_HOME/traefik, $HOME/.config/traefik i ./traefik, próbując rozszerzeń toml, yaml i yml. Własną lokalizację wskazuje flaga --configFile.

/etc/traefik/traefik.yml
YAML
# /etc/traefik/traefik.yml, warstwa statyczna
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: "proxy"
    watch: true

certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@example.com
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web

Jedno pole z tego przykładu zasługuje na szczególną uwagę. providers.docker.exposedByDefault ma domyślną wartość true, co oznacza, że bez tej linii Traefik wystawi do internetu każdy kontener widoczny na gnieździe demona, w tym bazę danych i kolejkę. Domyślna reguła to Host({{ normalize .Name }}), czyli nazwa kontenera jako nazwa hosta. Ustawienie false odwraca logikę: routowane są tylko kontenery z etykietą traefik.enable=true.

Warstwa dynamiczna dla Dockera to etykiety. Nazwa routera i nazwa usługi w środku etykiety są dowolne i służą wyłącznie do wiązania powiązanych ze sobą wpisów.

Code
YAML
services:
  traefik:
    image: traefik:v3.7.11
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
      - ./letsencrypt:/letsencrypt
    networks: [proxy]

  api:
    image: ghcr.io/example/api:1.4.2
    labels:
      - traefik.enable=true
      - traefik.http.routers.api.rule=Host(`api.example.com`)
      - traefik.http.routers.api.entrypoints=websecure
      - traefik.http.routers.api.tls.certresolver=letsencrypt
      - traefik.http.services.api.loadbalancer.server.port=8080
      - traefik.docker.network=proxy
    networks: [proxy]

W Kubernetesie ten sam opis przybiera postać zasobu własnego. Grupa to traefik.io/v1alpha1, a przed pierwszym użyciem trzeba wgrać definicje zasobów i reguły dostępu z katalogu dynamic-configuration w repozytorium.

Code
YAML
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: api-route
  namespace: apps
spec:
  entryPoints:
    - websecure
  routes:
    - kind: Rule
      match: Host(`api.example.com`) && PathPrefix(`/v1`)
      priority: 10
      services:
        - kind: Service
          name: api
          port: 8080
          passHostHeader: true
  tls:
    certResolver: letsencrypt

Pole priority rozstrzyga kolizje między regułami. Bez niego Traefik sortuje reguły po długości ich zapisu tekstowego, co bywa zaskakujące, gdy dwie trasy pasują do tego samego żądania.

Certyfikaty ACME i ich granice

Certyfikatami zajmuje się mechanizm nazwany certificate resolver. Deklaruje się go raz w warstwie statycznej, a potem wskazuje po nazwie z poziomu trasy przez tls.certresolver. Wymagane pola to email i storage, przy czym storage domyślnie wskazuje na acme.json w katalogu roboczym.

Wyzwanie wybiera się jedno z trzech. httpChallenge.entryPoint wskazuje punkt wejścia nasłuchujący na porcie 80, który musi być osiągalny z zewnątrz. tlsChallenge wykorzystuje TLS-ALPN-01 na porcie 443. dnsChallenge.provider sięga po wpis TXT w strefie DNS i tylko ta droga daje certyfikaty wieloznaczne, bo do wpisu w DNS potrzebne są dane dostępowe do dostawcy, przekazywane przez zmienne środowiskowe zgodnie z listą biblioteki Lego.

Domyślny urząd to https://acme-v02.api.letsencrypt.org/directory, domyślny typ klucza to RSA4096, a Traefik zakłada certyfikaty 90-dniowe i rozpoczyna odnawianie 30 dni przed wygaśnięciem. Dla urzędów wystawiających certyfikaty o innym okresie ważności służy certificatesDuration podawane w godzinach, z wartością domyślną 2160.

Tu leży najważniejsze ograniczenie darmowego wariantu i trzeba je znać przed projektowaniem wdrożenia. Magazyn acme.json to zwykły plik na dysku, a nie rozproszony magazyn ze spójnością. Dwie repliki Traefika czytające ten sam plik przez współdzielony wolumin będą się o niego biły i obie zamówią własne certyfikaty, marnując limity urzędu. Rozwiązaniem po stronie producenta jest funkcja o nazwie Distributed Let's Encrypt, dostępna wyłącznie w płatnym Traefik Hub. W wariancie otwartym poprawne wyjścia to jedna replika terminująca TLS, certyfikaty wystawiane poza Traefikiem i wstrzykiwane jako sekrety, albo mechanizm zewnętrzny w rodzaju cert-managera w Kubernetesie.

Traefik Proxy, Hub i Enterprise

Dokumentacja i strona produktowa mieszają trzy produkty na jednym poziomie nawigacji, więc bardzo łatwo napisać przykład korzystający z funkcji, której w wersji darmowej po prostu nie ma.

FunkcjaTraefik Proxy (MIT)Traefik Hub API GatewayTraefik Hub API Management
Automatyczne wykrywanie usługtaktaktak
HTTP/2, HTTP/3, TCP, UDP, gRPC, WebSocketstaktaktak
Metryki i ślady OpenTelemetrytaktaktak
Wdrożenia kanarkowe, panel widoku ingressutaktaktak
OIDC, LDAP, JWT, HMAC, klucze API, Open Policy Agentnietaktak
Wbudowany firewall aplikacyjnynietaktak
Distributed Let's Encrypt, rozproszony rate limitingnietaktak
Buforowanie HTTP, panel widoku klastra, wiele klastrównietaktak
FIPS 140-2 i 140-3nietaktak
Portal deweloperski, wersjonowanie i plany APInienietak
Tryb odcięty od sieci, mockowanie APInienietak

Cennika nie ma. Strona traefik.io/pricing zestawia trzy kolumny, ale przy Traefik Proxy jest przycisk pobrania i osobna oferta wsparcia dla wersji otwartej, a przy obu wariantach Hub widnieje wyłącznie „Get pricing". Żadnej liczby, żadnego progu, żadnej informacji o jednostce rozliczeniowej. Wycenę trzeba wyciągnąć rozmową z handlowcem, co przy porównywaniu z konkurencją oznacza tygodnie zamiast minut.

Traefik Enterprise, opisywany jeszcze przed rokiem jako osobny produkt, ma na własnej stronie baner mówiący wprost, że został przeniesiony do Traefik Hub. Dokumentacja pod doc.traefik.io/traefik-enterprise/ nadal odpowiada, więc istniejące wdrożenia mają gdzie zaglądać, ale nowy projekt nie ma po co tam wchodzić. To także sygnał o ryzyku przywiązania do dostawcy: linia płatna zmieniła nazwę i kształt, a klienci musieli przejść na nową.

Uczciwie trzeba dodać, że sam Traefik Proxy jest kompletny. Reverse proxy, load balancer, kontroler ingressu, middleware z przekierowaniami, nagłówkami, uwierzytelnianiem podstawowym i ograniczaniem liczby żądań na instancję, katalog wtyczek pisanych w Go. Dla pojedynczego serwera albo jednego klastra to komplet. Płatne warianty zaczynają mieć sens dopiero przy wielu klastrach i wymaganiach zgodnościowych.

Traefik a Caddy i nginx

Caddy rozwiązuje częściowo ten sam problem: też jest w Go, też sam bierze certyfikaty i też chce zastąpić parę nginx plus certbot. Różnica siedzi w tym, skąd bierze się lista tras.

KryteriumTraefik Proxy 3.7Caddy 2nginx z certbotem
Źródło trasprovidery: Docker, Kubernetes, Consul, Nomad, plikCaddyfile albo JSON przez admin APIpliki w katalogu konfiguracyjnym
Reakcja na nowy kontenerautomatyczna, bez przeładowaniaedycja pliku i przeładowanieedycja pliku i przeładowanie
CertyfikatycertificatesResolvers z magazynem plikowymwbudowane, włączone domyślnieosobny proces i harmonogram
Cała konfiguracja w jednym plikunie, trasy siedzą w etykietachtaktak
LicencjaMITApache 2.0BSD 2-clause
Płatny wariantTraefik Hub, cena na zapytaniebrak, finansowanie ze sponsoringubrak w rdzeniu

Wybór rozstrzyga zmienność środowiska, a nie sympatia do składni. Przy stałym zestawie kilku usług, gdzie adresy zmieniają się raz na kwartał, plik Caddy'ego jest po prostu lepszy: mieści się na ekranie, wchodzi do repozytorium, przegląda się go w minutę i przy awarii widać całą prawdę w jednym miejscu. Traefik w takim układzie dokłada demona obserwującego zdarzenia, żeby wykryć zmianę, która i tak nie zachodzi.

Przy dziesiątkach kontenerów wstających i gasnących w rytmie wdrożeń proporcje się odwracają. Generowanie pliku Caddy'ego z szablonu i przeładowywanie go przy każdej zmianie odtwarza dokładnie tę mechanikę, którą Traefik ma wbudowaną, tyle że własnym kodem, który trzeba utrzymywać i który potrafi zawieść po cichu. Etykieta przy kontenerze mieszka obok definicji usługi, więc wdrożenie i trasa zmieniają się w jednej rewizji.

Warto też odnotować, że wiele platform wdrożeniowych rozstrzyga ten wybór za Ciebie. Coolify stawia Traefika jako domyślne proxy i sam dorzuca etykiety do uruchamianych kontenerów. Railway i Fly.io mają własne warstwy sieciowe i tam pytanie w ogóle nie powstaje. Jeśli usługi za proxy to głównie PostgreSQL i Redis, czyli protokoły inne niż HTTP, potrzebny jest router TCP z regułą HostSNI, a nie zwykły router HTTP.

Typowe błędy

Pozostawienie exposedByDefault na wartości domyślnej. Efektem jest publiczny adres dla każdego kontenera w sieci, łącznie z tymi, które nigdy nie miały wyjść na zewnątrz.

Montowanie /var/run/docker.sock do zapisu. Dostęp do gniazda demona jest równoważny uprawnieniom administratora na hoście, więc proxy wystawione do internetu z takim woluminem to poważne ryzyko. Minimum to przyrostek :ro, lepiej pośrednik ograniczający zakres wywołań.

Dwie repliki na jednym pliku acme.json. Skutkiem są zdublowane zamówienia certyfikatów i wyczerpanie tygodniowego limitu urzędu, po czym domena zostaje bez ważnego certyfikatu do końca okna limitu.

Kontener i Traefik w różnych sieciach Dockera. Trasa powstaje, panel ją pokazuje, a odpowiedzią jest błąd bramy, bo proxy nie ma jak połączyć się z adresem docelowym. Etykieta traefik.docker.network albo pole providers.docker.network rozstrzyga sprawę.

Pominięcie loadbalancer.server.port, gdy obraz udostępnia więcej niż jeden port. Traefik zgaduje wtedy port i zgaduje źle.

Wystawienie panelu z api.insecure=true na publicznym punkcie wejścia. Panel pokazuje pełną tablicę tras i konfigurację middleware, czyli mapę infrastruktury.

Przenoszenie konfiguracji z gałęzi drugiej do trzeciej bez lektury przewodnika migracji. Nazwy providerów, składnia reguł i część pól przeszły zmiany niezgodne wstecz, a stary plik potrafi wstać z częścią tras po cichu pominiętych.

FAQ

Czy pakiet npm o nazwie traefik to oficjalny Traefik?

Nie. Wersja 1.0.0 z 2 sierpnia 2021 roku pochodzi z repozytorium hello-seam/node-traefik i jest nieoficjalną nakładką jednej osoby. Zawiera działający kod, ale ma zaszytą wersję Traefika 2.4.9 i pobiera ją z niewierzytelnionego zapytania do interfejsu GitHuba. Oficjalna dystrybucja to binarium z sekcji wydań albo obraz traefik.

Jaka jest licencja Traefika i gdzie jej szukać?

MIT, w pliku LICENSE.md w katalogu głównym repozytorium, z notą praw autorskich Containous SAS i Traefik Labs. Plik jest też w archiwum wydania, ale nie ma go w oficjalnym obrazie kontenera, bo Dockerfile wypakowuje z archiwum wyłącznie binarium.

Czy Traefik obsłuży automatyczne certyfikaty przy kilku replikach?

Nie w wersji otwartej. Magazyn acme.json to plik i nie ma w nim koordynacji między instancjami. Funkcja Distributed Let's Encrypt należy do płatnego Traefik Hub. Przy wielu replikach sensowniejsze jest wystawianie certyfikatów poza proxy, na przykład cert-managerem.

Ile kosztuje Traefik Hub?

Cennik nie jest publiczny. Strona cenowa przy obu wariantach Hub pokazuje wyłącznie przycisk „Get pricing", bez stawki, progu i jednostki rozliczeniowej. Wycenę trzeba uzyskać od działu handlowego.

Traefik czy Caddy do jednego serwera z kilkoma usługami?

Przy stałym zestawie usług Caddy zwykle wypada lepiej, bo cała konfiguracja mieści się w jednym krótkim pliku. Traefik zaczyna się opłacać, gdy usługi wstają i gasną same, a lista tras zmienia się przy każdym wdrożeniu.

Czy Traefik przepuści ruch inny niż HTTP?

Tak. Poza routerami HTTP są routery TCP z regułami opartymi o HostSNI oraz routery UDP. Dzięki temu za jednym punktem wejścia można postawić także usługi bazodanowe, choć bez nazwy w SNI rozróżnienie kilku usług na jednym porcie nie jest możliwe.

Źródła: repozytorium projektu, strona z cennikiem, wpis pakietu w rejestrze npm.

Czytaj dalej

Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie