22 KiB
Конфигурация проекта workflows-api
workflows-api — HTTP-сервис (Go 1.24, фреймворк Fiber v2) для работы с workflow: создание, чтение, перезапуск задач, отмена запусков, приоритизация. Хранилище — PostgreSQL. Трейсинг — OpenTelemetry (через внешнюю библиотеку gitlab.sarex.io/infra/golang-fiber-otel-tools).
Способы конфигурирования
Конфигурация читается только из переменных окружения. Используется библиотека github.com/ilyakaznacheev/cleanenv (cleanenv.ReadEnv). Файлы конфигурации (.yaml, .json) не читаются — вызывается именно ReadEnv, а не ReadConfig.
- Префикс у переменных отсутствует — используются «плоские» имена (
POSTGRES_ADDRESS,HTTP_HOSTи т. п.). - Вложенность структуры
Configописывается через встроенные (embedded) структуры (App,Log,HTTP,pgxconnection.Postgres,TRACER,Execution), но на имена переменных это не влияет — тегиenvзаданы плоско. - Значения по умолчанию задаются тегом
env-default. - Булевы значения cleanenv принимает как
true/false, а также1/0(в Helm используется числовая форма).
Точка сборки конфигурации — config/config.go, функция config.New(). Отдельно, для запуска миграций, вторая структура pkg/postgres/gopg.Postgres читается своим вызовом cleanenv.ReadEnv в gopg.GetPgConnectionWithoutConfig() — у неё те же имена переменных, но частично другие значения по умолчанию (см. «Замечания»).
Способы запуска
| Способ запуска | Откуда берутся переменные |
|---|---|
Бинарь httpserver (production, Dockerfile ENTRYPOINT ["/httpserver", "migrate"]) |
Переменные окружения контейнера (в k8s — из Helm-чарта: блоки envs и secretEnvs) |
Бинарь migrations (отдельный ранер миграций) |
Переменные окружения контейнера |
Локальный запуск через air (.air.toml, hot-reload, сборка ./cmd/httpserver/main.go) |
Переменные окружения оболочки / .env (подхватываются вручную), значения по умолчанию из кода |
docker-compose up (docker-compose.yaml) |
environment: в compose + значения по умолчанию из кода |
Точки входа и вспомогательные скрипты
| Файл / скрипт | Назначение |
|---|---|
cmd/httpserver/main.go |
Основная точка входа. Если передан хотя бы один аргумент (например migrate) — сначала выполняет миграции (go-pg-migrations), затем поднимает Fiber-сервер |
cmd/migrations/main.go |
Отдельный бинарь только для миграций (без запуска сервера) |
Dockerfile |
Multi-stage сборка: собирает httpserver и migrations, ENTRYPOINT ["/httpserver", "migrate"] |
entrypoint.sh |
Скрипт-обёртка (/go/bin/migrations migrate → /go/bin/httpserver). Не используется Dockerfile и ссылается на несуществующие пути бинарей — устаревший артефакт (см. «Замечания») |
.air.toml |
Конфиг hot-reload air для локальной разработки |
docker-compose.yaml |
Локальный стенд: PostgreSQL 14-alpine + сборка API. Блок migrations закомментирован |
Makefile |
Юнит-тесты, генерация моков, поднятие/сборка контейнера БД (.docker/postgres) |
.docker/postgres/Dockerfile |
Образ локальной БД для make container-run-deps |
Порядок старта контейнера (production)
- Контейнер стартует с
ENTRYPOINT ["/httpserver", "migrate"]. httpserverвидит аргументmigrate(len(os.Args) > 1) → открывает подключение к БД черезgo-pg(gopg.GetPgConnectionWithoutConfig, читает env заново) и прогоняет миграции изcmd/migrations/migrationfiles.- После миграций поднимается Fiber-приложение (
server.New→server.Run), подключается пулpgx(pgxconnection.GetPgConnection), приTRACER_USE=trueинициализируется трейсер/otel-логгер. - Сервер слушает адрес из
HTTP_HOST. Health-check —GET /ping.
Переменные приложения
Ниже — переменные, которые реально читает код (config/config.go + pkg/postgres/pgxconnection/postgres.go).
App (config/config.go)
| Переменная | Тип | Значение по умолчанию | Назначение |
|---|---|---|---|
APP_NAME |
string | workflows-api |
Имя приложения (App.Name) |
APP_VERSION |
string | v1 |
Версия приложения (App.Version) |
Log
| Переменная | Тип | Значение по умолчанию | Назначение |
|---|---|---|---|
LOG_LEVEL |
string | info |
Уровень логирования (logging.NewLogger) |
HTTP
| Переменная | Тип | Значение по умолчанию | Назначение |
|---|---|---|---|
HTTP_HOST |
string | 0.0.0.0:8000 |
Адрес и порт прослушивания Fiber-сервера |
PUBLIC_KEY |
string | — (пусто) | PEM-публичный ключ (PKIX) для проверки JWT Sarex. Обязателен: при пустом значении auth.New вызывает panic на старте |
HTTP_BODY_LIMIT |
int | 268435456 (256 MiB) |
Максимальный размер тела запроса (fiber.Config.BodyLimit) |
HTTP_READ_BUFFER_SIZE |
int | 98304 (96 KiB) |
Размер буфера чтения (fiber.Config.ReadBufferSize) |
Database (pkg/postgres/pgxconnection)
| Переменная | Тип | Значение по умолчанию | Назначение |
|---|---|---|---|
POSTGRES_ADDRESS |
string | localhost |
Хост PostgreSQL |
POSTGRES_DB |
string | processing_db |
Имя базы данных |
POSTGRES_USER |
string | sarex |
Пользователь БД |
POSTGRES_PASSWORD |
string | sarex |
Пароль БД |
POSTGRES_PORT |
string | 5432 |
Порт PostgreSQL |
POSTGRES_POOL_SIZE |
int | 3 |
Размер пула (используется только для логирования; фактический размер пула pgx задаётся строкой подключения) |
ENABLE_SQL_QUERY |
bool | true |
Флаг логирования SQL. Читается в конфиг, но нигде не используется (см. «Замечания») |
YC-PG-CERTIFICATE |
string | — (пусто) | CA-сертификат (PEM) для TLS-подключения к БД. Непустое значение включает TLS |
POSTGRES_SSL_USE |
bool | false |
Включение TLS-подключения к БД |
Tracer (config.TRACER, OpenTelemetry)
| Переменная | Тип | Значение по умолчанию | Назначение |
|---|---|---|---|
TRACER_USE |
bool | false |
Включить трейсинг/otel-логгер и otelfiber-middleware |
TRACER_HOST |
string | localhost:4317 |
Адрес OTLP-коллектора (gRPC) |
TRACER_USE_INSECURE |
bool | true |
Небезопасное (без TLS) подключение к коллектору |
SERVICE_NAME |
string | wf-test-db |
Имя сервиса в трейсах |
TRACER_LOGGER_NAME |
string | tracer_logger |
Имя otel-логгера |
Execution (лимиты ресурсов задач, config.Execution)
| Переменная | Тип | Значение по умолчанию | Назначение |
|---|---|---|---|
MAX_CPU_REQUESTS |
string | 25 |
Максимально допустимый CPU-request в конфиге execution задачи (валидация через k8s.io/apimachinery/resource) |
MAX_MEMORY_REQUESTS |
string | 300Gi |
Максимально допустимый memory-request в конфиге execution задачи |
Переменные инфраструктуры, сборки и вспомогательных утилит
Переменные Makefile (значения по умолчанию, переопределяются через make VAR=...):
| Переменная | Значение по умолчанию | Назначение |
|---|---|---|
OCI |
docker |
Контейнерный движок (docker/podman) |
WF_API_CONTAINER__NETWORK_NAME |
wf-api-network |
Имя bridge-сети для локальных контейнеров |
WF_API_DATABASE_IMAGE__TAG |
wf-api-database |
Тег образа локальной БД |
WF_API_DATABASE_CONTAINER__NAME |
wf-api-database-c |
Имя контейнера БД |
WF_API_DATABASE__VOLUME_NAME |
wf-api-data |
Имя тома данных БД |
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB / POSTGRES_PORT |
берутся из окружения | Прокидываются в контейнер БД при container-run-database |
Переменные сборки образа (Dockerfile):
| Переменная | Значение | Назначение |
|---|---|---|
CGO_ENABLED |
0 |
Статическая сборка Go |
GOOS |
linux |
Целевая ОС |
GOARCH |
amd64 |
Целевая архитектура |
Переменные .docker/postgres/Dockerfile и docker-compose.yaml (локальный стенд):
| Переменная | Значение | Назначение |
|---|---|---|
POSTGRES_DB |
processing_db |
БД локального PostgreSQL |
POSTGRES_USER |
processing |
Пользователь локального PostgreSQL |
POSTGRES_PASSWORD |
processing |
Пароль локального PostgreSQL |
POSTGRES_ADDRESS |
database (в compose для сервиса api) |
Хост БД внутри сети compose |
POSTGRES_SSL_USE |
false |
Отключение TLS локально |
Переменные из Helm-чарта
Деплой выполняется зависимостью-чартом universal-chart (.helm/Chart.yaml, версия 0.1.7), значения — в .helm/values.yaml. Значения даются по стендам через ключи _default / stage / preprod / production.
Обычные переменные (services.workflows-api.envs)
| Переменная | Значение (_default) |
Значения по стендам / примечание |
|---|---|---|
POD_NAME |
$(K8S_POD_NAME) |
Имя пода. Кодом не читается |
POSTGRES_POOL_SIZE |
3 |
Размер пула (логирование) |
HTTP_HOST |
0.0.0.0:8080 |
Адрес прослушивания в k8s (порт 8080) |
S3_SERVICE_ACCOUNT |
/etc/sarex/yc-s3/yc-s3-service-account.json |
Кодом не читается |
DJANGO_HOST |
https://stage.sarex.io |
stage: stage.sarex.io, preprod: preprod.sarex.io, production: lk.sarex.io. Кодом не читается |
OBSERVABILITY_TRACE_COLLECTOR_ENDPOINT |
opentelemetry-collector.observability.svc.cluster.local:4318 |
Одинаково на всех стендах. Кодом не читается (легаси-пакет observavility не подключён) |
ENABLE_SQL_QUERY |
0 |
Читается в конфиг, но не используется |
POSTGRES_SSL_USE |
1 |
preprod: true, остальные 1 |
ENABLE_OBSERVABILITY |
1 |
stage 1, preprod 0, production 1. Кодом не читается |
TRACER_USE |
1 |
Включает трейсинг |
TRACER_HOST |
signoz-otel-collector.signoz.svc.cluster.local:4317 |
preprod/production: signoz-otel-collector-external.signoz.svc.cluster.local:4317 |
SERVICE_NAME |
workflows-api.processing-stage |
stage: workflows-api.platform, preprod: workflows-api.processing-preprod, production: workflows-api.processing-prod |
TRACER_USE_INSECURE |
1 |
Небезопасное подключение к коллектору |
TRACER_LOGGER_NAME |
tracer_logger |
Имя otel-логгера |
MAX_CPU_REQUESTS |
25 |
Лимит CPU-request задач |
MAX_MEMORY_REQUESTS |
300Gi |
Лимит memory-request задач |
Секретные переменные (services.workflows-api.secretEnvs)
| Переменная | Секрет (secret_name) | Ключ (secret_key) |
|---|---|---|
POSTGRES_ADDRESS |
_default/stage: processing-postgresql-secret; preprod/production: ya-pg-secret |
host |
POSTGRES_PORT |
_default/stage: processing-postgresql-secret; preprod/production: ya-pg-secret |
port |
POSTGRES_DB |
_default/stage: processing-postgresql-secret; preprod/production: ya-pg-secret |
database |
POSTGRES_USER |
_default/stage: processing-postgresql-secret; preprod/production: ya-pg-secret |
_default/stage: user; preprod/production: username |
POSTGRES_PASSWORD |
_default/stage: processing-postgresql-secret; preprod/production: ya-pg-secret |
password |
PUBLIC_KEY |
_default/stage: jwt-secret; preprod/production: public-key |
_default/stage: public_key; preprod/production: key |
YC-PG-CERTIFICATE |
_default/stage: processing-postgresql-secret; preprod/production: yc-pg-certificate |
_default/stage: ca.crt; preprod/production: certificate |
Прочие параметры чарта
- Порт деплоймента:
8080; сервисClusterIP,targetPort: 8080,port: 80(stage:8000). - Имя сервиса:
workflows-service(stage:workflows-api-service). - Реплики:
_default/stage— 1, preprod/production — 2. - Ресурсы пода: requests
_default100Mi / 100m, preprod/production 200Mi / 200m. - Пробы: liveness и readiness —
httpGet /pingна порту 8080. - serviceAccount:
workflows-api-sa. - imagePullSecrets:
dockerhub. Образ:cr.yandex/crp3ccidau046kdj8g9q/workflows-api.
Переменные в CI
.gitlab-ci.yml подключает общие пайплайны generic/common-ci (common-security-scan.yaml, universal-pipeline.yaml@apps-business). Глобальные переменные:
| Переменная | Значение | Назначение |
|---|---|---|
SERVICE_NAME |
workflows-api |
Имя сервиса в пайплайне |
DOCKERFILE_PATH |
Dockerfile |
Путь к Dockerfile |
BUILD_ARGS |
--build-arg CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA} |
Аргументы сборки образа |
CI_TRIGGER_SOURCE |
app |
Источник триггера |
Маппинг ветка/тег → стенд и namespace (workflow.rules):
| Условие | STAND | NAMESPACE | CHART_VERSION | K8S_HUSTLER_BRANCH | env (universal-chart.global.env) |
|---|---|---|---|---|---|
CI_COMMIT_BRANCH == "stage" |
stage |
platform |
0.0.1-stage |
universal-chart-stage |
stage |
CI_COMMIT_BRANCH == "master" |
preprod |
processing-preprod |
0.0.1-preprod |
universal-chart-preprod |
preprod |
CI_COMMIT_TAG (любой тег) |
production |
processing-prod |
0.0.1-prod |
universal-chart-production |
production |
CI_PIPELINE_SOURCE == "merge_request_event" |
— | — | — | — | сборка образа выключена (ENABLE_BUILD_IMAGE=false) |
Во всех деплой-правилах через HELM_SET_ARGS пробрасываются IMAGE_NAME, commitSha=${CI_COMMIT_SHA}, gitlabUri, gitlabJobUrl, owner. RELEASE_NAME/CHART_NAME — workflows-api.
Джоба unittest (stage: test, образ golang:1.24, make unit-tests) запускается на любых ветках/тегах и MR, allow_failure: true.
Замечания и потенциальные проблемы
- Две разные структуры конфигурации БД с разными дефолтами. Сервер использует
pkg/postgres/pgxconnection.Postgres(дефолтыPOSTGRES_USER=sarex,POSTGRES_PASSWORD=sarex), а миграции —pkg/postgres/gopg.Postgres(дефолтыprocessing/processing). При запуске без явно заданных переменных сервер и миграции подключались бы под разными кредами. В production это не проявляется, т. к. все переменные приходят из секретов. ENABLE_SQL_QUERYне используется. Поле читается в обе структуры (EnableSQLQuery), но нигде в коде не применяется — флаг «мёртвый».OBSERVABILITY_TRACE_COLLECTOR_ENDPOINT,ENABLE_OBSERVABILITYне используются. Пакетpkg/observavility(сSetupOTelSDK) нигде не импортируется — это легаси. Реальный трейсинг настраивается переменнымиTRACER_*через внешнюю библиотекуgolang-fiber-otel-tools.POD_NAME,S3_SERVICE_ACCOUNT,DJANGO_HOSTиз Helm кодом не читаются — либо задел на будущее, либо устаревшие переменные.entrypoint.shустарел и не используется. Он ссылается на/go/bin/migrationsи/go/bin/httpserver, тогда как в образе бинари лежат в/httpserverи/migrations, аENTRYPOINTзадан вDockerfileнапрямую (/httpserver migrate).- Опечатка в mount-пути internal-middleware. В
server.gomiddleware, выставляющийis_internal=true, монтируется какapp.Use("./internal", ...)(с ведущей точкой) вместо"/internal". Из-за этого для маршрутов группы/internalфлагis_internalможет не выставляться; в контроллерахnil-значение трактуется как «внутренний/доверенный запрос» (проверки принадлежности к компании пропускаются). Логически поведение сохраняется, но путь выглядит как баг. PUBLIC_KEYобязателен. При пустом значенииauth.Newделаетpanic("failed to parse PEM block ...")— сервис не стартует. Дефолта нет.- Расхождение по порту. Дефолт кода
HTTP_HOST=0.0.0.0:8000, docker-compose —8000, а в k8s (Helm) —8080. Локально сервис слушает 8000, в кластере — 8080. BUILD_ARGSпередаётCI_COMMIT_SHORT_SHA, ноDockerfileне объявляет соответствующийARG— build-arg игнорируется.POSTGRES_SSL_USEв Helm задаётся то как1, то какtrue(preprod). cleanenv корректно парсит обе формы, но единообразия нет.
Минимальный набор для локального запуска
Для запуска сервера локально (например, БД поднята через make container-run-deps или docker-compose) достаточно:
# БД
POSTGRES_ADDRESS=localhost
POSTGRES_PORT=5432
POSTGRES_DB=processing_db
POSTGRES_USER=processing
POSTGRES_PASSWORD=processing
POSTGRES_SSL_USE=false
# HTTP
HTTP_HOST=0.0.0.0:8000
# Обязательно: PEM публичный ключ (PKIX) для проверки JWT
PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
# Трейсинг можно выключить
TRACER_USE=false
Минимальный сценарий:
- Поднять PostgreSQL:
make container-run-deps(илиdocker-compose up database). - Экспортировать переменные выше (особенно валидный
PUBLIC_KEY, иначеpanic). - Прогнать миграции и запустить сервер:
go run ./cmd/httpserver migrate(аргументmigrateвключает миграции), либоairдля hot-reload. - Проверить:
GET http://localhost:8000/ping→{"status":"ready"}.
Через
docker-compose upсервис поднимается на:8000, БД —processing/processing/processing_db, ноPUBLIC_KEYв compose не задан — для полноценной работы API его нужно добавить.