Главная фишка Traefik — сервисы регистрируют себя сами. Добавил labels в docker-compose.yml, поднял контейнер — Traefik его уже видит и маршрутизирует. Никаких отдельных конфигов, никакой ручной работы.
Переписываем docker-compose.yml приложения под Traefik labels:
# /opt/applab/docker-compose.yml
version: '3.8'
services:
# API Gateway — api.applab.dev
api-gateway:
image: applab/api-gateway:${TAG:-latest}
restart: always
networks:
- traefik-public
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.applab.dev`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.services.api.loadbalancer.server.port=3000"
- "traefik.http.services.api.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.api.loadbalancer.healthcheck.interval=10s"
- "traefik.http.routers.api.middlewares=api-ratelimit,security-headers"
# Auth Service — api.applab.dev/auth/*
auth-service:
image: applab/auth-service:${TAG:-latest}
restart: always
networks:
- traefik-public
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.auth.rule=Host(`api.applab.dev`) && PathPrefix(`/auth`)"
- "traefik.http.routers.auth.entrypoints=websecure"
- "traefik.http.routers.auth.tls.certresolver=letsencrypt"
- "traefik.http.services.auth.loadbalancer.server.port=3001"
- "traefik.http.services.auth.loadbalancer.healthcheck.path=/health"
- "traefik.http.routers.auth.middlewares=api-ratelimit,security-headers"
# Catalog — api.applab.dev/catalog/*
catalog:
image: applab/catalog:${TAG:-latest}
restart: always
networks:
- traefik-public
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.catalog.rule=Host(`api.applab.dev`) && PathPrefix(`/catalog`)"
- "traefik.http.routers.catalog.entrypoints=websecure"
- "traefik.http.routers.catalog.tls.certresolver=letsencrypt"
- "traefik.http.services.catalog.loadbalancer.server.port=3002"
- "traefik.http.routers.catalog.middlewares=api-ratelimit,security-headers"
# Cart — api.applab.dev/cart/*
cart:
image: applab/cart:${TAG:-latest}
restart: always
networks:
- traefik-public
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.cart.rule=Host(`api.applab.dev`) && PathPrefix(`/cart`)"
- "traefik.http.routers.cart.entrypoints=websecure"
- "traefik.http.services.cart.loadbalancer.server.port=3003"
- "traefik.http.routers.cart.middlewares=api-ratelimit,security-headers,auth-forward"
# Payments — api.applab.dev/payments/*
payments:
image: applab/payments:${TAG:-latest}
restart: always
networks:
- traefik-public
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.payments.rule=Host(`api.applab.dev`) && PathPrefix(`/payments`)"
- "traefik.http.routers.payments.entrypoints=websecure"
- "traefik.http.services.payments.loadbalancer.server.port=3004"
- "traefik.http.routers.payments.middlewares=payments-ratelimit,security-headers,auth-forward"
# Notifications — внутренний, без внешнего доступа
notifications:
image: applab/notifications:${TAG:-latest}
restart: always
networks:
- internal
# Нет traefik.enable — сервис не виден снаружи
# Analytics — api.applab.dev/analytics/*
analytics:
image: applab/analytics:${TAG:-latest}
restart: always
networks:
- traefik-public
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.analytics.rule=Host(`api.applab.dev`) && PathPrefix(`/analytics`)"
- "traefik.http.routers.analytics.entrypoints=websecure"
- "traefik.http.services.analytics.loadbalancer.server.port=3006"
- "traefik.http.routers.analytics.middlewares=security-headers,auth-forward"
# Admin Panel — admin.applab.dev
admin-panel:
image: applab/admin-panel:${TAG:-latest}
restart: always
networks:
- traefik-public
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.admin.rule=Host(`admin.applab.dev`)"
- "traefik.http.routers.admin.entrypoints=websecure"
- "traefik.http.routers.admin.tls.certresolver=letsencrypt"
- "traefik.http.services.admin.loadbalancer.server.port=3007"
- "traefik.http.routers.admin.middlewares=admin-ipwhitelist,security-headers"
networks:
traefik-public:
external: true
internal:
driver: bridge
Обратите внимание: ни одного IP-адреса или порта в конфигурации Traefik. Он сам лезет в Docker socket, читает labels и строит маршруты. Добавляешь новый сервис — просто пишешь labels в его docker-compose, и через несколько секунд Traefik его уже обслуживает. Без перезагрузок, без правки конфигов.
Traefik постоянно проверяет здоровье каждого сервиса и молча выводит упавшие инстансы из балансировки — трафик на мёртвые контейнеры больше не летит:
# Health check конфигурация (через labels):
# loadbalancer.healthcheck.path=/health — путь для проверки
# loadbalancer.healthcheck.interval=10s — проверка каждые 10 секунд
# loadbalancer.healthcheck.timeout=3s — таймаут запроса
# В каждом микросервисе реализован эндпоинт /health:
# Пример для api-gateway (Node.js / Express):
# app.get('/health', (req, res) => {
# const checks = {
# uptime: process.uptime(),
# memory: process.memoryUsage(),
# db: await checkDatabaseConnection(),
# redis: await checkRedisConnection()
# };
# const healthy = checks.db && checks.redis;
# res.status(healthy ? 200 : 503).json(checks);
# });
# Traefik автоматически:
# 1. Опрашивает /health каждые 10 секунд
# 2. Если сервис вернул не 2xx — помечает как unhealthy
# 3. Перестаёт отправлять трафик на unhealthy-инстанс
# 4. Продолжает проверять — если сервис восстановился, возвращает в пул
# Логи Traefik при падении сервиса:
# level=warn msg="Health check failed for service catalog@docker"
# url=http://172.20.0.5:3002/health error="connection refused"