20 KiB
Конфигурация sarex-subscriptions (api + cron-задачи)
Документ описывает все переменные окружения и способы конфигурирования сервиса sarex-subscriptions — Django-приложения рассылки уведомлений (email/Telegram) по подпискам.
Компоненты сервиса используют один и тот же модуль настроек config.settings.production и общий набор переменных окружения:
- api — HTTP-сервис (uwsgi,
config.wsgi:application), REST API подписок/получателей/шаблонов; отдаёт статику и медиа через S3; - cron
run_notifications(subscription-periodic) — периодическая рассылка отложенных уведомлений; - cron
run_immediately_notifications(subscription-immediately) — рассылка немедленных уведомлений.
Обе cron-задачи — это management-команды Django (server/apps/notification/management/commands), запускаемые как отдельные CronJob из того же образа.
Способы конфигурирования
Сервис настраивается через переменные окружения (os.getenv в config/settings/base.py и config/settings/production.py) плюс жёстко заданные в коде настройки. Отдельной библиотеки разбора конфига (как cleanenv в Go-сервисах) здесь нет — используется штатный механизм Django settings.
Часть настроек захардкожена в base.py и не выносится в окружение: SECRET_KEY, DEBUG, ALLOWED_HOSTS, CORS_*, REST Framework, локаль/таймзона (ru-ru, Europe/Moscow). В production.py DEBUG=False и заданы фиксированные ALLOWED_HOSTS/CORS_ALLOWED_ORIGINS.
Обязательные переменные не помечены тегами (как в Go), но при их отсутствии процесс падает при старте (подключение к БД) либо при обращении к соответствующему сервису (клиенты system-log/user-service, хранилище S3).
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
|---|---|
| Локально (docker-compose) | docker-compose.yml поднимает контейнер db (postgis/postgis) и сервисы api/migrations. Значения БД (DATABASE_USER/PASSWORD/NAME, ALLOWED_HOST_EMAIL) подставляются из окружения/файла .env рядом с compose. api собирается из compose/server/Dockerfile и стартует через entrypoint.sh |
| Kubernetes — собственный Helm-чарт репозитория | .helm/values.yaml: зависимость от universal-chart. Блоки services.api.envs (обычные значения, per-env _default/stage/preprod/production) и services.api.secretEnvs (из k8s-секретов). Плюс cronjobs.periodic / cronjobs.immediately — шаблоны CronJob в .helm/templates/, наследующие envs/secretEnvs api |
Kubernetes — этот infra-репозиторий (iac/apps/subscriptions) |
base/ — kustomize-манифесты с инъекцией секретов через HashiCorp Vault (annotations vault.hashicorp.com/*), обычные переменные заданы инлайн в env:. Оверлеи: yc-k8s-test (base + postgresql), brusnika-stage / brusnika-prod (Flux HelmRelease на universal-chart, блоки envs/secretEnvs) |
| CI/CD (GitLab) | .gitlab-ci.yml подключает шаблоны generic/common-ci (universal-pipeline.yaml, ref apps-business); в workflow.rules задаются переменные пайплайна (SERVICE_NAME, STAND, NAMESPACE, RELEASE_NAME, CHART_NAME, CHART_VERSION, K8S_HUSTLER_BRANCH, HELM_SET_ARGS, IMAGE_NAME и т.п.) |
Миграции БД (api). Выполняются в entrypoint контейнера api перед стартом uwsgi: python manage.py migrate --settings=config.settings.production (compose/server/entrypoint.sh). Cron-задачи миграций не выполняют. Локально в docker-compose.yml отдельный сервис migrations вызывает makemigrations (генерация миграций, не применение).
api (sarex-subscriptions)
Переменные читаются в config/settings/base.py (S3, OTEL) и config/settings/production.py (БД и внешние сервисы; production.py импортирует всё из base.py).
База данных (PostgreSQL / PostGIS)
Движок — core.db.backends.postgis (GeoDjango, требуется PostGIS). Все пять переменных обязательны — без них подключение к БД не поднимется.
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
|---|---|---|---|---|
DATABASE_HOST |
string | да | — | Хост PostgreSQL |
DATABASE_PORT |
string | да | — | Порт PostgreSQL |
DATABASE_NAME |
string | да | — | Имя базы данных |
DATABASE_USER |
string | да | — | Пользователь БД |
DATABASE_PASSWORD |
string | да | — | Пароль пользователя БД |
Хранилище S3 (static + media)
STATICFILES_STORAGE и DEFAULT_FILE_STORAGE = storages.backends.s3boto3.S3Boto3Storage, AWS_DEFAULT_ACL="public-read". Значения по умолчанию отсутствуют (os.getenv без default → None), поэтому для корректной отдачи статики/медиа креды фактически обязательны.
| Переменная | Тип | Обяз. | Назначение |
|---|---|---|---|
YC_S3_ACCESS_KEY_ID |
string | да | Access key (AWS_ACCESS_KEY_ID) |
YC_S3_SECRET_ACCESS_KEY |
string | да | Secret key (AWS_SECRET_ACCESS_KEY) |
YC_S3_BUCKET_NAME |
string | да | Имя бакета (AWS_STORAGE_BUCKET_NAME) |
YC_S3_ENDPOINT_URL |
string | да | Endpoint S3 (AWS_S3_ENDPOINT_URL) |
Трейсинг (OpenTelemetry)
Блок OTEL в base.py (и обёртка WSGI в wsgi.py) включается по os.getenv('USE_OTEL', False). Важно: проверяется истинность строки, а не её значение — любая непустая строка (в т.ч. "False", "0") включает трейсинг. Задействует пакет django_otel_tools.
| Переменная | Тип | По умолчанию | Назначение |
|---|---|---|---|
USE_OTEL |
bool-строка | не задана (выкл.) | Включает OTEL-трейсинг, otel-логгер и OtelMiddleware |
SERVICE_NAME |
string | subscriptions |
Имя сервиса в трейсах |
TRACER_ENDPOINT |
string | localhost:4375 |
Адрес OTLP-коллектора |
USE_INSECURE |
bool-строка | не задана (выкл.) | Небезопасное (без TLS) подключение к коллектору; та же логика истинности строки, что и USE_OTEL |
Захардкожено (не через окружение):
SECRET_KEY,DEBUG(Falseв production),ALLOWED_HOSTS,CORS_ALLOWED_ORIGINS,CORS_ALLOW_ALL_ORIGINS=True.
cron-задачи (run_notifications, run_immediately_notifications)
Обе команды используют тот же модуль настроек и, помимо БД, обращаются к внешним сервисам для сбора данных и рассылки. Переменные читаются в production.py и потребляются в server/apps/notification/management/commands/*.py.
Внешние сервисы и рассылка
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
|---|---|---|---|---|
SYSTEM_LOG_HOST |
string | да | — | Базовый URL сервиса system-log (логирование событий) |
USER_SERVICE_HOST |
string | да | — | Базовый URL сервиса пользователей (Django/ЛК) |
USER_SERVICE_LOGIN |
string | нет | "" |
Логин для авторизации в user-service |
USER_SERVICE_PASSWORD |
string | нет | "" |
Пароль для авторизации в user-service |
ALLOWED_HOST_EMAIL |
string | нет | https://lk.sarex.io |
Базовый URL для формирования ссылок в письмах (context_processing/document.py) |
Email — Mailgun
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
|---|---|---|---|---|
IS_MAILGUN_USE |
bool-строка | нет | True |
Использовать Mailgun для отправки писем |
MAILGUN_API_KEY |
string | нет | "" |
API-ключ Mailgun |
MAILGUN_BASE_URL |
string | нет | https://api.mailgun.net/v3/mg.sarex.io |
Базовый URL Mailgun API |
MAILGUN_EMAIL_FROM |
string | нет | hello@sarex.io |
Адрес отправителя |
Email — SMTP
SMTP-ветка активируется, только если заданы оба SMTP_EMAIL_HOST и SMTP_EMAIL_PORT (по умолчанию None — SMTP отключён).
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
|---|---|---|---|---|
SMTP_EMAIL_HOST |
string | нет | None |
Хост SMTP-сервера |
SMTP_EMAIL_PORT |
string | нет | None |
Порт SMTP-сервера |
SMTP_EMAIL_FROM |
string | нет | hello@sarex.io |
Адрес отправителя |
Telegram
| Переменная | Тип | Обяз. | По умолчанию | Назначение |
|---|---|---|---|---|
IS_USE_TELEGRAM |
bool-строка | нет | True |
Использовать Telegram-рассылку |
TELEGRAM_BOT_TOKEN |
string | нет | "" |
Токен Telegram-бота (settings.TELEGRAM_BOT_TOKEN) |
Значения
IS_*читаются как строки Django-настроек: непустая строка истинна. Чтобы выключить канал, инфраструктурные манифесты задают"false"/"0"— но с точки зрения Python это тоже непустые строки, поэтому фактическое поведение зависит от того, как значение интерпретируется в коде команды (см. замечания).
Инфраструктурные и вспомогательные переменные
Не читаются кодом приложения, но участвуют в запуске/сборке/деплое.
| Переменная | Где используется | Назначение |
|---|---|---|
API_ADDRESS |
base/*.yaml, .helm/values.yaml, brusnika-оверлеи |
Задаётся в манифестах, но кодом не читается — порт uwsgi фиксирован в uwsgi.ini (http = 0.0.0.0:8000) |
DJANGO_SETTINGS_MODULE |
entrypoint.sh, wsgi.py, manage.py |
Модуль настроек Django (config.settings.production в проде) |
NEXUS_USERNAME, NEXUS_PASSWORD |
compose/server/Dockerfile (build-arg), .gitlab-ci.yml |
Доступ к приватному PyPI (nexus.infra.sarex.io) при сборке образа |
SERVICE_NAME, DOCKERFILE_PATH, BUILD_ARGS, CI_TRIGGER_SOURCE |
.gitlab-ci.yml (variables) |
Параметры сборки/пайплайна |
STAND, NAMESPACE, RELEASE_NAME, CHART_NAME, CHART_VERSION, K8S_HUSTLER_BRANCH, HELM_SET_ARGS, IMAGE_NAME, ENABLE_BUILD_IMAGE |
.gitlab-ci.yml (workflow.rules) |
Параметры пайплайна generic/common-ci (деплой по окружениям stage/preprod/production) |
Обратите внимание:
SERVICE_NAMEвстречается в двух ролях — как переменная приложения (имя сервиса в OTEL-трейсах) и как переменная CI (имя сервиса для сборки/чарта). Значения задаются в разных местах и не связаны между собой.
Деплой из этого репозитория (iac/apps/subscriptions)
Здесь используется kustomize (не собственный Helm-чарт сервиса). Секреты БД и S3 инъектируются агентом Vault и подгружаются в окружение процесса до старта:
set -a
[ -f /vault/secrets/subscriptions-postgresql ] && . /vault/secrets/subscriptions-postgresql
[ -f /vault/secrets/subscriptions-minio ] && . /vault/secrets/subscriptions-minio
set +a
exec /server/entrypoint.sh
base/
backend-deployment.yaml— обычные переменные инлайн вenv:(API_ADDRESS,SYSTEM_LOG_HOST,USER_SERVICE_HOST,IS_USE_TELEGRAM=false,IS_MAILGUN_USE=0,SMTP_EMAIL_FROM/HOST/PORT). Vault-шаблоны формируютDATABASE_HOST/PORT/NAME/USER/PASSWORD(изsecrets/data/postgresql/apps/subscriptions, БДsubscriptions_db) иYC_S3_ACCESS_KEY_ID/SECRET_ACCESS_KEY/BUCKET_NAME/ENDPOINT_URL(изsecrets/data/minio/apps/subscriptions).backend-service.yaml,namespace.yaml(istio-injection: enabled),serviceaccount.yaml(subscriptions-vault).kustomization.yamlсобирает namespace, serviceaccount, deployment и service.
Оверлеи
yc-k8s-test—../base+postgresql.yaml(HelmReleasepostgresql-contour: создаёт БДsubscriptions_db, пользователяsubscriptions, расширенияltree/pg_stat_statements/postgis/timescaledb, восстановление из дампа).brusnika-stage/brusnika-prod— FluxHelmReleaseнаuniversal-chart(v0.1.7). Переменные — вenvs(DATABASE_HOST/PORT/NAME,API_ADDRESS,SYSTEM_LOG_HOST,USER_SERVICE_HOST,IS_USE_TELEGRAM=false,IS_MAILGUN_USE=0,SMTP_*), секреты — вsecretEnvs(postgres-secret:username/password;yc-s3-secret:key_id/access_key/storage_bucket_name/endpoint_url). Отличаются толькоDATABASE_HOST(postgres-serviceв prod vs192.168.2.45в stage).
В этих kustomize/brusnika-манифестах не задаются
USE_OTEL,TELEGRAM_BOT_TOKEN,MAILGUN_API_KEY,USER_SERVICE_LOGIN/PASSWORD,ALLOWED_HOST_EMAIL— используются дефолты из кода. Telegram и Mailgun выключены (IS_USE_TELEGRAM=false,IS_MAILGUN_USE=0), рассылка идёт по SMTP.
Отличия от Helm-чарта репозитория (.helm/values.yaml)
Собственный чарт сервиса (.helm/) — это другой путь деплоя, с более широким набором переменных, чем kustomize/brusnika здесь:
- дополнительно задаёт
ALLOWED_HOST_EMAIL,USE_OTEL=True,SERVICE_NAME,TRACER_ENDPOINT,USE_INSECURE=True(per-env), а также секретыMAILGUN_API_KEY(mailgun-cred) иTELEGRAM_BOT_TOKEN(telegram-bot-secret); IS_USE_TELEGRAM=true, монтируетuwsgi.iniчерез ConfigMap;- определяет
CronJobsubscription-periodic(0,30 * * * *,run_notifications) иsubscription-immediately(* * * * *,run_immediately_notifications), наследующиеenvs/secretEnvsapi.
Замечания и потенциальные проблемы
manage.pyуказывает на несуществующий модуль настроек. По умолчаниюmanage.pyзадаётDJANGO_SETTINGS_MODULE=config.settings.local, но модуляlocal.pyв репозитории нет (есть толькоbase.pyиproduction.py). Поэтому management-команды нужно запускать с явным--settings=config.settings.production(как это и делают entrypoint и cron-задачи). Локальный сервисmigrationsвdocker-compose.ymlвызываетmakemigrationsбез--settings— команда упадёт из-за отсутствияlocal.USE_OTEL/USE_INSECUREработают по истинности строки.os.getenv('USE_OTEL', False)возвращает строку; любое непустое значение (включая"False","0") включает трейсинг. Чтобы выключить — переменную нужно не задавать вовсе, а не ставитьFalse.- Каналы рассылки
IS_MAILGUN_USE/IS_USE_TELEGRAM— тоже строки. Значения по умолчанию —True(Python-объект), но из окружения приходит строка; поведение зависит от того, как значение проверяется в коде команды. При настройке важно учитывать это (в манифестах используют"false"/"0"). - S3 обязателен для статики/медиа. Хранилища заданы как S3 без файлового фолбэка; при отсутствии
YC_S3_*operations со статикой/медиа будут падать, хотя сам процесс поднимется. SECRET_KEYзахардкожен вbase.pyи не выносится в окружение — для продакшена это стоит вынести в секрет.- Расхождения имён БД между окружениями: infra
baseи postgresql-чарт используютsubscriptions_db, brusnika-оверлеи —subscriptions. При подключении важно использовать значение конкретного окружения. - Два деплой-пути расходятся по набору переменных (kustomize/brusnika vs
.helm): OTEL, Telegram-токен, Mailgun-ключ иALLOWED_HOST_EMAILприсутствуют только в.helm. Это стоит учитывать при переносе окружения.
Минимальный набор для запуска
api (uwsgi, миграции при старте):
DATABASE_HOST,DATABASE_PORT,DATABASE_NAME,DATABASE_USER,DATABASE_PASSWORDYC_S3_ACCESS_KEY_ID,YC_S3_SECRET_ACCESS_KEY,YC_S3_BUCKET_NAME,YC_S3_ENDPOINT_URL- при необходимости —
USE_OTEL(+SERVICE_NAME,TRACER_ENDPOINT,USE_INSECURE)
cron run_notifications / run_immediately_notifications:
- блок БД (как у api)
SYSTEM_LOG_HOST,USER_SERVICE_HOST(+USER_SERVICE_LOGIN,USER_SERVICE_PASSWORDпри авторизации)- канал рассылки:
IS_MAILGUN_USE+MAILGUN_API_KEYилиSMTP_EMAIL_HOST+SMTP_EMAIL_PORT; при Telegram —IS_USE_TELEGRAM+TELEGRAM_BOT_TOKEN - при необходимости —
ALLOWED_HOST_EMAIL(ссылки в письмах)
См. пример значений в .env.example рядом с этим файлом.