diff --git a/TEST_STAND/LUCEE/SCHEMA.md b/TEST_STAND/LUCEE/SCHEMA.md deleted file mode 100644 index 654dfbf..0000000 --- a/TEST_STAND/LUCEE/SCHEMA.md +++ /dev/null @@ -1,5 +0,0 @@ -# LUCEE — схема взаимодействия с Postgres - -Ниже статическая SVG-версия схемы (надёжно рендерится в VSCode): - -![LUCEE схема](SCHEMA.svg) diff --git a/TEST_STAND/LUCEE/SCHEMA.svg b/TEST_STAND/LUCEE/SCHEMA.svg deleted file mode 100644 index b77332f..0000000 --- a/TEST_STAND/LUCEE/SCHEMA.svg +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - - - - - - - TABLE_NAME - - - TABLE_NAME - - - testds_username - - - testds_password - - - testds_connectionString - - - testds_username - - - testds_validate - - - testds_class - - - - - Postgres (БД) - - internalMaster - - - vault_users - - - pg_db_name - - - DATABASE_URL - - - PGHOST - - - PGPORT - - - PGUSER - - - PGPASSWORD - - - notification - - - - - Lucee - DATABASE_URL - PGHOST · PGPORT · PGUSER · PGPASSWORD - TABLE_NAME · testds_class/bundle/version - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TEST_STAND/LUCEE/locals.tf b/TEST_STAND/LUCEE/locals.tf new file mode 100644 index 0000000..0c93bae --- /dev/null +++ b/TEST_STAND/LUCEE/locals.tf @@ -0,0 +1,45 @@ +# ============================================================================= +# locals.tf — все настраиваемые значения модуля LUCEE +# Никакого хардкода в ресурсах — всё здесь. +# ============================================================================= + +locals { + # ─── PostgreSQL ────────────────────────────────────────────────────────── + pg_resource_name = "pglucee001" + pg_cpu = 500 + pg_memory = 512 + pg_replicas = 1 + pg_disk = 10 + pg_version = "17" + pg_retain = 14 + pg_schedule = "0 0 * * *" + pg_timeout = "11m" + + # ─── PostgreSQL User ───────────────────────────────────────────────────── + pg_username = "user4crudpg" + pg_role = "ddl_user" + pg_db_name = "db4crudpg" + + # ─── Lucee ─────────────────────────────────────────────────────────────── + lucee_git_revision = "94e14" + lucee_resource_name = "luceeresource" + lucee_domain = "tflucee" + lucee_version = "5.4" + lucee_git_path = "https://gitea.services.ngcloud.ru/Nail/tfluceecrud.git" + lucee_cpu = 300 + lucee_memory = 512 + lucee_replicas = 1 + + # ─── Таблица CRUD ──────────────────────────────────────────────────────── + crud_table_name = "crud_items" + + # ─── JDBC / БД ─────────────────────────────────────────────────────────── + jdbc_class = "org.postgresql.Driver" + jdbc_bundle_name = "org.postgresql.jdbc" + jdbc_bundle_version = "42.6.0" + jdbc_conn_limit = "5" + jdbc_live_timeout = "15" + jdbc_validate = "false" + pg_port = "5432" + pg_ssl_mode = "require" +} diff --git a/TEST_STAND/LUCEE/lucee.tf b/TEST_STAND/LUCEE/lucee.tf index 7117d58..57daf86 100644 --- a/TEST_STAND/LUCEE/lucee.tf +++ b/TEST_STAND/LUCEE/lucee.tf @@ -1,51 +1,51 @@ locals { pg_host = nubes_postgres.npg_lucee.state_out_flat["internalMaster"] pg_user = nubes_postgres_user.crud_user_0.username - pg_pass = jsondecode(nubes_postgres.npg_lucee.vault_secrets["users"]).user4crudpg.password + pg_pass = nonsensitive(jsondecode(nubes_postgres.npg_lucee.vault_secrets["users"]).user4crudpg.password) pg_db = nubes_postgres_database.pg_db.db_name } resource "nubes_lucee" "applucee" { - resource_name = "luceeresource" + resource_name = local.lucee_resource_name startup_configuration = { resource_realm = var.realm } cluster_configuration = { - cpu = 300 - memory = 512 - replicas = 1 + cpu = local.lucee_cpu + memory = local.lucee_memory + replicas = local.lucee_replicas } access_configuration = { - domain = "tflucee" + domain = local.lucee_domain } app_configuration = { - version = "5.4" - git_path = "https://gitea.services.ngcloud.ru/Nail/tfluceecrud.git" + version = local.lucee_version + git_path = local.lucee_git_path } - git_revision = "94ebf06" + git_revision = local.lucee_git_revision json_env = jsonencode({ - TABLE_NAME = "check_point" - testds_class = "org.postgresql.Driver" - testds_bundleName = "org.postgresql.jdbc" - testds_bundleVersion = "42.6.0" + TABLE_NAME = local.crud_table_name + testds_class = local.jdbc_class + testds_bundleName = local.jdbc_bundle_name + testds_bundleVersion = local.jdbc_bundle_version testds_connectionString = "jdbc:postgresql://${local.pg_host}:5432/${local.pg_db}" testds_username = local.pg_user testds_password = local.pg_pass - testds_connectionLimit = "5" - testds_liveTimeout = "15" - testds_validate = "false" + testds_connectionLimit = local.jdbc_conn_limit + testds_liveTimeout = local.jdbc_live_timeout + testds_validate = local.jdbc_validate PGHOST = local.pg_host - PGPORT = "5432" + PGPORT = local.pg_port PGUSER = local.pg_user PGPASSWORD = local.pg_pass - PGSSLMODE = "require" + PGSSLMODE = local.pg_ssl_mode DATABASE_URL = format( "postgresql://%s:%s@%s:5432/%s", local.pg_user, diff --git a/TEST_STAND/LUCEE/nubes_postgres_lucee.tf b/TEST_STAND/LUCEE/nubes_postgres_lucee.tf index 3c0b46b..834e25b 100644 --- a/TEST_STAND/LUCEE/nubes_postgres_lucee.tf +++ b/TEST_STAND/LUCEE/nubes_postgres_lucee.tf @@ -1,15 +1,15 @@ resource "nubes_postgres" "npg_lucee" { - resource_name = "pglucee001" + resource_name = local.pg_resource_name startup_configuration = { resource_realm = var.realm } cluster_configuration = { - cpu = 500 - memory = 512 - replicas = 1 - disk = 10 + cpu = local.pg_cpu + memory = local.pg_memory + replicas = local.pg_replicas + disk = local.pg_disk } access_configuration = { @@ -20,7 +20,7 @@ resource "nubes_postgres" "npg_lucee" { } postgres_configuration = { - version = "17" + version = local.pg_version ssl_required = true pooler_master = false pooler_slave = false @@ -33,9 +33,8 @@ resource "nubes_postgres" "npg_lucee" { backup_configuration = { s3_uid = var.s3_name - # s3_uid = var.s3_user_uid - retain = 14 - schedule = "0 0 * * *" + retain = local.pg_retain + schedule = local.pg_schedule } autoscale_configuration = { @@ -45,6 +44,6 @@ resource "nubes_postgres" "npg_lucee" { quota = 100 } - operation_timeout = "11m" + operation_timeout = local.pg_timeout adopt_existing_on_create = true } diff --git a/TEST_STAND/LUCEE/userUNDdb.tf b/TEST_STAND/LUCEE/userUNDdb.tf index 103844b..2ee8cfd 100644 --- a/TEST_STAND/LUCEE/userUNDdb.tf +++ b/TEST_STAND/LUCEE/userUNDdb.tf @@ -1,17 +1,16 @@ # ============================================================================= -# PostgreSQL — пользователи (6 шт.) +# PostgreSQL — пользователи и базы данных # ============================================================================= resource "nubes_postgres_user" "crud_user_0" { postgres_id = nubes_postgres.npg_lucee.id - username = "user4crudpg" - role = "ddl_user" + username = local.pg_username + role = local.pg_role adopt_existing_on_create = true } resource "nubes_postgres_database" "pg_db" { postgres_id = nubes_postgres.npg_lucee.id - db_name = "db4crudpg" + db_name = local.pg_db_name db_owner = nubes_postgres_user.crud_user_0.username adopt_existing_on_create = true } - diff --git a/TOOLS/config/dev/profile.env b/TOOLS/config/dev/profile.env index 27db4e8..97617d0 100644 --- a/TOOLS/config/dev/profile.env +++ b/TOOLS/config/dev/profile.env @@ -4,7 +4,7 @@ TOKEN_FILE="secrets/dev.token" # Release versions # Version -VERSION="3.1.11" +VERSION="3.1.12" # Registry/S3 settings REGISTRY_HOST="registry.kube5s.ru" diff --git a/TOOLS/config/prod/profile.env b/TOOLS/config/prod/profile.env index d0f8eb3..5082d56 100644 --- a/TOOLS/config/prod/profile.env +++ b/TOOLS/config/prod/profile.env @@ -4,7 +4,7 @@ TOKEN_FILE="secrets/prod.token" # Release versions # Version -VERSION="2.1.10" +VERSION="2.1.11" # Registry/S3 settings REGISTRY_HOST="registry.kube5s.ru" diff --git a/TOOLS/config/test/profile.env b/TOOLS/config/test/profile.env index 259b5db..ac1b71e 100644 --- a/TOOLS/config/test/profile.env +++ b/TOOLS/config/test/profile.env @@ -3,7 +3,7 @@ NUBES_API_ENDPOINT="https://lk-api-gateway-test.ngcloud.ru/api/v1/svc" TOKEN_FILE="secrets/test.token" # Version -VERSION="5.1.13" +VERSION="5.1.14" # Docs generation — ONLY from docs_gen// (never from docs/) DOCS_GEN_DIR="provider/docs_gen/test" diff --git a/TOOLS/resource-generator/internal/templates/instance.go b/TOOLS/resource-generator/internal/templates/instance.go index b1e0c8f..ef22a03 100644 --- a/TOOLS/resource-generator/internal/templates/instance.go +++ b/TOOLS/resource-generator/internal/templates/instance.go @@ -548,7 +548,6 @@ func (r *{{ToCamel .Name}}Resource) Update(ctx context.Context, req resource.Upd {{- if .HasRedeploy }} // --- Redeploy support (ARCHITECTURE.md) --- if redeployRequested { - {{- if .RedeployParams }} redeployParams := map[int]string{} {{- range .RedeployParams }} {{- if (IsNested .) }} @@ -559,10 +558,17 @@ func (r *{{ToCamel .Name}}Resource) Update(ctx context.Context, req resource.Upd redeployParams[{{.ID}}] = {{ParamFormat . (printf "plan.%s" (ToCamel .Code))}} {{- end }} {{- end }} - if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout, redeployParams); err != nil { + // Merge modify-params into redeploy to avoid state drift + {{- range .ModifyParams }} + {{- if (IsNested .) }} + if plan.{{ToCamel .Code}} != nil { + redeployParams[{{.ID}}] = {{NestedJSONExpr . "plan"}} + } {{- else }} - if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout, nil); err != nil { + redeployParams[{{.ID}}] = {{ParamFormat . (printf "plan.%s" (ToCamel .Code))}} {{- end }} + {{- end }} + if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout, redeployParams); err != nil { resp.Diagnostics.AddError("Ошибка клиента", err.Error()) return } diff --git a/docs/TODO/GATEWAY_SERVICE.md b/docs/TODO/GATEWAY_SERVICE.md new file mode 100644 index 0000000..ab7788d --- /dev/null +++ b/docs/TODO/GATEWAY_SERVICE.md @@ -0,0 +1,574 @@ +# GATEWAY Service — Path-based DNS-less Router + +> **Репозиторий:** `gateway` (шаблонный, создан 2026-07-20) +> **URL:** `https://gateway.nodejsk8s.services.ngcloud.ru/` +> **Назначение:** Замена всех DNS-записей `*.kube5s.ru` единым path-based роутером +> **Статус:** СПЛАНИРОВАНО, НЕ НАЧАТО + +--- + +## 1. ЗАЧЕМ ЭТО НУЖНО + +### Проблема + +Сейчас каждый сервис живёт на своём поддомене `*.kube5s.ru`: + +| Поддомен | Сервис | Ingress | TLS-сертификат | +|----------|--------|---------|-----------------| +| `registry.kube5s.ru` | Terraform Registry | отдельный | отдельный | +| `something1.kube5s.ru` | Сервис 1 | отдельный | отдельный | +| `something2.kube5s.ru` | Сервис 2 | отдельный | отдельный | +| ... | ... | ... | ... | + +**Проблемы:** +- Домен `kube5s.ru` — **срочный**, скоро истекает +- Продление — **дорого** +- Каждый поддомен = DNS-запись + Ingress + сертификат — **администрировать заебало** + +### Решение + +**Один домен, один Ingress, один сертификат.** Все сервисы — под path-префиксами: + +``` +https://gateway.nodejsk8s.services.ngcloud.ru/record01/* → Сервис 1 +https://gateway.nodejsk8s.services.ngcloud.ru/record02/* → Сервис 2 +https://gateway.nodejsk8s.services.ngcloud.ru/record03/* → Сервис 3 +``` + +Домен `gateway.nodejsk8s.services.ngcloud.ru` — **облачный managed service**, назначается облаком, не требует покупки/продления. + +### Выгода + +| Было (DNS-based) | Стало (Path-based) | +|---|---| +| N DNS-записей | 0 дополнительных DNS-записей | +| N Ingress'ов | 1 Ingress | +| N TLS-сертификатов | 1 TLS-сертификат | +| Домен `kube5s.ru` нужен | Домен `kube5s.ru` не нужен | + +--- + +## 2. АРХИТЕКТУРА + +```mermaid +graph TD + subgraph "Внешний мир" + T[Terraform CLI] + C[Клиенты API] + end + + subgraph "Kubernetes (облако Nubes)" + I["Ingress
gateway.nodejsk8s.services.ngcloud.ru
(cert-manager + LE)"] + G["GATEWAY Service
(NodeJS: Express + http-proxy-middleware)"] + + I --> G + + G -->|"/record01/*"| R1["registry-server
(Terraform Registry)"] + G -->|"/record02/*"| R2["Сервис 2
(будущий)"] + G -->|"/record03/*"| R3["Сервис 3
(будущий)"] + G -->|"/"| FALLBACK["Fallback / health-check"] + end + + T -->|"source = gateway...nubes.ru/nubes/nubes"| I +``` + +### Как это работает (для Terraform Registry) + +1. Terraform читает `.tf`: + ```hcl + source = "gateway.nodejsk8s.services.ngcloud.ru/nubes-test/nubes" + ``` + +2. Terraform идёт в: + ``` + GET https://gateway.nodejsk8s.services.ngcloud.ru/.well-known/terraform.json + ``` + +3. GATEWAY проксирует на registry-server, который отвечает: + ```json + { "providers.v1": "/record01/v1/providers/" } + ``` + +4. Terraform дальше сам идёт по `/record01/v1/providers/nubes-test/nubes/versions` + +5. Registry-server генерит download-url с префиксом `/record01/v1/proxy?...` + +6. Profit. Terraform скачивает провайдер. + +--- + +## 3. КОНФИГУРАЦИЯ GATEWAY + +### Формат конфига (`config.yaml` или env-переменные) + +```yaml +# gateway/config.yaml +routes: + - id: "registry" + prefix: "/record01" + description: "Terraform Provider Registry" + upstream: "http://registry-server.terra.svc.cluster.local:8080" + stripPrefix: false # НЕ отрезать /record01 — registry сам знает свой префикс + timeout: 30000 # 30s (registry может долго листить S3) + + - id: "future-service-2" + prefix: "/record02" + description: "Будущий сервис — TODO" + upstream: "http://service2.namespace.svc.cluster.local:8080" + stripPrefix: true # Отрезать /record02 перед отправкой в upstream + timeout: 10000 + + - id: "future-service-3" + prefix: "/record03" + description: "Будущий сервис — TODO" + upstream: "http://service3.namespace.svc.cluster.local:3000" + stripPrefix: true + timeout: 10000 +``` + +### Конфиг через env (альтернатива, проще для K8s) + +```bash +# Формат: ROUTE_XX_ID, ROUTE_XX_PREFIX, ROUTE_XX_UPSTREAM, ROUTE_XX_STRIP, ROUTE_XX_TIMEOUT +ROUTE_01_ID=registry +ROUTE_01_PREFIX=/record01 +ROUTE_01_UPSTREAM=http://registry-server.terra.svc.cluster.local:8080 +ROUTE_01_STRIP=false +ROUTE_01_TIMEOUT=30000 + +ROUTE_02_ID=future-svc +ROUTE_02_PREFIX=/record02 +ROUTE_02_UPSTREAM=http://service2.namespace.svc.cluster.local:8080 +ROUTE_02_STRIP=true +ROUTE_02_TIMEOUT=10000 +``` + +### Важно: `stripPrefix` + +| Режим | Когда использовать | +|-------|--------------------| +| `stripPrefix: false` | Upstream **знает** о своём префиксе и сам его обрабатывает (как registry-server с `PATH_PREFIX=/record01`) | +| `stripPrefix: true` | Upstream **не знает** о префиксе — GATEWAY отрезает его перед проксированием. `/record01/api/users` → `/api/users` | + +--- + +## 4. КОД GATEWAY (план) + +### Стек + +- **NodeJS** + **Express** — HTTP-фреймворк +- **http-proxy-middleware** — реверс-прокси +- **Dotenv / js-yaml** — конфигурация + +### Структура проекта + +``` +gateway/ +├── package.json +├── server.js # Главный файл +├── config/ +│ ├── routes.yaml # Конфиг маршрутов +│ └── index.js # Загрузчик конфига +├── lib/ +│ ├── proxy.js # Фабрика proxy-middleware'ов из конфига +│ ├── health.js # Health/readiness probes +│ └── logger.js # Логирование +├── Dockerfile +├── .dockerignore +└── README.md +``` + +### `server.js` (псевдокод) + +```javascript +const express = require('express'); +const { createProxyMiddleware } = require('http-proxy-middleware'); +const { loadRoutes } = require('./config'); +const { healthHandler, readyHandler } = require('./lib/health'); + +const app = express(); +const routes = loadRoutes(); // из env или routes.yaml + +// Health probes (без прокси) +app.get('/healthz', healthHandler); +app.get('/readyz', readyHandler); + +// Root — информационная страница +app.get('/', (req, res) => { + res.json({ + service: 'gateway', + version: process.env.APP_VERSION || '1.0.0', + routes: routes.map(r => ({ + prefix: r.prefix, + description: r.description + })) + }); +}); + +// Динамическая регистрация прокси-маршрутов +for (const route of routes) { + const proxy = createProxyMiddleware({ + target: route.upstream, + changeOrigin: true, + pathRewrite: route.stripPrefix + ? { [`^${route.prefix}`]: '' } + : undefined, + timeout: route.timeout, + onError: (err, req, res) => { + console.error(`[${route.id}] Proxy error:`, err.message); + res.status(502).json({ error: 'Upstream unavailable', route: route.id }); + } + }); + + app.use(route.prefix, proxy); + console.log(`Route: ${route.prefix} → ${route.upstream} (strip: ${route.stripPrefix})`); +} + +// 404 для всего остального +app.use((req, res) => { + res.status(404).json({ error: 'Not Found', path: req.path }); +}); + +app.listen(process.env.PORT || 3000); +``` + +--- + +## 5. КАК ДОБАВИТЬ НОВЫЙ СЕРВИС (RECORD) + +### Шаг 1: Создать сервис в K8s + +```yaml +# Пример: новый сервис my-api +apiVersion: v1 +kind: Service +metadata: + name: my-api + namespace: default +spec: + ports: + - port: 8080 + selector: + app: my-api +``` + +### Шаг 2: Добавить route в конфиг gateway + +```yaml +# Добавить в config/routes.yaml: + - id: "my-api" + prefix: "/record04" + description: "Мой новый API" + upstream: "http://my-api.default.svc.cluster.local:8080" + stripPrefix: true + timeout: 10000 +``` + +### Шаг 3: Передеплоить gateway + +```bash +kubectl rollout restart deployment/gateway -n terra +``` + +### Шаг 4: Готово + +Сервис доступен по адресу: +``` +https://gateway.nodejsk8s.services.ngcloud.ru/record04/ +``` + +**Никаких DNS, Ingress'ов, сертификатов.** Только конфиг gateway. + +--- + +## 6. ЧТО НУЖНО ПОМЕНЯТЬ В REGISTRY-SERVER + +Файл: `~/tf_registry/server/main.go` + +### Добавить env-переменную + +```go +var pathPrefix = os.Getenv("PATH_PREFIX") // "/record01" или "" (пустая строка = без префикса, обратная совместимость) +``` + +### Изменить `main()` — регистрация handlers + +```go +// БЫЛО: +http.HandleFunc("/.well-known/terraform.json", discoveryHandler) +http.HandleFunc("/v1/providers/", router) +http.HandleFunc("/v1/proxy", proxyHandler) +http.HandleFunc("/docs/", docsHandler) + +// СТАЛО: +http.HandleFunc(pathPrefix+"/.well-known/terraform.json", discoveryHandler) +http.HandleFunc(pathPrefix+"/v1/providers/", router) +http.HandleFunc(pathPrefix+"/v1/proxy", proxyHandler) +http.HandleFunc(pathPrefix+"/docs/", docsHandler) +``` + +### Изменить `discoveryHandler()` — ответ с префиксом + +```go +// БЫЛО: +json.NewEncoder(w).Encode(Discovery{ProvidersV1: "/v1/providers/"}) + +// СТАЛО: +json.NewEncoder(w).Encode(Discovery{ProvidersV1: pathPrefix + "/v1/providers/"}) +``` + +### Изменить `downloadVersion()` — ссылки с префиксом + +```go +// БЫЛО: +baseURL := "https://" + hostname +downloadLink := fmt.Sprintf("%s/v1/proxy?bucket=%s&key=%s", baseURL, bucketName, url.QueryEscape(fullKey)) + +// СТАЛО: +baseURL := "https://" + hostname + pathPrefix +downloadLink := fmt.Sprintf("%s/v1/proxy?bucket=%s&key=%s", baseURL, bucketName, url.QueryEscape(fullKey)) +``` + +### Изменить `listVersions()` — S3-префикс + +```go +// БЫЛО: +prefix := fmt.Sprintf("%s/%s/%s/", hostname, namespace, pType) + +// СТАЛО (hostname теперь = gateway.nodejsk8s.services.ngcloud.ru): +// Если PATH_PREFIX непустой, можно использовать его как основу для S3-пути, +// либо продолжать использовать hostname. Зависит от того, как лежат файлы в S3. +// Пока оставляем hostname — он просто поменяется на новый домен. +prefix := fmt.Sprintf("%s/%s/%s/", hostname, namespace, pType) +``` + +### Новые env-переменные для registry-server + +| Переменная | Было | Стало | +|------------|------|-------| +| `REGISTRY_HOSTNAME` | `terra.k8c.ru` / `registry.kube5s.ru` | `gateway.nodejsk8s.services.ngcloud.ru` | +| `PATH_PREFIX` | — | `/record01` | + +--- + +## 7. КАК ЭТО ВЫГЛЯДИТ ДЛЯ КЛИЕНТОВ (terraform init) + +### Было + +```hcl +terraform { + required_providers { + nubes = { + source = "registry.kube5s.ru/nubes-test/nubes" + version = "5.1.13" + } + } +} +``` + +### Стало + +```hcl +terraform { + required_providers { + nubes = { + source = "gateway.nodejsk8s.services.ngcloud.ru/nubes-test/nubes" + version = "5.1.13" + } + } +} +``` + +**Всё.** Terraform сам разберётся: +1. Пойдёт на `.well-known/terraform.json` +2. Получит путь `/record01/v1/providers/` +3. Скачает провайдер через `/record01/v1/proxy?...` + +--- + +## 8. ПЛАН ВНЕДРЕНИЯ + +### Фаза 1: Подготовка GATEWAY + +- [ ] Склонировать шаблонный репо +- [ ] Написать `server.js` (прокси-роутер) +- [ ] Написать `config/routes.yaml` с первым роутом (`/record01` → registry) +- [ ] Dockerfile +- [ ] Helm chart / K8s manifests (Deployment, Service) +- [ ] Ingress: `gateway.nodejsk8s.services.ngcloud.ru` → gateway-service +- [ ] TLS через cert-manager + +### Фаза 2: Подготовка Registry-Server + +- [ ] Добавить `PATH_PREFIX` в `server/main.go` +- [ ] Изменить `REGISTRY_HOSTNAME` на `gateway.nodejsk8s.services.ngcloud.ru` +- [ ] Собрать новый Docker-образ +- [ ] Задеплоить registry-server с новыми env +- [ ] Убедиться что registry отвечает на `/record01/.well-known/terraform.json` +- [ ] Убедиться что download-url содержат `/record01/` + +### Фаза 3: Тестирование + +- [ ] `curl https://gateway.nodejsk8s.services.ngcloud.ru/record01/.well-known/terraform.json` → OK +- [ ] `curl https://gateway.nodejsk8s.services.ngcloud.ru/record01/v1/providers/nubes-test/nubes/versions` → OK +- [ ] `terraform init` с новым source → OK + +### Фаза 4: Миграция клиентов + +- [ ] Обновить `provider/main.go` — `address` по умолчанию на новый домен +- [ ] Обновить profile.env (dev/test/prod) — `REGISTRY_HOSTNAME` +- [ ] Обновить все `.tf` файлы в `PROD_STAND/`, `TEST_STAND/`, `DEV_STAND/` +- [ ] Обновить CI/CD (`.github/workflows/`, build scripts) +- [ ] Старый `registry.kube5s.ru` — 301 редирект или удалить + +### Фаза 5: Добавление остальных сервисов + +- [ ] Выявить все текущие `*.kube5s.ru` (через grep по всем репо) +- [ ] Для каждого: добавить route в gateway +- [ ] Перенести сервис за gateway +- [ ] Удалить старые DNS/Ingress/сертификаты + +--- + +## 9. ТЕКУЩИЕ ЗАПИСИ `kube5s.ru` (НАЙТИ ВСЕ) + +```bash +# Выполнить чтобы найти все использования kube5s.ru: +grep -r "kube5s\.ru" /home/naeel/ --include="*.{tf,yaml,yml,go,sh,env,js,json,md,cfg,ejs,html}" -l +``` + +**Известные на 2026-07-20:** + +| Запись | Сервис | Приоритет миграции | +|--------|--------|--------------------| +| `registry.kube5s.ru` | Terraform Registry Server | **#1 (критично)** | +| ??? | ??? | Найти grep'ом | + +--- + +## 10. КОНФИГУРАЦИЯ KUBERNETES + +### Deployment + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gateway + namespace: terra +spec: + replicas: 1 + selector: + matchLabels: + app: gateway + template: + metadata: + labels: + app: gateway + spec: + containers: + - name: gateway + image: registry.kube5s.ru/gateway:1.0.0 + ports: + - containerPort: 3000 + env: + - name: PORT + value: "3000" + - name: APP_VERSION + value: "1.0.0" + # ROUTES + - name: ROUTE_01_ID + value: "registry" + - name: ROUTE_01_PREFIX + value: "/record01" + - name: ROUTE_01_UPSTREAM + value: "http://registry-server.terra.svc.cluster.local:8080" + - name: ROUTE_01_STRIP + value: "false" + - name: ROUTE_01_TIMEOUT + value: "30000" + livenessProbe: + httpGet: + path: /healthz + port: 3000 + initialDelaySeconds: 5 + readinessProbe: + httpGet: + path: /readyz + port: 3000 + initialDelaySeconds: 3 +``` + +### Service + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: gateway + namespace: terra +spec: + ports: + - port: 80 + targetPort: 3000 + selector: + app: gateway +``` + +### Ingress + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: gateway-ingress + namespace: terra + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/proxy-body-size: "100m" +spec: + ingressClassName: nginx + tls: + - hosts: + - gateway.nodejsk8s.services.ngcloud.ru + secretName: gateway-tls + rules: + - host: gateway.nodejsk8s.services.ngcloud.ru + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: gateway + port: + number: 80 +``` + +--- + +## 11. ССЫЛКИ + +| Ресурс | URL | +|--------|-----| +| GATEWAY (production) | `https://gateway.nodejsk8s.services.ngcloud.ru/` | +| Репозиторий GATEWAY | `~/tf_provider/gateway/` (создать) или отдельный репо | +| Registry Server | `~/tf_registry/server/main.go` | +| Terraform Provider | `~/tf_provider/provider/main.go` | +| S3 (registry files) | `s3.msk-1.ngcloud.ru`, bucket `terraform-registry` | + +--- + +## 12. КОНТРОЛЬНЫЙ СПИСОК ПРИ ДОБАВЛЕНИИ НОВОГО RECORD + +1. [ ] Сервис задеплоен в K8s, есть Service +2. [ ] Сервис работает (проверить через `kubectl port-forward` или напрямую) +3. [ ] Определён `stripPrefix`: upstream знает о префиксе? (как registry) или нет? +4. [ ] Добавлен route в конфиг gateway +5. [ ] Gateway передеплоен +6. [ ] Проверен curl через gateway: `curl https://gateway...ngcloud.ru/recordXX/...` +7. [ ] Клиенты обновлены на новый URL + +--- + +*Документ создан 2026-07-20. Планирование завершено, реализация — позже.* diff --git a/tfluceecrud b/tfluceecrud index 53e12ec..7b6ab4c 160000 --- a/tfluceecrud +++ b/tfluceecrud @@ -1 +1 @@ -Subproject commit 53e12ecddd2237c70d0ddde536a7edef6e748649 +Subproject commit 7b6ab4c8b735ca7858c083f4e72a14a263c83f8f