7.0 KiB
🏭 Инфраструктура
Docker Compose (локальная разработка)
Сервисы
services:
backend: # Spring Boot (Java 17), порт 8080
frontend: # Apache httpd:alpine, порт 80
db: # PostgreSQL alpine3.23, порт 5432
Сеть
Все сервисы работают в Docker-сети proxy (external). Перед первым запуском:
docker network create proxy
Переменные окружения
Файл .env в корне проекта:
POSTGRES_USER=myuser
POSTGRES_PASSWORD=replace-with-local-password
POSTGRES_DB=app_db
JWT_SECRET=replace-with-random-jwt-secret-minimum-32-bytes
JWT_ACCESS_TOKEN_TTL=15m
JWT_REFRESH_TOKEN_TTL=7d
POSTGRES_PASSWORD обязателен для docker compose up: пароль не хранится в compose.yaml. JWT_SECRET должен быть случайным секретом длиной минимум 32 байта. В продакшене секреты задаются через Kubernetes Secret, а не через коммитимые файлы.
Встроенного JWT fallback в приложении нет. Отсутствующее, короткое или шаблонное значение
останавливает запуск; профиль production также требует Secure refresh-cookie.
Локальный backend/tenants.json тоже не коммитится. Для ручного запуска backend вне Docker можно взять backend/tenants.example.json, создать рядом tenants.json и подставить локальный пароль.
Dockerfile (Backend)
Backend собирается через multi-stage сборку Maven:
- Этап сборки:
maven:3.9-eclipse-temurin-17→mvn package - Этап запуска:
eclipse-temurin:17-jre-alpine→java -jar app.jar
Dockerfile (Frontend)
FROM httpd:alpine
COPY . /usr/local/apache2/htdocs/
RUN chown -R www-data:www-data /usr/local/apache2/htdocs/
Kubernetes (продакшн)
Расположение конфигурации
Файлы Kubernetes манифестов: ../k8s/
Ключевые ресурсы
| Ресурс | Тип | Описание |
|---|---|---|
backend |
Deployment | Spring Boot приложение |
frontend |
Deployment | Apache httpd |
tenants-secret |
Внешний Secret | JSON-список tenant-подключений; значения отсутствуют в манифестах |
JWT настройки
app-config задаёт TTL access/refresh-токенов и признак Secure-cookie:
JWT_ACCESS_TOKEN_TTL=15mJWT_REFRESH_TOKEN_TTL=7dJWT_REFRESH_COOKIE_SECURE=true
app-secret задаёт JWT_SECRET. Этот Secret не создаётся файлами ../k8s/: его заранее
предоставляет внешний secret manager или оператор. Deployment явно включает профиль
production, поэтому небезопасная cookie-конфигурация останавливает startup.
Secrets для приложения и тенантов
Обязательные внешние объекты:
| Secret | Назначение |
|---|---|
app-secret |
JWT и fallback credentials backend |
tenants-secret |
Полный tenants.json с credentials tenant-БД |
otel-postgres-secret |
Credentials PostgreSQL receivers для OTel Collector |
gitea-registry |
Доступ Kubernetes к registry |
Secret tenants-secret монтируется в pod backend по пути /config/tenants.json.
При добавлении тенанта через API:
DatabaseControllerобновляет in-memory DataSourceKubernetesTenantSecretUpdaterобновляет Secret через Kubernetes APITenantConfigWatcherна остальных pod подхватывает смонтированное изменение (каждые 30 сек)
Kubernetes-клиент доверяет только service-account CA и проверяет hostname API server.
RBAC ограничен объектом tenants-secret. Скрипт ../k8s/deploy.sh проверяет наличие
объектов и ключей до rollout, не читая и не печатая их значения.
Создание, ротация, отзыв скомпрометированных значений и очистка истории описаны в
SECURITY_RUNBOOK.md. Эти действия требуют полномочий оператора и
не выполняются автоматически.
Обновление backend
kubectl rollout restart deployment backend -n magistr
Caddy (реверс-прокси)
Расположение: ../caddy-proxy/ для локальной разработки, в продакшене - отдельный сервис
В продакшене Caddy обрабатывает входящий трафик для *.zuev.company:
- Автоматическое получение TLS-сертификатов (Let's Encrypt)
- Маршрутизация
/api/*→ backend:8080 - Маршрутизация статики → frontend:80
CI/CD (Gitea Actions)
Пайплайн сборки Docker-образов
Расположение: .gitea/workflows/docker-build.yaml
Основные шаги:
- Checkout кода
- Login в Docker Registry
- Build + Push образов (
backend,frontend) - Генерация меток через
docker/metadata-action
Мониторинг (SigNoz + OpenTelemetry)
Архитектура мониторинга
graph LR
Backend["Spring Boot"] -->|OTLP gRPC| Collector["OTel Collector"]
Frontend["JS (otel.js)"] -->|OTLP HTTP| Collector
Collector --> SigNoz["SigNoz"]
Collector -->|"Метрики PostgreSQL"| PgExporter["pg_exporter"]
Интеграция Backend
Backend отправляет через OpenTelemetry:
- Логи — через Logback + OTLP exporter
- Трейсы — автоинструментация Spring Boot
- Метрики — JVM метрики, HTTP метрики
Tenant ID добавляется в:
- MDC (логи):
MDC.put("tenant.id", tenant) - Span атрибуты:
Span.current().setAttribute("tenant.id", tenant)
Интеграция Frontend
Файл admin/js/otel.js — клиентская телеметрия:
- Метрики производительности страниц
- Трейсы пользовательских действий
PostgreSQL receivers collector получают endpoint и credentials только из
otel-postgres-secret; ConfigMap collector содержит лишь ${env:...} ссылки.
Дашборды SigNoz
- JVM Dashboard (Heap, GC, Threads)
- PostgreSQL Dashboard (Connections, Queries)
- HTTP Dashboard (Requests, Latency, Errors)