iac/apps/processing/workflows-api.CONFIGURATION.md

247 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Конфигурация проекта workflows-api
`workflows-api` — HTTP-сервис (Go 1.24, фреймворк [Fiber v2](https://github.com/gofiber/fiber)) для работы с workflow: создание, чтение, перезапуск задач, отмена запусков, приоритизация. Хранилище — PostgreSQL. Трейсинг — OpenTelemetry (через внешнюю библиотеку `gitlab.sarex.io/infra/golang-fiber-otel-tools`).
## Способы конфигурирования
Конфигурация читается **только из переменных окружения**. Используется библиотека [`github.com/ilyakaznacheev/cleanenv`](https://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)
1. Контейнер стартует с `ENTRYPOINT ["/httpserver", "migrate"]`.
2. `httpserver` видит аргумент `migrate` (`len(os.Args) > 1`) → открывает подключение к БД через `go-pg` (`gopg.GetPgConnectionWithoutConfig`, читает env заново) и прогоняет миграции из `cmd/migrations/migrationfiles`.
3. После миграций поднимается Fiber-приложение (`server.New` → `server.Run`), подключается пул `pgx` (`pgxconnection.GetPgConnection`), при `TRACER_USE=true` инициализируется трейсер/otel-логгер.
4. Сервер слушает адрес из `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 `_default` 100Mi / 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`.
## Замечания и потенциальные проблемы
1. **Две разные структуры конфигурации БД с разными дефолтами.** Сервер использует `pkg/postgres/pgxconnection.Postgres` (дефолты `POSTGRES_USER=sarex`, `POSTGRES_PASSWORD=sarex`), а миграции — `pkg/postgres/gopg.Postgres` (дефолты `processing`/`processing`). При запуске без явно заданных переменных сервер и миграции подключались бы под разными кредами. В production это не проявляется, т. к. все переменные приходят из секретов.
2. **`ENABLE_SQL_QUERY` не используется.** Поле читается в обе структуры (`EnableSQLQuery`), но нигде в коде не применяется — флаг «мёртвый».
3. **`OBSERVABILITY_TRACE_COLLECTOR_ENDPOINT`, `ENABLE_OBSERVABILITY` не используются.** Пакет `pkg/observavility` (с `SetupOTelSDK`) нигде не импортируется — это легаси. Реальный трейсинг настраивается переменными `TRACER_*` через внешнюю библиотеку `golang-fiber-otel-tools`.
4. **`POD_NAME`, `S3_SERVICE_ACCOUNT`, `DJANGO_HOST` из Helm кодом не читаются** — либо задел на будущее, либо устаревшие переменные.
5. **`entrypoint.sh` устарел и не используется.** Он ссылается на `/go/bin/migrations` и `/go/bin/httpserver`, тогда как в образе бинари лежат в `/httpserver` и `/migrations`, а `ENTRYPOINT` задан в `Dockerfile` напрямую (`/httpserver migrate`).
6. **Опечатка в mount-пути internal-middleware.** В `server.go` middleware, выставляющий `is_internal=true`, монтируется как `app.Use("./internal", ...)` (с ведущей точкой) вместо `"/internal"`. Из-за этого для маршрутов группы `/internal` флаг `is_internal` может не выставляться; в контроллерах `nil`-значение трактуется как «внутренний/доверенный запрос» (проверки принадлежности к компании пропускаются). Логически поведение сохраняется, но путь выглядит как баг.
7. **`PUBLIC_KEY` обязателен.** При пустом значении `auth.New` делает `panic("failed to parse PEM block ...")` — сервис не стартует. Дефолта нет.
8. **Расхождение по порту.** Дефолт кода `HTTP_HOST=0.0.0.0:8000`, docker-compose — `8000`, а в k8s (Helm) — `8080`. Локально сервис слушает 8000, в кластере — 8080.
9. **`BUILD_ARGS` передаёт `CI_COMMIT_SHORT_SHA`, но `Dockerfile` не объявляет соответствующий `ARG`** — build-arg игнорируется.
10. **`POSTGRES_SSL_USE` в Helm задаётся то как `1`, то как `true`** (preprod). cleanenv корректно парсит обе формы, но единообразия нет.
## Минимальный набор для локального запуска
Для запуска сервера локально (например, БД поднята через `make container-run-deps` или `docker-compose`) достаточно:
```env
# БД
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
```
Минимальный сценарий:
1. Поднять PostgreSQL: `make container-run-deps` (или `docker-compose up database`).
2. Экспортировать переменные выше (особенно валидный `PUBLIC_KEY`, иначе `panic`).
3. Прогнать миграции и запустить сервер: `go run ./cmd/httpserver migrate` (аргумент `migrate` включает миграции), либо `air` для hot-reload.
4. Проверить: `GET http://localhost:8000/ping``{"status":"ready"}`.
> Через `docker-compose up` сервис поднимается на `:8000`, БД — `processing/processing/processing_db`, но `PUBLIC_KEY` в compose не задан — для полноценной работы API его нужно добавить.