# Конфигурация проекта bim-backend-v2 Документ описывает все переменные окружения и способы конфигурирования сервиса. ## Способы конфигурирования Сервис настраивается **только через переменные окружения**. Разбор выполняется в `config/config.go` (функция `NewConfig`) через библиотеку [`kelseyhightower/envconfig`](https://github.com/kelseyhightower/envconfig) (структура `Config`). Особенности разбора: - **Префикса нет** — `envconfig.Process("", &cfg)` вызывается с пустым префиксом, поэтому имена переменных задаются как есть (напр. `POSTGRES_ADDRESS`, `API_ADDRESS`). Имя переменной определяется тегом `envconfig:"..."` у каждого поля. - Типы приводятся автоматически по типу поля Go (`string`, `int`, `bool`, `uint64`). Для `bool` подходят `1`/`0`/`true`/`false`. - Ошибка разбора приводит к `panic` при старте (в `NewConfig` `envconfig.Process` завёрнут в `sync.Once`, ошибка не возвращается, а паникует). - Отсутствующая переменная не является ошибкой — поле получает нулевое значение соответствующего типа (пустая строка, `0`, `false`). Обязательность полей не проверяется. В отличие от python-сервисов, приложение **загружает `.env` автоматически**: в `cmd/httpserver/main.go` вызывается `godotenv.Load(".env")` (если файла нет — печатается предупреждение и используются переменные окружения процесса). Отдельного конфиг-файла (yaml/toml) у приложения нет. Источники переменных по способам запуска: | Способ запуска | Откуда берутся переменные | | --- | --- | | Локально (бинарник) | Файл `.env` в рабочем каталоге (`godotenv.Load`) либо переменные окружения процесса | | Локально (контейнеры) | `.docker/docker-compose.yml`: `env_file` → `.docker/.env` + `.docker/.docker.env` | | Kubernetes (Helm, репозиторий приложения) | `.helm/values-.yaml`: блоки `envs` (обычные значения) и `secrets` (из k8s-секретов); шаблон `.helm/templates/api.yaml` | | Kubernetes (IaC, этот репозиторий) | `iac/apps/bim/base/backend-deployment.yaml`: блок `env` и секреты из Vault (аннотации `vault.hashicorp.com/*`, шаблон `bim-postgresql`) | | CI/CD (GitLab) | `.gitlab-ci.yml`: подключение общих пайплайнов `generic/common-ci` и переменные `workflow.rules` по ветке/тегу | Способы запуска процессов: | Команда | Точка входа | Назначение | | --- | --- | --- | | `httpserver` (`make api` → `go install ./cmd/httpserver`) | `cmd/httpserver/main.go` | HTTP API. При старте применяет миграции (`appmigrations.RunOnStartup`), поднимает `net/http/pprof` на `:8081`, затем запускает API на `API_ADDRESS` | | `migrations` (`go install ./cmd/migrations`) | `cmd/migrations/main.go` | Отдельный запуск миграций БД | Порядок запуска в контейнере (`.docker/entrypoint.sh`): запускается `/go/bin/httpserver` (строка запуска миграций закомментирована — миграции выполняются самим приложением на старте). Финальный образ (`.docker/api.dockerfile`) — `scratch` со статически слинкованным бинарником `httpserver` и вшитым CA-сертификатом Postgres (`/root/yandex_pg.pem`). ## Переменные приложения Ниже перечислены все переменные, читаемые кодом (`config/config.go`). Префикса нет. Дефолт — это нулевое значение типа Go, если переменная не задана. ### App | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `APP_NAME` | string | `""` | Имя приложения (в коде помечено TODO — в deploy-envs не задаётся) | | `APP_VERSION` | string | `""` | Версия приложения (TODO — в deploy-envs не задаётся) | | `LOG_LEVEL` | string | `""` | Уровень логирования, передаётся в `logging.NewLogger` (TODO — в deploy-envs не задаётся) | | `API_ADDRESS` | string | `""` | Адрес прослушивания HTTP API в формате `host:port` (напр. `0.0.0.0:8080`) | | `TEST_ENV` | string | `""` | Служебное поле для тестов | ### PostgreSQL Сервис работает с **тремя** кластерами PostgreSQL (master, slave-1, slave-2). Выбор кластера для конкретного BIM выполняется по его id в `internal/app/http/httpserver.go` (сравнение с `LAST_MASTER_BIM*`/`LAST_SLAVE_1_BIM*`). Строка подключения собирается в `Config.GetPostgresConnectionURL` (`postgres://user:password@addr:port/db`, при `ENABLE_SSL=false` добавляется `?sslmode=disable`). Master-кластер: | Переменная | Тип | Назначение | | --- | --- | --- | | `POSTGRES_ADDRESS` | string | Хост PostgreSQL (master) | | `POSTGRES_PORT` | string | Порт PostgreSQL (master) | | `POSTGRES_USER` | string | Пользователь БД | | `POSTGRES_PASSWORD` | string | Пароль пользователя БД | | `POSTGRES_DB` | string | Имя базы данных | | `POSTGRES_POOL_SIZE` | int | Размер пула соединений | | `DB_CERT_PATH` | string | Путь к CA-сертификату PostgreSQL (используется при `ENABLE_SSL=1`) | Slave-1 кластер — те же поля с суффиксом `_2`: | Переменная | Тип | Назначение | | --- | --- | --- | | `POSTGRES_ADDRESS_2` | string | Хост PostgreSQL (slave-1) | | `POSTGRES_PORT_2` | string | Порт | | `POSTGRES_USER_2` | string | Пользователь | | `POSTGRES_PASSWORD_2` | string | Пароль | | `POSTGRES_DB_2` | string | База данных | | `POSTGRES_POOL_SIZE_2` | int | Размер пула | | `DB_CERT_PATH_2` | string | Путь к CA-сертификату | Slave-2 кластер — те же поля с суффиксом `_3`: | Переменная | Тип | Назначение | | --- | --- | --- | | `POSTGRES_ADDRESS_3` | string | Хост PostgreSQL (slave-2) | | `POSTGRES_PORT_3` | string | Порт | | `POSTGRES_USER_3` | string | Пользователь | | `POSTGRES_PASSWORD_3` | string | Пароль | | `POSTGRES_DB_3` | string | База данных | | `POSTGRES_POOL_SIZE_3` | int | Размер пула | | `DB_CERT_PATH_3` | string | Путь к CA-сертификату | ### Шардирование BIM по кластерам | Переменная | Тип | Назначение | | --- | --- | --- | | `LAST_MASTER_BIM` | uint64 | Верхняя граница id BIM для master-кластера (API v1) | | `LAST_MASTER_BIM_V3` | uint64 | Верхняя граница id BIM для master-кластера (API v2 / BIM v3) | | `LAST_SLAVE_1_BIM` | uint64 | Верхняя граница id BIM для slave-1 (API v1) | | `LAST_SLAVE_1_BIM_V3` | uint64 | Верхняя граница id BIM для slave-1 (API v2 / BIM v3) | ### Прочее | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `ENABLE_SSL` | bool | `false` | Подключение к PostgreSQL по TLS. При `false` в DSN добавляется `sslmode=disable` | | `ENABLE_SQL_QUERY` | bool | `false` | Логировать SQL-запросы | | `DJANGO_HOST` | string | `""` | Базовый URL Django-бэкенда для проверки прав администратора (см. `ENDPOINTS.md`) | | `INTEGRATION_TESTS` | bool | `false` | Режим интеграционных тестов. При `true` `CheckUserIsAdmin` всегда возвращает `true` | ## Переменные, не читаемые приложением (инфраструктура/сборка/тесты) Присутствуют в `.docker/.env`, `.docker/.docker.env`, `docker-compose.yml` или Helm, но `config/config.go` их не разбирает. | Переменная | Где используется | Назначение | | --- | --- | --- | | `API_PORT` | `.docker/.env` | Порт API для локального compose | | `POSTGRES_EXTERNAL_PORT`, `POSTGRES_EXTERNAL_PORT_2` | `docker-compose.yml` | Проброс портов контейнеров Postgres | | `POSTGRES_ADDRESS2` | `.docker/.docker.env` | Опечатка/легаси (нет суффикса `_`), кодом не читается | | `GRPC_ADDRESS`, `GRPC_PORT` | `.docker/.env` | Объявлены, но кодом не используются | | `TEST_BIM`, `JWT_TEST` | `.docker/.env`, `.docker/.docker.env` | Данные для интеграционных тестов | | `POSTGRES_*_4`, `DB_CERT_PATH_4` | `.helm/values-*.yaml`, IaC `backend-deployment.yaml` | Четвёртый кластер задаётся в деплое, но `config.go` доходит только до суффикса `_3` | | `LAST_SLAVE_2_BIM(_V3)`, `LAST_SLAVE_3_BIM(_V3)`, `LAST_SLAVE_4_BIM(_V3)` | `.helm/values-*.yaml` | Заданы в values, но кодом не читаются (актуальны только `LAST_MASTER_*` и `LAST_SLAVE_1_*`) | | `CI_COMMIT_SHORT_SHA` | `.gitlab-ci.yml` (build-arg) | Тег/версия сборки образа | ## Переменные из Helm-чарта приложения (`.helm/values-.yaml`) Обычные значения задаются в блоке `envs` для каждого окружения (`stage`/`preprod`/`production`) и содержат те же переменные `POSTGRES_*`, `API_ADDRESS`, `DJANGO_HOST`, `ENABLE_SSL`, `ENABLE_SQL_QUERY`, `LAST_*`, что описаны выше (различаются адресами БД, размерами пула, границами шардирования и доменом Django). Значения из секретов (блок `secrets`, монтируются как env через `secretKeyRef`): | Переменная | Секрет (`secret_name`) | Ключ (`secret_key`) | | --- | --- | --- | | `POSTGRES_USER` | `bim-v2-database-secret` | `username` | | `POSTGRES_PASSWORD` | `bim-v2-database-secret` | `password` | | `POSTGRES_USER_2` | `bim-v2-database-secret-2` | `username` | | `POSTGRES_PASSWORD_2` | `bim-v2-database-secret-2` | `password` | | `POSTGRES_USER_3` | `bim-v2-database-secret-3` | `username` | | `POSTGRES_PASSWORD_3` | `bim-v2-database-secret-3` | `password` | | `POSTGRES_USER_4` | `bim-v2-database-secret-3` | `username` | | `POSTGRES_PASSWORD_4` | `bim-v2-database-secret-3` | `password` | Ключевые не-env значения чарта: `api.name`, `api.image`, `api.version`, `api.port` (`8080`), `api.replicas`, `api.service_name`/`api.service_port` (`80`), `api.service_account`, `api.requests.memory`/`cpu`, `api.api_host`, `api.api_host_prefix` (`/bimv2/api/`), `api.api_path` (`/api/`), `api.internal_path` (`/internal/`), `api.permitted_ns` (namespace'ы, которым разрешён доступ к `/internal/*`), `imagePullSecrets`. Сетевой слой (`.helm/templates/mesh-config.yaml`, Istio): - `VirtualService` (при `api.virtual_service.enabled`) маршрутизирует `api_host_prefix` → `api_path`, задаёт CORS (`allowOrigins` — `*.sarex.io` и `localhost`, `allowHeaders` включают `Authorization`, `Content-Type`, `Identity`). - `AuthorizationPolicy` `routes-v2`: доступ к `/api/*` разрешён только от istio-ingressgateway при наличии claim `token_type=access`; доступ к `/internal/*` — только из namespace'ов `api.permitted_ns`. ## Переменные из IaC-репозитория (`iac/apps/bim/`) Деплой в этом репозитории (kustomize) устроен иначе, чем чарт приложения: - `base/backend-deployment.yaml` — Deployment `backend` в namespace `bim`, образ `bim-api`, `containerPort: 8000`, `API_ADDRESS=0.0.0.0:8000`, health-проба `GET /ping`. - Секреты PostgreSQL инъектируются **из Vault** (аннотации `vault.hashicorp.com/*`, роль `bim`, путь `secrets/data/postgresql/apps/bim`) в файл `/vault/secrets/bim-postgresql`, который экспортируется в окружение перед запуском (`set -a; . /vault/secrets/bim-postgresql; set +a; exec ./httpserver`). Шаблон Vault задаёт `POSTGRES_ADDRESS[_2../_4]`, `POSTGRES_PORT*`, `POSTGRES_DB*` (все указывают на `postgresql.bim.svc.cluster.local:5432`, БД `bim_db`) и `POSTGRES_USER*`/`POSTGRES_PASSWORD*` из Vault. - Прочие env заданы прямо в манифесте: `LAST_MASTER_BIM`, `LAST_MASTER_BIM_V3`, `LAST_SLAVE_1_BIM`, `POSTGRES_POOL_SIZE`, `DB_CERT_PATH_2/3/4`, `DJANGO_HOST` (`http://backend.django.svc.cluster.local:8000`), `ENABLE_SQL_QUERY=0`, `ENABLE_SSL=0`. - Оверлеи `brusnika-prod`, `brusnika-stage`, `yc-k8s-test` патчат base (реплики, образ, postgresql). ## Переменные в CI (`.gitlab-ci.yml`) Пайплайн подключает общие шаблоны `generic/common-ci` (`universal-pipeline-.yaml`, `common-security-scan.yaml`, `common-build.yaml`) и переключает окружение по ветке/тегу через `workflow.rules`: | Условие | STAND | Namespace | | --- | --- | --- | | ветка `master` | `preprod` | `bim-api-preprod` | | ветка `stage` | `stage` | `bim-api-stage` | | тег (`CI_COMMIT_TAG`) | `prod` | `bim-api-prod` | Общие переменные job'ов: `RELEASE_NAME=bim-backend-v2`, `CHART_NAME=bim-backend-v2`, `CHART_VERSION=0.0.1-`, `IMAGE_PATH=api.image`, `DOCKERFILE_PATH=.docker/api.dockerfile`, `HELM_SET_ARGS=--set api.image=${IMAGE_NAME}`, `BUILD_ARGS=--build-arg CI_COMMIT_SHORT_SHA=...`, флаги `ENABLE_BUILD_CHART`/`ENABLE_BUILD_IMAGE`/`ENABLE_STATE_UPDATE`/`ENABLE_DEPLOY=true`, `ENABLE_LINTER=false`. Стадии: `linter → test → unittest → prebuild-secscan → build → state-update → deploy`. ## Замечания и потенциальные проблемы - Переменные разбираются **без префикса** (`envconfig.Process("", ...)`) — имена совпадают с тегами `envconfig` полей структуры `Config`. - Обязательность полей не валидируется: отсутствующая переменная молча получает нулевое значение. Например пустой `API_ADDRESS` приведёт к попытке слушать на `":0"`. - В коде объявлены только три кластера (`POSTGRES_*`, `_2`, `_3`), тогда как в деплое присутствует и четвёртый (`_4`). Переменные `_4` и дополнительные `LAST_SLAVE_2/3/4_*` в окружении задаются, но приложением не используются. - Приложение загружает `.env` автоматически (`godotenv.Load(".env")`); при отсутствии файла ошибки нет — берутся переменные процесса. - В `NewConfig` ошибка `envconfig.Process` не возвращается, а вызывает `panic` (обёрнута в `sync.Once`). ## Минимальный набор для локального запуска Postgres поднимается через `docker-compose` (`.docker/docker-compose.yml`), приложение — через `make api` и запуск `httpserver`. Минимально необходимо задать (готовые примеры — в `.env.example`): - `API_ADDRESS` - Master-кластер: `POSTGRES_ADDRESS`, `POSTGRES_PORT`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, `POSTGRES_POOL_SIZE` - Slave-кластеры `_2` и `_3` (те же поля) — сервис создаёт соединения ко всем трём при старте - `ENABLE_SSL=0`, `DB_CERT_PATH*` (при `ENABLE_SSL=1`) - `DJANGO_HOST` - `LAST_MASTER_BIM`, `LAST_MASTER_BIM_V3`, `LAST_SLAVE_1_BIM`, `LAST_SLAVE_1_BIM_V3` - `INTEGRATION_TESTS=0`, `ENABLE_SQL_QUERY` по необходимости