- Replaced the existing reverse proxy implementation with a new alias forwarding mechanism, improving path handling and request normalization. - Updated the gateway to utilize the new forwarding approach, ensuring consistent handling of API requests and proper error management. - Enhanced tests to validate the new routing behavior, including handling of double slashes and user endpoint requests. - Improved documentation in GATEWAY_RUN.md to clarify the updated API routing and configuration requirements.
16 KiB
Запуск Telemt API Gateway (Docker)
Оглавление:
- Назначение
- Требования
- Минимальная конфигурация
- Переменные окружения
- Готовый образ из registry
- Локальная сборка образа
- Запуск через Docker CLI
- Запуск через Docker Compose
- Проверка
- Обновление и CI/CD
- Устранение неполадок
Назначение
Шлюз — это один HTTP‑вход для нескольких экземпляров Telemt Control API:
- Web UI (в образе Docker): статика панели на
GET /(и клиентские маршруты SPA), агрегаты и прокси на/api/…. Тот же порт, что и у API (например8080). Исходники UI — каталог web/, сборка встроена в Dockerfile (стадия Node +embedв Go). - Белый список IP (CIDR): кто может обращаться к шлюзу (кроме
GET /health, см. ниже). - Маршрутизация по alias: клиент вызывает
GET /api/{alias}/health, шлюз проксирует на{base_url}/v1/healthу соответствующего сервера. - Метрики Prometheus:
GET /metrics(под тем же правилом whitelist, что и API). - Доверенные прокси: если прямой TCP‑peer входит в
trusted_proxies, для проверки whitelist берётся первый адрес изX-Forwarded-ForилиX-Real-IP.
Эндпоинты и контракт ответов бэкенда описаны в API.md.
Требования
- Установленные Docker и при необходимости Docker Compose v2.
- Для локальной сборки Docker-образа из репозитория: Docker сам подтянет Node на стадии сборки фронта и Go 1.22+ на стадии компиляции (см. Dockerfile).
- Для
go test ./...без Docker на машине нужен только Go 1.22+.
Минимальная конфигурация
Скопируйте config.example.yaml в свой config.yaml и отредактируйте.
Минимальный рабочий фрагмент для разработки (без проверки IP):
listen: ":8080"
allow_all: true
servers:
- alias: main_srv
base_url: http://127.0.0.1:9091
Минимальный фрагмент для продакшена (только перечисленные сети/хосты):
listen: ":8080"
allow_all: false
whitelist_cidrs:
- "203.0.113.10/32"
- "10.0.0.0/8"
servers:
- alias: main_srv
base_url: http://telemt-internal:9091
Правила:
- При
allow_all: falseи пустомwhitelist_cidrsдоступ будет закрыт для всех (кромеGET /health). - В
whitelist_cidrsиtrusted_proxiesдопустимы CIDR (10.0.0.0/8) и одиночный IPv4/IPv6 без маски (87.103.241.8эквивалентно87.103.241.8/32). GET /healthна шлюзе не проверяется по whitelist — так проще настроить DockerHEALTHCHECKи оркестраторы.- Поле
path_prefixпо умолчанию равно/v1(префикс Telemt Control API).
Опционально для бэкенда с включённым auth_header в Telemt задайте в конфиге имя переменной окружения, значение которой будет отправлено как заголовок Authorization на этот upstream:
servers:
- alias: main_srv
base_url: http://telemt:9091
authorization_env: TELEMT_API_AUTH
Значение должно точно совпадать с настроенным в Telemt auth_header (см. API.md).
Переменные окружения
| Переменная | Описание |
|---|---|
CONFIG_PATH |
Путь к YAML внутри контейнера. По умолчанию: /etc/telemt-gateway/config.yaml. |
TELEMT_API_AUTH |
Пример: секрет для authorization_env в конфиге (имя может быть любым). |
Готовый образ из registry
CI публикует образ в Container Registry Gitea. Для репозитория denozord/telemt-api на git.shts.su стабильный тег:
docker pull git.shts.su/denozord/telemt-api:latest
Если registry не публичный, сначала войдите (логин — пользователь Gitea, пароль — personal access token с правом read:package):
docker login git.shts.su
Другие полезные теги из того же workflow: имя ветки (с / заменённым на -) и sha-<12 символов коммита> — см. раздел Обновление и CI/CD.
Локальная сборка образа
Если нужно собрать образ самостоятельно из клона репозитория:
docker build -t telemt-api-gateway:local .
Сборка многостадийная: сначала npm ci + npm run build в каталоге web/ (в бандл вшивается пустой PUBLIC_TELEMT_GATEWAY_URL, запросы API с того же origin), затем компиляция Go со встраиванием web/build через embed. В командах docker run ниже вместо имени из registry подставьте telemt-api-gateway:local.
Запуск через Docker CLI
Пример для Linux (подставьте путь к config.yaml; ниже — файл из текущего каталога). Используется готовый образ:
docker run -d --name telemt-gateway \
-p 8080:8080 \
-v "$(pwd)/config.yaml:/etc/telemt-gateway/config.yaml:ro" \
-e CONFIG_PATH=/etc/telemt-gateway/config.yaml \
git.shts.su/denozord/telemt-api:latest
Проверка:
curl -sS -i http://127.0.0.1:8080/health
curl -sS -i http://127.0.0.1:8080/api/main_srv/health
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/
Второй запрос проксируется на {base_url}/v1/health для alias main_srv. Третий — HTML панели (в образах, собранных с Web UI; ожидайте 200).
Панель в браузере: http://127.0.0.1:8080/ (при allow_all: false ваш IP должен быть в whitelist_cidrs, иначе для / будет 403, как и для API).
Остановка и удаление:
docker stop telemt-gateway
docker rm telemt-gateway
Запуск через Docker Compose
В репозитории есть docker-compose.yml (один сервис gateway) и пример config.compose.yaml с allow_all: true и base_url: http://host.docker.internal:9091 (Telemt на хосте; на Docker Desktop для Linux это обычно работает из коробки). Образ по умолчанию скачивается из registry, локальная сборка не требуется. UI доступен на том же порту, что и шлюз: http://127.0.0.1:8080/.
docker compose pull
docker compose up -d
docker compose logs -f gateway
docker compose down
Чтобы пересобрать образ из исходников вместо pull, в docker-compose.yml временно замените блок image: на build: . (и нужный тег при необходимости).
На Linux без host.docker.internal сделайте одно из:
- в
docker-compose.ymlдля сервисаgatewayдобавьтеextra_hosts: ["host.docker.internal:host-gateway"](Docker Engine 20.10+); - либо замените в
config.compose.yamlзначениеbase_urlна IP хоста в docker‑bridge (часто172.17.0.1) или на имя сервиса Telemt в той же сети compose.
Проверка
| Сценарий | Ожидание |
|---|---|
GET /health |
200, JSON {"status":"ok"} |
GET / (образ с Web UI) |
200, HTML панели |
| Разрешённый IP, корректный alias | ответ бэкенда (например 200 для /v1/health) |
| IP не в whitelist | 403, JSON с code: forbidden |
| Неизвестный alias | 404, JSON с code: not_found |
| Бэкенд недоступен | 502, JSON с code: bad_gateway |
GET /metrics |
текст метрик Prometheus (при разрешённом IP) |
Обновление и CI/CD
-
Образ: подтяните свежий тег (
docker pull git.shts.su/denozord/telemt-api:latestилиdocker compose pull), пересоздайте контейнер (docker compose up -dили новыйdocker runс тем же volume конфига). Локальная пересборка нужна только если вы меняете Dockerfile/код и не пользуетесь CI. Образы, собранные до добавления стадииweb/в Dockerfile, могут отдавать на/только заглушку — нужен образ из актуального CI или локальныйdocker build. -
Конфиг: отредактируйте файл на хосте и перезапустите контейнер (шлюз не перечитывает конфиг на лету).
-
Gitea Actions: workflow .gitea/workflows/docker.yaml сначала выполняет
go mod tidy && go test ./..., затем собирает образ через Buildx по Dockerfile (стадии Node дляweb/и Go) и пушит в Container Registry Gitea.- В репозитории должен быть secret
ACTIONS_PAT— personal access token пользователя с правомwrite:package(и при необходимостиread:package), как для обычногоdocker loginк registry. - Логин в registry: пользователь
gitea.actor(кто запустил workflow), пароль — этот PAT. - Хост registry задаётся в workflow в
env.REGISTRY(по умолчаниюgit.shts.su); при другом инстансе Gitea измените значение в.gitea/workflows/docker.yaml. - Теги образа:
latest, имя ветки/тега (с/заменённым на-), иsha-<первые 12 символов коммита>. Полный путь:{REGISTRY}/{gitea.repository}:<тег>.
- В репозитории должен быть secret
Устранение неполадок
- Nginx с
location /api/иproxy_pass http://…:9091/;(со слэшем в конце) на бэкенд уходит путь без префикса/api/(например запрос к nginxGET /api/v1/usersпревращается вGET /v1/usersна Telemt). Шлюз приbase_url: https://gt2.example/api/должен запрашивать именно/api/v1/…на стороне nginx. Если вbase_urlнет пути/api/(толькоhttps://gt2.example), шлюз обратится кhttps://gt2.example/v1/…— часто это не попадает вlocation /api/, и nginx отдаёт чужой vhost / заглушку. Задавайтеbase_urlс завершающим слэшем:https://gt2.example/api/. - Заголовок
Host: шлюз выставляетHostравным хосту изbase_url(как у обычного клиента к этому имени). Если после обновления образа проблема остаётся, с хоста шлюза проверьте:curl -sv -o /dev/null https://gt2…/api/v1/healthи сравните с запросом через шлюз. 400на/api/{alias}/…при локальномbase_url(напримерhttp://172.20.0.3:9091), хотяcurlк:9091/v1/…даёт200: частая причина — несовпадение заголовкаHost: браузер шлётHost: публичное_имя:8888, а при прямомcurlк IP вHostпопадает172.20.0.3:9091. Строгий upstream (часто hyper/Rust) отвечает400, еслиHostне совпадает с ожидаемым authority. Шлюз при проксировании не пересылает клиентскийHostи выставляет authority изbase_url(как серверные запросы агрегатора). Убедитесь также, что в YAML нет пробела/переноса в концеbase_url(поля обрезаютсяTrimSpace), и в URL нет лишнего/api//…(путь под/apiнормализуется).- Список пользователей через шлюз: запрос
GETилиHEADна/api/{alias}/usersшлюз перенаправляет на upstreamGET/HEAD /v1/stats/users(как и агрегатор). Так совместимы сборки Telemt, где прямойGET /v1/usersдаёт ошибку (например400), а/v1/stats/usersработает.POST /api/{alias}/users(создание) иGET /api/{alias}/users/{username}по-прежнему идут на/v1/usersи/v1/users/{username}. Явный путь/api/{alias}/stats/usersне меняется. См. API.md. docker pull:unauthorized/denied: выполнитеdocker login git.shts.suс учётной записью Gitea и PAT сread:package.403 forbiddenс хоста приallow_all: false: добавьте CIDR клиента вwhitelist_cidrs. Запросы из контейнера к самому себе идут с127.0.0.1— при необходимости добавьте127.0.0.1/32.- За reverse proxy: укажите CIDR прокси в
trusted_proxies, иначе whitelist видит IP прокси, а не клиента. 502 bad_gateway: проверьтеbase_url, DNS в Docker‑сети и то, что Telemt слушает API ([server.api].enabled=trueи корректныйlisten).- Сборка Go без Docker: в корне репозитория выполните
go mod tidy && go test ./....