баг-фикс завершён

This commit is contained in:
Zuev
2026-07-19 20:16:12 +03:00
parent bc0e1ab1b4
commit ee876f1acd
43 changed files with 1228 additions and 258 deletions

View File

@@ -7,16 +7,29 @@
```yaml
services:
backend: # Spring Boot (Java 17), внутренний порт 8080
frontend: # Apache httpd, публикует HTTP_PORT (по умолчанию 80)
frontend: # Apache httpd, внутренний порт 80
db: # PostgreSQL 16.3, внутренний порт 5432
```
### Сеть
Compose сам создаёт изолированную bridge-сеть `magistr`. Внешняя сеть или отдельно
установленный reverse proxy для локального запуска не нужны. Apache раздаёт frontend и
проксирует same-origin пути `/api` и `/actuator/health` в backend; backend и PostgreSQL не
публикуют порты на хосте.
Compose сам создаёт изолированную bridge-сеть `magistr` для приложения и подключает backend
с frontend к существующей внешней Docker-сети `proxy`. Caddy из `../сaddy-proxy/` также
подключён к `proxy`: на `localhost` он отправляет `/api/*` непосредственно в `backend:8080`,
а остальные пути — в `frontend:80`. Контейнеры Magistr не публикуют порты на хосте;
PostgreSQL доступен только во внутренней сети `magistr`.
Перед первым запуском создайте общую сеть и поднимите Caddy:
```bash
docker network inspect proxy >/dev/null 2>&1 || docker network create proxy
docker compose -f ../сaddy-proxy/compose.yaml up -d
docker compose up -d --build
```
Для `https://localhost` Caddy выпускает сертификат своим локальным CA. На CachyOS/Arch
корневой сертификат устанавливается в системное хранилище через `trust anchor`; точная
команда приведена в `STARTUP_GUIDE.md`.
Данные PostgreSQL сохраняются в именованном томе `postgres_data`. Обычный
`docker compose down` не удаляет их; явный `docker compose down -v` выполняет полный сброс.
@@ -39,8 +52,9 @@ LOGIN_RATE_BASE_BLOCK_DURATION=1m
LOGIN_RATE_MAX_BLOCK_DURATION=15m
LOGIN_AUDIT_RETENTION=90d
TRUSTED_PROXY_CIDRS=172.16.0.0/12
BUSINESS_TIME_ZONE=Europe/Moscow
TZ=Europe/Moscow
OTEL_SDK_DISABLED=true
HTTP_PORT=80
```
Начальный шаблон находится в `.env.example`: скопируйте его в игнорируемый Git файл `.env`
@@ -51,10 +65,15 @@ HTTP_PORT=80
согласованным. Все JWT TTL/cleanup-переменные и параметры защиты входа передаются
backend-контейнеру явно. `TRUSTED_PROXY_CIDRS` должен содержать только сеть фактического
reverse proxy: заголовок `X-Forwarded-For` от остальных источников backend игнорирует.
`BUSINESS_TIME_ZONE` задаёт правила календарных бизнес-дат, а `TZ` и
`JAVA_TOOL_OPTIONS=-Duser.timezone=...` фиксируют timezone JVM и контейнера. Абсолютные
timestamps при этом всегда передаются между Java и PostgreSQL в UTC.
Поскольку локальный Compose не запускает OpenTelemetry Collector, SDK по умолчанию отключён;
при подключённом Collector задайте `OTEL_SDK_DISABLED=false` и его OTLP endpoint.
В продакшене секреты задаются через Kubernetes Secret, а не через коммитимые файлы.
Kubernetes `app-config` также явно задаёт `BUSINESS_TIME_ZONE=Europe/Moscow`,
`TZ=Europe/Moscow` и `JAVA_TOOL_OPTIONS=-Duser.timezone=Europe/Moscow` для backend pod.
Встроенного JWT fallback в приложении нет. Отсутствующее, короткое или шаблонное значение
останавливает запуск; профиль `production` также требует Secure refresh-cookie.
@@ -64,10 +83,10 @@ reverse proxy: заголовок `X-Forwarded-For` от остальных ис
### Dockerfile (Backend)
Backend собирается через multi-stage сборку Maven:
1. Этап сборки: `maven:3.9-eclipse-temurin-17``mvn package`
1. Этап сборки: `maven:3.9.9-eclipse-temurin-17@sha256:f58d59b...``mvn package`
2. OpenTelemetry Java Agent `2.28.1` загружается как фиксированный Maven-артефакт и
проверяется по закреплённому SHA-256
3. Этап запуска: `eclipse-temurin:17-jre-alpine``java -jar app.jar`
3. Этап запуска: `eclipse-temurin:17-jre-alpine@sha256:02320dd4...``java -jar app.jar`
### Dockerfile (Frontend)
@@ -82,7 +101,8 @@ COPY security.conf /usr/local/apache2/conf/extra/magistr-security.conf
COPY proxy.conf /usr/local/apache2/conf/extra/magistr-proxy.conf
```
Оба базовых образа зафиксированы tag и manifest digest. Первый этап собирает зафиксированный
Все базовые образы backend/frontend и локальный PostgreSQL зафиксированы одновременно точным
tag и manifest digest. Первый этап frontend собирает зафиксированный
OpenTelemetry bundle; второй раздаёт только runtime-
файлы, без `node_modules`, тестов и build-исходников. Apache подключает `mod_headers`,
`mod_proxy` и `mod_proxy_http`; proxy сохраняет исходный `Host`, чтобы `localhost` корректно
@@ -340,16 +360,26 @@ Deployment-файлов запрещено.
Расположение: `.gitea/workflows/docker-build.yaml`
Основные шаги:
1. Backend unit/component tests, frontend static/unit tests, Compose validation и shell-тест
immutable rollout/rollback.
1. Backend unit/component tests, frontend static/unit tests, Compose validation, shell-тест
immutable rollout/rollback и регрессионная проверка закрепления артефактов.
2. Только после успешных gates — login, параллельная сборка и push backend/frontend с
SHA-tag и release tag без `latest`.
3. Build jobs публикуют digest обоих образов; deploy job устанавливает фиксированный
`kubectl v1.33.12` после SHA-256 проверки.
4. `scripts/deploy-images.sh` принимает только `image@sha256:...`, сохраняет предыдущие
SHA-tag и release tag без `latest`. Сторонние Actions закреплены полными commit SHA.
3. BuildKit публикует для обоих образов максимальную provenance- и SBOM-attestation. Build
jobs также возвращают registry digest каждого образа.
4. Отдельный обязательный job сканирует опубликованные digests закреплённым Trivy `0.63.0` и
блокирует deploy при исправимых `HIGH`/`CRITICAL` уязвимостях.
5. Deploy job устанавливает фиксированный `kubectl v1.33.12` только после SHA-256 проверки.
Java Agent также имеет точную версию и checksum.
6. `scripts/deploy-images.sh` принимает только `image@sha256:...`, сохраняет предыдущие
ссылки, применяет оба digest и ждёт rollout. При отказе автоматически возвращает оба
предыдущих образа и повторно проверяет их готовность.
5. Workflow-wide concurrency lock не допускает одновременные production deployment.
7. Workflow-wide concurrency lock не допускает одновременные production deployment.
`scripts/check-artifact-pinning.sh` проверяет Dockerfile, Compose, Actions, checksum и CI
gates. При передаче `K8S_DIR=../k8s` он дополнительно требует digest у каждого production
образа Kubernetes. Внешний `otel-collector.yaml` использует официальный Collector Contrib
`0.153.0@sha256:93aad750175cbf1a973ae1c5886c3371f4d800f61be25cdd26870b8441ffe9fa`;
версия и manifest digest обновляются только вместе и проверяются до rollout.
---