From e90dfe1bd4251c827b217ed7bcde7526eeef0c17 Mon Sep 17 00:00:00 2001 From: sova-bootstrap Date: Thu, 28 May 2026 12:09:28 +0300 Subject: [PATCH] chore: initial docs site for test contour --- .gitea/workflows/build.yml | 103 +++++ Dockerfile | 4 + nginx.conf | 14 + site/README.md | 22 ++ site/_sidebar.md | 4 + site/docs/argocd-apps.md | 81 ++++ site/docs/tags.md | 90 +++++ site/docs/test-contour-article.md | 634 ++++++++++++++++++++++++++++++ site/index.html | 25 ++ 9 files changed, 977 insertions(+) create mode 100644 .gitea/workflows/build.yml create mode 100644 Dockerfile create mode 100644 nginx.conf create mode 100644 site/README.md create mode 100644 site/_sidebar.md create mode 100644 site/docs/argocd-apps.md create mode 100644 site/docs/tags.md create mode 100644 site/docs/test-contour-article.md create mode 100644 site/index.html diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..2380d81 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,103 @@ +name: docs-ci-cd + +on: + push: + tags: + - 'docs-v*' + pull_request: + branches: [main] + +env: + REGISTRY: gitea-http.gitea.svc.cluster.local:3000 + IMAGE: gitea-http.gitea.svc.cluster.local:3000/sova/docs + IMAGE_DEPLOY: git.sova.local/sova/docs + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Validate site files + run: | + test -f site/index.html + test -f site/README.md + test -f site/docs/test-contour-article.md + + parse-tag: + if: startsWith(github.ref, 'refs/tags/docs-v') + runs-on: ubuntu-latest + outputs: + full_tag: ${{ steps.meta.outputs.full_tag }} + env: ${{ steps.meta.outputs.env }} + version: ${{ steps.meta.outputs.version }} + steps: + - name: Parse tag + id: meta + run: | + TAG="${GITHUB_REF#refs/tags/}" + echo "full_tag=$TAG" >> "$GITHUB_OUTPUT" + echo "env=$(echo "$TAG" | sed -E 's/docs-v([0-9.]+)-([a-z]+)/\2/')" >> "$GITHUB_OUTPUT" + echo "version=$(echo "$TAG" | sed -E 's/docs-v([0-9.]+).*/\1/')" >> "$GITHUB_OUTPUT" + + build-and-push: + needs: [test, parse-tag] + if: startsWith(github.ref, 'refs/tags/docs-v') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Docker login + env: + REGISTRY_USER: ${{ secrets.REGISTRY_USER }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} + run: | + echo "${REGISTRY_PASSWORD}" | docker login "$REGISTRY" -u "${REGISTRY_USER}" --password-stdin + - name: Build and push + run: | + TAG="${{ needs.parse-tag.outputs.full_tag }}" + docker build -f Dockerfile -t "$IMAGE:${TAG}" -t "$IMAGE:${{ needs.parse-tag.outputs.version }}" . + docker push "$IMAGE:${TAG}" + docker push "$IMAGE:${{ needs.parse-tag.outputs.version }}" + + deploy-gitops: + needs: [build-and-push, parse-tag] + if: startsWith(github.ref, 'refs/tags/docs-v') + runs-on: ubuntu-latest + steps: + - name: Bump image tag in sova-deploy + env: + DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} + DEPLOY_USER: ${{ secrets.REGISTRY_USER }} + run: | + REPO_URL="http://${DEPLOY_USER}:${DEPLOY_TOKEN}@gitea-http.gitea.svc.cluster.local:3000/sova/sova-deploy.git" + git clone "${REPO_URL}" + cd sova-deploy + ENV="${{ needs.parse-tag.outputs.env }}" + TAG="${{ needs.parse-tag.outputs.full_tag }}" + git config user.email "ci-bot@sova.local" + git config user.name "sova-ci" + MAX_RETRIES=5 + case "$(uname -m)" in + x86_64|amd64) YQ_ARCH=amd64 ;; + aarch64|arm64) YQ_ARCH=arm64 ;; + *) echo "Unsupported arch: $(uname -m)"; exit 1 ;; + esac + curl -sSL -o /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_${YQ_ARCH}" + chmod +x /usr/local/bin/yq + for attempt in $(seq 1 $MAX_RETRIES); do + git pull --rebase "${REPO_URL}" main + yq -i ".image.repository = \"${IMAGE_DEPLOY}\"" "apps/docs/values-${ENV}.yaml" + yq -i ".image.tag = \"${TAG}\"" "apps/docs/values-${ENV}.yaml" + yq -i ".image.pullPolicy = \"IfNotPresent\"" "apps/docs/values-${ENV}.yaml" + git add "apps/docs/values-${ENV}.yaml" + git diff --cached --quiet && { echo "No changes"; exit 0; } + git commit -m "chore(docs): bump ${ENV} to ${TAG}" + if git push "${REPO_URL}" main; then + echo "Push OK on attempt ${attempt}" + exit 0 + fi + echo "Push failed, retry ${attempt}/${MAX_RETRIES}..." + git reset --hard HEAD~1 + sleep $((attempt * 2)) + done + echo "Failed to push after ${MAX_RETRIES} attempts" + exit 1 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7b96fa3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:1.27-alpine +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY site/ /usr/share/nginx/html/ +EXPOSE 8080 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..18c6199 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,14 @@ +server { + listen 8080; + server_name _; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location ~* \.(md|html|css|js|json)$ { + add_header Cache-Control "no-cache"; + } +} diff --git a/site/README.md b/site/README.md new file mode 100644 index 0000000..a9215f6 --- /dev/null +++ b/site/README.md @@ -0,0 +1,22 @@ +# Документация test-контура Sova + +Статический сайт с инструкциями по песочнице `k3s-test`: развёртывание, CI/CD, GitOps и перенос на удалённый сервер. + +## Быстрые ссылки + +| URL | Сервис | +|-----|--------| +| http://docs.sova.local | эта документация | +| http://api.test.sova.local | backend API | +| http://admin.test.sova.local | admin panel | +| http://cabinet.test.sova.local | личный кабинет | +| http://argocd.sova.local | ArgoCD | +| http://git.sova.local | Gitea | + +## Разделы + +- [Test-контур k3s](docs/test-contour-article.md) — полная статья: архитектура, bootstrap, CI, troubleshooting +- [Система тегов](docs/tags.md) — формат тегов и release-скрипт +- [ArgoCD приложения](docs/argocd-apps.md) — зачем `sova-root` и `data-test`, почему «нельзя войти» + +Исходники: репозиторий `sova/docs` в Gitea, каталог `k3s-test/sova-docs/` локально. diff --git a/site/_sidebar.md b/site/_sidebar.md new file mode 100644 index 0000000..76e1139 --- /dev/null +++ b/site/_sidebar.md @@ -0,0 +1,4 @@ +* [Главная](/README.md) +* [Test-контур k3s](/docs/test-contour-article.md) +* [Система тегов CI/CD](/docs/tags.md) +* [ArgoCD: sova-root и data-test](/docs/argocd-apps.md) diff --git a/site/docs/argocd-apps.md b/site/docs/argocd-apps.md new file mode 100644 index 0000000..34dc2c9 --- /dev/null +++ b/site/docs/argocd-apps.md @@ -0,0 +1,81 @@ +# ArgoCD: sova-root, data-test и «почему нельзя войти» + +В UI ArgoCD видны приложения разных типов. Не у всех есть URL в браузере или смысл открывать Terminal «как в backend». + +## Сводная таблица + +| Application | Что деплоит | Namespace | Есть URL? | Terminal | +|-------------|-------------|-----------|-----------|----------| +| **sova-root** | другие `Application` CR (app-of-apps) | `argocd` | нет | нет pod'ов | +| **data-test** | PostgreSQL, MySQL, Redis (Helm Bitnami) | `sova-data-test` | нет | только в pod БД | +| **backend-test** | Symfony API | `sova-test` | api.test.sova.local | php-fpm | +| **adminpanel-test** | React admin | `sova-test` | admin.test.sova.local | nginx | +| **cabinet-test** | Symfony ЛК | `sova-test` | cabinet.test.sova.local | php-fpm | +| **docs-test** | документация (nginx) | `sova-test` | docs.sova.local | nginx | +| **mocks-test** | WireMock, Mailpit | `sova-mocks` | internal only | по pod | + +--- + +## sova-root — «корневое» GitOps-приложение + +**Назначение:** паттерн *app-of-apps*. Один `Application` следит за каталогом `sova-deploy/argocd/apps/` и создаёт/обновляет остальные Application-манифесты (`backend-test`, `data-test`, …). + +**Почему «нельзя войти»:** + +- Это **мета-приложение**. Оно не разворачивает Deployment, Service или Ingress. +- В дереве ресурсов — только объекты типа `Application` в namespace `argocd`. +- Нет веб-интерфейса, логина пользователя или pod'а для exec. + +**Как пользоваться:** смотрите дочерние приложения (`backend-test`, `docs-test`, …). `sova-root` нужен для автоматического подхвата новых Application при push в `sova-deploy`. + +```mermaid +flowchart TB + root["sova-root Application"] + apps["argocd/apps/*.yaml"] + be["backend-test"] + data["data-test"] + docs["docs-test"] + root --> apps + apps --> be & data & docs +``` + +--- + +## data-test — инфраструктура данных + +**Назначение:** Helm-чарт `sova-deploy/data/test` — PostgreSQL (backend + cabinet БД), MySQL Bitrix, Redis для test-контура. + +**Почему «нельзя войти»:** + +- Это **слой данных**, не пользовательское приложение. +- Нет Ingress и публичного hostname. +- «Войти» в ArgoCD UI можно только в смысле открыть карточку приложения — там StatefulSet/Deployment БД, а не сайт. + +**Как подключаться:** + +```bash +# PostgreSQL из другого pod в кластере +postgresql-test.sova-data-test.svc.cluster.local:5432 + +# Инициализация schema/seed — отдельный Job db-init (чарт data/db-init), не через браузер +kubectl get jobs -n sova-data-test +``` + +**Terminal:** технически можно `exec` в pod PostgreSQL/MySQL, но это для DBA/отладки, не «логин в приложение». + +**Sync degraded:** если в чарте `data/test` был лишний шаблон `db-init` с несуществующими values (`postgres.*` вместо `postgresql.*`), Application падал в ошибку. Инициализация БД выполняется **отдельным** чартом `data/db-init` через `deploy-test-stack.sh`. + +--- + +## Куда идти вместо этого + +| Задача | Куда | +|--------|------| +| API, миграции, cron | **backend-test** → Pod → container **php-fpm** → Terminal | +| Админка | **adminpanel-test** → http://admin.test.sova.local | +| Личный кабинет | **cabinet-test** → http://cabinet.test.sova.local | +| Документация | **docs-test** → http://docs.sova.local | +| Git, CI | http://git.sova.local | +| Метрики/логи | http://grafana.sova.local | + +Exec в ArgoCD включён в `platform/argocd/values-test.yaml` (`exec.enabled: true`). diff --git a/site/docs/tags.md b/site/docs/tags.md new file mode 100644 index 0000000..88e6410 --- /dev/null +++ b/site/docs/tags.md @@ -0,0 +1,90 @@ +# Система тегов CI/CD + +Каждое приложение в Gitea публикуется **отдельным репозиторием** и выпускается **своим тегом**. Тег запускает Gitea Actions: сборка Docker-образа → push в registry → обновление `values-{env}.yaml` в `sova-deploy`. + +## Формат тега + +``` +{component}-v{semver}-{env} +``` + +| Часть | Пример | Описание | +|-------|--------|----------| +| `component` | `backend`, `adminpanel`, `cabinet`, `docs` | имя сервиса | +| `semver` | `1.0.1` | версия образа | +| `env` | `test`, `stage` | контур (подставляется в `values-{env}.yaml`) | + +Примеры для test-контура: + +| Репозиторий Gitea | Тег | Helm values | +|-------------------|-----|-------------| +| `sova/backend` | `backend-v1.0.1-test` | `apps/backend/values-test.yaml` | +| `sova/adminpanel` | `adminpanel-v1.0.1-test` | `apps/adminpanel/values-test.yaml` | +| `sova/cabinet` | `cabinet-v1.0.1-test` | `apps/cabinet/values-test.yaml` | +| `sova/docs` | `docs-v1.0.1-test` | `apps/docs/values-test.yaml` | + +`sova-deploy` и `sova-mocks` **не** собираются по тегам — их меняют вручную или через bootstrap; ArgoCD подхватывает `main`. + +## Release-скрипт + +```bash +./scripts/release-test-tag.sh backend backend-v1.0.1-test +./scripts/release-test-tag.sh adminpanel adminpanel-v1.0.1-test +./scripts/release-test-tag.sh cabinet cabinet-v1.0.1-test +./scripts/release-test-tag.sh docs docs-v1.0.1-test +``` + +Скрипт создаёт аннотированный тег в локальном зеркале репозитория и пушит в Gitea. Workflow парсит суффикс `-test` и обновляет соответствующий `values-test.yaml`. + +## Pipeline (общая схема) + +```mermaid +flowchart LR + tag["git tag push"] --> test["job: test"] + test --> build["build-and-push"] + build --> registry["Gitea registry"] + build --> deploy["deploy-gitops"] + deploy --> deployRepo["sova-deploy main"] + deployRepo --> argocd["ArgoCD sync"] + argocd --> k8s["Pod rollout"] +``` + +## Секреты Actions (на репозиторий) + +Настраиваются `./scripts/bootstrap-gitea-ci-secrets.sh`: + +| Secret | Назначение | +|--------|------------| +| `REGISTRY_USER` / `REGISTRY_PASSWORD` | push образа в Gitea registry | +| `DEPLOY_TOKEN` | HTTPS push в `sova/sova-deploy` | +| `HOST_IP` | резерв для jobs с внешним доступом | + +Перед первым CI после bootstrap: + +```bash +./scripts/configure-k3s-registry.sh +./scripts/bootstrap-gitea-ci-secrets.sh +``` + +## Локальная сборка (без CI) + +```bash +./scripts/build-images.sh local-test # backend, adminpanel, cabinet, docs +./scripts/import-images-to-vm.sh local-test +``` + +Образы с тегом `local-test` и `pullPolicy: Never`/`IfNotPresent` — для первого деплоя до настройки registry. + +## Проверка + +```bash +# Workflow +open http://git.sova.local/sova/backend/actions + +# Образ в registry +curl -u gitea_admin:PASSWORD http://git.sova.local/v2/sova/backend/tags/list + +# ArgoCD +kubectl get applications -n argocd +kubectl get deploy -n sova-test +``` diff --git a/site/docs/test-contour-article.md b/site/docs/test-contour-article.md new file mode 100644 index 0000000..387c688 --- /dev/null +++ b/site/docs/test-contour-article.md @@ -0,0 +1,634 @@ +# Test-контур Sova на k3s: что сделано и как перенести на удалённый сервер + +Статья описывает изолированный test-контур в каталоге `k3s-test/`: архитектуру, порядок локального развёртывания и план переноса на реальный сервер. + +--- + +## Зачем это нужно + +Монорепозиторий Sova (`apps/backend`, `apps/cabinet`, `local/` и т.д.) не трогали. Вместо этого собран **отдельный контур** — песочница, где можно: + +- поднять backend, admin panel, БД и моки в Kubernetes; +- проверить GitOps (ArgoCD), CI (Gitea Actions), мониторинг (Prometheus/Grafana); +- накатывать **изолированные test-БД** (не `*_local`, а `*_test`) из тех же SQL, что и в `local/`; +- отрабатывать сценарии до выкладки на stage/production. + +Домены локально: `*.sova.local`. На удалённом сервере их заменят на реальные, например `*.test.sova.dev`. + +--- + +## Архитектура + +```mermaid +flowchart TB + subgraph dev["Mac (разработчик)"] + docker["Docker build"] + helm["Helm / kubectl"] + scripts["scripts/*.sh"] + end + + subgraph vm["VM sova-test (Multipass) / удалённый сервер"] + k3s["k3s single-node"] + ingress["ingress-nginx"] + end + + subgraph platform["Platform layer"] + argocd["ArgoCD"] + gitea["Gitea + Actions"] + prom["Prometheus"] + graf["Grafana"] + end + + subgraph apps["Application layer"] + be["backend nginx+php-fpm"] + ap["adminpanel nginx"] + mocks["WireMock + Mailpit"] + end + + subgraph data["Data layer (sova-data-test)"] + pg["PostgreSQL Bitnami"] + mysql["MySQL 8.0"] + redis["Redis"] + dbinit["Job db-init: schema → seed"] + end + + scripts --> helm + docker --> k3s + helm --> k3s + k3s --> ingress + ingress --> be & ap & argocd & gitea & graf & prom + argocd --> apps & data + gitea --> argocd + dbinit --> pg & mysql + be --> pg & redis & mysql + be --> mocks +``` + +### Структура репозитория `k3s-test/` + +| Каталог | Назначение | +|---------|------------| +| `sova-backend/` | Копия Symfony API + Dockerfile + workflow Gitea | +| `sova-adminpanel/` | Копия React admin + runtime `env.js` | +| `sova-cabinet/` | Копия Symfony ЛК + Dockerfile + workflow Gitea | +| `sova-docs/` | Документация (Docsify) + Dockerfile + workflow Gitea | +| `sova-deploy/` | Helm charts, ArgoCD manifests, SQL для test-БД | +| `sova-mocks/` | WireMock (MIS, Calltouch, Captcha) + Mailpit | +| `sova-platform/` | Terraform-модуль установки k3s на VM | +| `scripts/` | Bootstrap, сборка образов, деплой, smoke | + +--- + +## Что сделано в коде + +### Backend (`sova-backend`) + +- Вынесены URL интеграций в env: `WIDGET_API_URL`, `API_PUBLIC_URL`. +- Stub-режим внешних сервисов: SMS, Calltouch, SmartCaptcha (`INTEGRATIONS_STUB_MODE=true`). +- Production Dockerfile: PHP 8.4-FPM, multistage. +- JWT-ключи монтируются из Helm Secret (`sova-deploy/apps/backend/jwt/`). + +### Admin Panel (`sova-adminpanel`) + +- Runtime-конфиг `public/env.js` (API URL без пересборки). +- Dockerfile: Node build → nginx. +- ConfigMap + entrypoint для подстановки URL в k8s. + +### Базы данных + +SQL из монорепо (`local/postgres/init/`, `local/mysql-bitrix/init/`) **разделён на два этапа**: + +1. **Schema** — `sova-deploy/data/test/sql/*/schema/` +2. **Seed** — `sova-deploy/data/test/sql/*/seed/` + +Скрипт `scripts/prepare-db-init.py`: + +- переименовывает `*_local` → `*_test`; +- добавляет `\connect` в seed-файлы; +- заменяет `md5('...')` на литералы (PostgreSQL 18 не поддерживает `md5()` в INSERT). + +Job `db-init` (Helm chart `sova-deploy/data/db-init/`) выполняет: schema PostgreSQL → schema MySQL → seed PostgreSQL → seed MySQL. + +| База | Имя | Назначение | +|------|-----|------------| +| PostgreSQL | `sova_backend_test` | Backend API, admin auth | +| PostgreSQL | `sova_cabinet_test` | Личный кабинет (если подключается) | +| MySQL | `sova_bitrix_test` | Views/синк Bitrix | +| Redis | — | Кэш, messenger | + +MySQL поднят через простой manifest `mysql:8.0` (Bitnami chart давал ImagePullBackOff). Auth plugin: `mysql_native_password` для совместимости с клиентом в init Job. + +### GitOps (`sova-deploy`) + +- Helm: `apps/backend`, `apps/adminpanel`, `data/db-init`, `data/test`. +- ArgoCD Applications: backend, adminpanel, mocks, data-test. +- Репозитории в Gitea: `sova/backend`, `sova/adminpanel`, `sova/sova-deploy`, `sova/sova-mocks`. + +#### Backend: stateless console в ArgoCD + +Помимо Deployment (nginx + php-fpm), chart `apps/backend` создаёт **CronJob-ы с контейнером `console`** — Symfony-команды по расписанию. В ArgoCD они видны в дереве приложения `backend-test` как отдельные ресурсы с label `app.kubernetes.io/component: console`: + +| CronJob | Расписание (MSK) | Команда | +|---------|------------------|---------| +| `backend-clear-schedule-cache` | `0 */6 * * *` | `app:schedule:clear-cache` | +| `backend-sync-doctors` | `0 3 * * *` | `upload:doctors` | +| `backend-sync-reviews` | `30 3 * * *` | `bitrix-update-reviews` | + +Конфигурация — список `cronjobs` в `values.yaml`. Для test-контура Job миграций (`backend-migrate`) **отключён** (`migrate.enabled: false`), т.к. схема накатывается через `db-init`, а не `doctrine:migrations:migrate`. На stage/prod можно включить PreSync-migrate. + +Deployment использует initContainer `warmup-cache` и `emptyDir` для `/app/var/cache` и `/app/var/log` — иначе Symfony не может писать кэш в prod (HTTP 500). + +### Platform layer + +| Компонент | Namespace | Ingress | +|-----------|-----------|---------| +| ingress-nginx | `ingress` | LoadBalancer на IP VM | +| cert-manager | `cert-manager` | — | +| sealed-secrets | `kube-system` | — | +| ArgoCD | `argocd` | `argocd.sova.local` | +| Gitea | `gitea` | `git.sova.local` | +| kube-prometheus-stack | `monitoring` | `grafana.sova.local`, `prometheus.sova.local` | +| Loki + Promtail | `monitoring` | только внутри кластера (логи в Grafana) | + +**Метрики vs логи:** Prometheus собирает **метрики** (CPU, память, kube-state). **Логи подов** — через **Loki + Promtail** (Explore → Loki в Grafana). Без Loki в Grafana «логов нет» — это ожидаемо до `./scripts/deploy-monitoring-logs.sh`. + +```bash +# После deploy-platform или отдельно: +./scripts/deploy-monitoring-logs.sh + +# В Grafana Explore: +# datasource: Loki +# query: {namespace="sova-test", app="backend"} +``` + +**Важно для ArgoCD:** UI работает по HTTP только при: + +- `server.insecure=true` в `argocd-cmd-params-cm` (ключ `server.insecure`, не вложенный YAML); +- `url: http://argocd.sova.local` в `argocd-cm`; +- ingress без принудительного HTTPS. + +**Терминал в pod (exec):** по умолчанию в Argo CD выключен. В test-контуре включён через `sova-deploy/platform/argocd/values-test.yaml` (`exec.enabled: true` + RBAC). В UI: Application → backend-test → Pod → **⋮** → **Terminal** → контейнер **`php-fpm`**. + +Пример миграций из терминала ArgoCD или kubectl: + +```bash +php bin/console doctrine:migrations:migrate --no-interaction +php bin/console doctrine:migrations:status +``` + +Через kubectl (если UI недоступен): + +```bash +kubectl exec -n sova-test deploy/backend -c php-fpm -it -- sh +# внутри pod: +php bin/console doctrine:migrations:migrate --no-interaction +``` + +ArgoCD внутри кластера ходит в Gitea по **внутреннему URL**: +`http://gitea-http.gitea.svc.cluster.local:3000/sova/...` +(снаружи браузер использует `http://git.sova.local`). + +--- + +## Локальное развёртывание (Multipass) + +Требования: Docker, Multipass, Helm ≥ 3.14, kubectl, Terraform (опционально). + +### Полный цикл + +```bash +cd k3s-test + +# 1. Синхронизация кода из монорепо (если нужно обновить) +./scripts/sync-from-monorepo.sh + +# 2. VM + k3s (4 CPU, 8 GB RAM, 40 GB disk) +./scripts/bootstrap-multipass.sh local-test + +# 3. Platform: ingress, ArgoCD, Gitea, Prometheus/Grafana +./scripts/deploy-platform.sh + +# 4. Приложения, БД, моки +USE_MULTIPASS=1 ./scripts/deploy-test-stack.sh local-test + +# 5. Репозитории в Gitea + CI user +./scripts/bootstrap-gitea.sh + +# 6. Gitea Actions runner +./scripts/bootstrap-gitea-runner.sh + +# 7. ArgoCD applications + HTTP UI +./scripts/bootstrap-argocd.sh + +# 8. Логины и URL +./scripts/print-test-users.sh +./scripts/print-urls.sh +``` + +### /etc/hosts на Mac + +Подставьте IP из `multipass info sova-test`: + +``` +192.168.x.x api.test.sova.local admin.test.sova.local +192.168.x.x argocd.sova.local git.sova.local grafana.sova.local prometheus.sova.local +``` + +Kubeconfig: `~/.kube/sova-test-config`. + +### Альтернатива без Multipass (k3d) + +Для быстрой проверки на Mac без VM: + +```bash +./scripts/k3d-bootstrap.sh local-test +echo "127.0.0.1 api.test.sova.local admin.test.sova.local" | sudo tee -a /etc/hosts +./scripts/smoke-test.sh +``` + +Platform layer (Gitea, ArgoCD) в k3d-варианте поднимается по необходимости через `deploy-platform.sh`. + +--- + +## URL и тестовые пользователи + +| Сервис | URL | +|--------|-----| +| Backend API | http://api.test.sova.local | +| Admin Panel | http://admin.test.sova.local | +| Gitea | http://git.sova.local/sova/ | +| ArgoCD | http://argocd.sova.local | +| Grafana | http://grafana.sova.local | +| Prometheus | http://prometheus.sova.local | + +### Пользователи приложения (seed в БД) + +| Сценарий | Логин | Пароль | +|----------|-------|--------| +| Admin Panel + Backend JWT | `local.backend@example.test` | `local-password` | +| Cabinet (отдельная БД) | `local.cabinet@example.test` | `local-password` | +| Auth по pcode | uid `100001`, birthDate `19900101` | — | + +Проверка логина: + +```bash +curl -X POST http://api.test.sova.local/user/login \ + -H 'Content-Type: application/json' \ + -d '{"username":"local.backend@example.test","password":"local-password"}' +``` + +### Platform credentials + +После `bootstrap-gitea.sh` — файл `.generated/platform-credentials.env`: + +- Gitea admin: `gitea_admin` +- CI user: `sova-ci` +- ArgoCD: `admin` + пароль из `argocd-initial-admin-secret` + +Актуальные значения: `./scripts/print-test-users.sh`. + +--- + +## CI/CD (Gitea Actions) + +В репозиториях лежат workflow: + +- `sova-backend/.gitea/workflows/build.yml` +- `sova-adminpanel/.gitea/workflows/build.yml` + +Цепочка по тегу `backend-v1.0.1-test` / `adminpanel-v1.0.1-test`: + +1. **test** — composer / npm, lint, build +2. **build-and-push** — Docker-образ в Gitea Container Registry +3. **deploy-gitops** — commit в `sova/sova-deploy` (repository, tag, pullPolicy) + +### Registry и секреты CI + +| Секрет | Назначение | +|--------|------------| +| `REGISTRY_USER` / `REGISTRY_PASSWORD` | Push образов (`gitea_admin` — у `sova-ci` нет прав на packages) | +| `DEPLOY_TOKEN` | HTTPS push в `sova-deploy` | +| `HOST_IP` | IP VM для `/etc/hosts` (имена с префиксом `GITEA_` Gitea не принимает) | + +Push из runner идёт на **внутренний URL** `gitea-http.gitea.svc.cluster.local:3000` (DinD не резолвит `git.sova.local`). В `values-test.yaml` для pull на ноде k3s используется **`git.sova.local/sova/backend`** — после `./scripts/configure-k3s-registry.sh`. + +```bash +./scripts/bootstrap-gitea-ci-secrets.sh # секреты в Gitea Actions +./scripts/configure-k3s-registry.sh # k3s registries.yaml + pull secret +./scripts/release-test-tag.sh backend backend-v1.0.1-test +``` + +### Runner (Gitea Actions) + +Развёрнут через официальный chart `gitea-charts/actions` + DinD (Docker-in-Docker): + +```bash +./scripts/bootstrap-gitea-runner.sh +``` + +Конфиг: `sova-deploy/platform/gitea-actions/values-test.yaml` + +| Параметр | Значение | +|----------|----------| +| Release | `gitea-actions` | +| Namespace | `gitea` | +| Имя runner | `sova-test-k8s` | +| Labels | `ubuntu-latest`, `ubuntu-22.04` | +| Gitea URL (внутри кластера) | `http://gitea-http.gitea.svc.cluster.local:3000` | + +Проверка: http://git.sova.local/admin/actions/runners — должен быть **Online**. + +Логи: `kubectl logs -n gitea -l app.kubernetes.io/name=actions-runner -c runner -f` + +Workflow запускается по push тега. Job `test` не требует registry; `build-and-push` — нужен Container Registry (`packages.ENABLED=true` в Gitea). + +--- + +## Проверка штатного режима (чеклист) + +После полного bootstrap или CI-релиза: + +```bash +export KUBECONFIG=~/.kube/sova-test-config + +# 1. Поды +kubectl get pods -n sova-test +kubectl get cronjobs -n sova-test # backend-sync-doctors, backend-sync-reviews, ... + +# 2. ArgoCD +kubectl get applications -n argocd +# UI: http://argocd.sova.local → backend-test → дерево с CronJob + +# 3. API +curl -s -o /dev/null -w "%{http_code}\n" -H "Host: api.test.sova.local" \ + "http://$(multipass info sova-test | awk '/IPv4/{print $2; exit}')/news/list?page=1" +# Ожидается: 200 + +curl -X POST http://api.test.sova.local/user/login \ + -H 'Content-Type: application/json' \ + -d '{"username":"local.backend@example.test","password":"local-password"}' + +# 4. CI (если настроен runner) +# http://git.sova.local/sova/backend/actions — последний run: success + +# 5. Логи в Grafana (не Prometheus!) +# http://grafana.sova.local → Explore → Loki → {namespace="sova-test"} + +# 6. Admin panel +curl -s -o /dev/null -w "%{http_code}\n" -H "Host: admin.test.sova.local" \ + "http://$(multipass info sova-test | awk '/IPv4/{print $2; exit}')/" +``` + +--- + +## Перенос на удалённый сервер + +Ниже — пошаговый план миграции с Multipass на bare metal / VPS / облако. + +### 1. Требования к серверу + +| Ресурс | Минимум (test) | Рекомендуется | +|--------|----------------|---------------| +| CPU | 4 vCPU | 8 vCPU | +| RAM | 8 GB | 16 GB | +| Disk | 40 GB SSD | 80+ GB SSD | +| ОС | Ubuntu 22.04 LTS | Ubuntu 22.04 / 24.04 | +| Сеть | Публичный IP или VPN | + DNS на ваш домен | + +Открытые порты: **80**, **443** (ingress), опционально **22** (SSH). + +### 2. Подготовка сервера + +```bash +# На сервере (Ubuntu) +sudo apt update && sudo apt upgrade -y +sudo apt install -y curl git + +# Установка k3s (аналог install-k3s-multipass.sh, но на bare metal) +curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik" sh - + +# Kubeconfig на вашу машину +scp user@SERVER:/etc/rancher/k3s/k3s.yaml ~/.kube/sova-remote-config +# Заменить 127.0.0.1 на IP сервера в server: +export KUBECONFIG=~/.kube/sova-remote-config +``` + +Terraform-модуль `sova-platform/terraform/modules/k3s-single-node` можно использовать и для удалённого сервера: задать `server_ip`, `ssh_user`, `ssh_private_key_path` в `terraform.tfvars`. + +### 3. DNS вместо /etc/hosts + +Замените `*.sova.local` на реальный домен, например: + +| Было (local) | Станет (remote test) | +|--------------|----------------------| +| `api.test.sova.local` | `api.test.sova.dev` | +| `admin.test.sova.local` | `admin.test.sova.dev` | +| `git.sova.local` | `git.test.sova.dev` | +| `argocd.sova.local` | `argocd.test.sova.dev` | +| `grafana.sova.local` | `grafana.test.sova.dev` | + +A-записи всех имён → **публичный IP сервера**. + +Файлы для правки: + +- `sova-deploy/apps/backend/values-test.yaml` — ingress host, `API_PUBLIC_URL`, CORS +- `sova-deploy/apps/adminpanel/values-test.yaml` — ingress, env.js API URL +- `scripts/deploy-platform.sh` — Gitea `DOMAIN`, `ROOT_URL` +- `scripts/deploy-platform-ingress.sh` — host rules +- `sova-adminpanel/public/env.js` (или ConfigMap) — `API_BASE_URL` + +### 4. TLS (рекомендуется на сервере) + +1. cert-manager уже ставится через `deploy-platform.sh`. +2. Создайте ClusterIssuer Let's Encrypt (HTTP-01 или DNS-01). +3. В Ingress добавьте `tls:` секции и annotation `cert-manager.io/cluster-issuer`. +4. Для ArgoCD при TLS на ingress: оставьте `server.insecure=true` **или** настройте TLS passthrough — см. [документацию ArgoCD](https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/). + +### 5. Образы: с локального import на registry + +**Сейчас (Multipass):** образы собираются на Mac, импортируются через `multipass transfer` + `k3s ctr images import`, `image.pullPolicy: Never`. + +**На сервере:** + +```bash +# Вариант A: registry в Gitea +# После bootstrap-gitea — включить Container Registry в Gitea, +# push: git.test.sova.dev/sova/backend:backend-v1.0.0-test + +# Вариант B: внешний registry (GitHub CR, GitLab, Yandex CR) +docker build -t registry.example.com/sova/backend:1.0.0-test ./sova-backend +docker push registry.example.com/sova/backend:1.0.0-test +``` + +В `values-test.yaml`: + +```yaml +image: + repository: git.test.sova.dev/sova/backend # или ваш registry + tag: backend-v1.0.0-test + pullPolicy: IfNotPresent +``` + +Добавьте `imagePullSecrets` если registry приватный. + +### 6. Секреты + +**Сейчас:** plain Secrets в Helm values (`sova-deploy/apps/backend/values.yaml`). + +**На сервере:** + +1. [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) — уже ставится в platform layer. +2. Зашифруйте секреты локально, commit sealed-манifests в `sova-deploy`. +3. Уберите пароли из plain `values.yaml`. + +Обязательно смените: + +- `APP_SECRET`, пароли БД, `JWT` keys (новая пара для test/stage/prod) +- Gitea admin password +- Grafana admin password + +### 7. Базы данных + +Test-контур использует in-cluster PostgreSQL/Redis/MySQL. Для удалённого test это допустимо; для stage/prod рассмотрите: + +- managed PostgreSQL (Yandex Cloud, RDS, etc.); +- отдельный MySQL для Bitrix views; +- backup PVC или external storage class. + +Порядок инициализации **тот же**: + +```bash +./scripts/prepare-db-init.sh +helm upgrade --install db-init ./sova-deploy/data/db-init -n sova-data-test +``` + +При смене PostgreSQL major version перегенерируйте SQL (`prepare-db-init.py` уже учитывает отличия PG 18). + +### 8. Деплой на сервер — чеклист + +```bash +# С вашей машины (KUBECONFIG → удалённый кластер) +export KUBECONFIG=~/.kube/sova-remote-config + +# 1. Platform +BOOTSTRAP_PLATFORM=1 ./scripts/deploy-platform.sh + +# 2. Обновить values-test.yaml под новый домен (см. п.3) +# 3. Apps + data +./scripts/deploy-test-stack.sh test # или ваш tag + +# 4. Gitea repos (push с CI-машины или с сервера) +GITEA_HOST=git.test.sova.dev ./scripts/bootstrap-gitea.sh + +# 5. ArgoCD +GITEA_REPO_URL=http://gitea-http.gitea.svc.cluster.local:3000 \ + ./scripts/bootstrap-argocd.sh + +# 6. Gitea Actions runner +./scripts/bootstrap-gitea-runner.sh + +# 7. Smoke +curl https://api.test.sova.dev/news/list?page=1 +./scripts/print-test-users.sh +``` + +### 9. GitOps как единственный источник правды + +После первичного bootstrap: + +1. Все изменения infra/apps — через commit в `sova/sova-deploy`. +2. ArgoCD sync автоматически (у Applications включён `automated.selfHeal`). +3. CI по тегу обновляет `values-test.yaml` → ArgoCD выкатывает новый образ. + +### 10. Мониторинг, логи и алерты + +- **Prometheus** — метрики k8s и приложений: http://prometheus.sova.local +- **Grafana** — дашборды + **логи через Loki**: http://grafana.sova.local +- Установка логов: `./scripts/deploy-monitoring-logs.sh` (Loki + Promtail + datasource) +- На сервере: смените пароль Grafana, TLS на Ingress + +### 11. Registry на сервере + +```bash +./scripts/configure-k3s-registry.sh # HTTP mirror git.sova.local + imagePullSecret +./scripts/bootstrap-gitea-ci-secrets.sh +``` + +В `values-test.yaml` после CI: + +```yaml +image: + repository: git.test.sova.dev/sova/backend + tag: backend-v1.0.1-test + pullPolicy: IfNotPresent +imagePullSecrets: + - name: gitea-registry +``` + +### 12. Отличия local vs remote (сводка) + +| Аспект | Multipass (сейчас) | Удалённый сервер | +|--------|-------------------|------------------| +| Домен | `*.sova.local` + /etc/hosts | Реальный DNS | +| TLS | HTTP | Let's Encrypt / свой сертификат | +| Образы | local import, `pullPolicy: Never` | Gitea/registry, `IfNotPresent` | +| Секреты | plain values | SealedSecrets / External Secrets | +| k3s | VM Multipass | bare metal / VPS / Terraform | +| Gitea URL для ArgoCD | internal service URL | тот же паттерн (internal) | +| CI runner | `gitea-actions` StatefulSet (DinD) | масштабировать replicas / отдельная VM | +| State Terraform | local | S3 + DynamoDB / GitLab state | + +--- + +## Troubleshooting + +| Симптом | Причина | Решение | +|---------|---------|---------| +| ArgoCD редирект на HTTPS | неверный `server.insecure` | `bootstrap-argocd.sh`, patch `argocd-cmd-params-cm` | +| Gitea 503 | неверный service в Ingress | `gitea-http:3000` в `deploy-platform-ingress.sh` | +| `/user/login` 500 | нет JWT keys | Helm chart `backend-jwt` secret, remount | +| `/news/list` 500 | Symfony cache not writable | initContainer `warmup-cache`, emptyDir `/app/var/cache` | +| ImagePullBackOff после CI | k3s не резолвит `.svc.cluster.local` | `repository: git.sova.local/...` + `configure-k3s-registry.sh` | +| Grafana без логов | Loki не установлен | `./scripts/deploy-monitoring-logs.sh`, Explore → Loki | +| ArgoCD нет кнопки Terminal в pod | `exec.enabled: false` | `./scripts/bootstrap-argocd.sh` или values `platform/argocd/values-test.yaml` | +| db-init Failed | MySQL TLS / auth plugin | `--skip-ssl`, `mysql_native_password` | +| db-init Failed на seed | нет `\connect` / md5() | перезапустить `prepare-db-init.sh` | +| ArgoCD Unknown sync | Gitea по внешнему DNS из pod | internal URL `gitea-http.gitea.svc.cluster.local:3000` | +| Bitnami chart 403 | закрытый HTTP repo | OCI: `oci://registry-1.docker.io/bitnamicharts/...` | + +--- + +## Полезные команды + +```bash +# Статус +kubectl get pods -A +kubectl get applications -n argocd + +# Логи backend +kubectl logs -n sova-test deploy/backend -c php-fpm --tail=50 + +# Пересоздать БД +kubectl delete job db-init -n sova-data-test +USE_MULTIPASS=1 ./scripts/deploy-test-stack.sh local-test + +# Helm dry-run +helm template backend-test ./sova-deploy/apps/backend \ + -f ./sova-deploy/apps/backend/values-test.yaml +``` + +--- + +## Итог + +В `k3s-test/` собран **полноценный test-контур**: приложения, изолированные БД (schema → seed), моки внешних сервисов, GitOps и заготовка CI. Локально он крутится на Multipass + k3s и имитирует production-подобный стек без изменений монорепо. + +Перенос на удалённый сервер — это в основном замена **домена**, **TLS**, **registry образов** и **управления секретами**; скрипты и Helm charts из `k3s-test/` переиспользуются с минимальными правками `values-test.yaml`. + +Дальнейшие шаги для production-ready test-сервера: + +1. DNS + TLS +2. Gitea Container Registry (для `docker push` в CI) +3. SealedSecrets +4. Backup БД +5. Отдельный stage-контур с `values-stage.yaml` diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..3676c50 --- /dev/null +++ b/site/index.html @@ -0,0 +1,25 @@ + + + + + Sova Test Contour Docs + + + + +
+ + + + +