add: documentation

This commit is contained in:
“Naeel”
2026-06-30 15:45:24 +04:00
parent 540c1f7293
commit ca276d200f
1055 changed files with 47294 additions and 0 deletions
+638
View File
@@ -0,0 +1,638 @@
# План миграции в Nubes Managed Kubernetes — Инструкции для агента
**Создан:** 2026-03-13 (Opus 4.6)
**Исполнитель:** Sonnet 4.6
**Статус:** Ожидает исполнения
> **ВАЖНО:** Этот документ — пошаговый план. Каждый пункт содержит:
> - ЧТО делать (цель)
> - ГДЕ делать (файлы)
> - КАК делать (конкретные инструкции)
> - ОГРАНИЧЕНИЯ (что нельзя трогать)
---
## Контекст
Terraform-провайдер Nubes Cloud сейчас работает на self-managed K8s (terra.k8c.ru).
Цель: подготовить инфраструктуру к передаче в Nubes Managed Kubernetes под управление их DevOps.
Nubes (nubes.ru) — российский cloud-провайдер, собственный DC Tier III (Москва), имеет Managed K8s, Harbor, S3.
**Репозиторий:** `/home/naeel/remote_dev/terraform`
**Обязательно прочитать перед работой:**
- `REPO_CONTENTS.md` — карта репозитория
- `.github/copilot-instructions.md` — правила работы (IMMUTABILITY POLICY)
- `docs/CODEBASE_ANALYSIS_AND_ROADMAP.md` — анализ кодовой базы
---
## Группа A: Подготовительные задачи (делать ПЕРВЫМИ)
### A1. Helm Chart для всех K8s-манифестов
**Цель:** Конвертировать raw YAML манифесты в Helm chart.
**Исходные файлы (ТОЛЬКО ЧИТАТЬ, НЕ МЕНЯТЬ):**
- `k8s/registry-deployment-new.yaml`
- `k8s/registry-ingress-new.yaml`
- `operator/manifests/00-namespace.yaml`
- `operator/manifests/00-rbac.yaml`
- `operator/manifests/02-crd.yaml`
- `operator/manifests/03-build-script.yaml`
- `operator/manifests/04-operator-deployment.yaml`
- `operator/manifests/05-registry-server.yaml`
- `operator/manifests/06-registry-server-docs.yaml`
**Создать:**
```
charts/
terraform-registry/
Chart.yaml
values.yaml
values-dev.yaml
values-prod.yaml
templates/
_helpers.tpl
namespace.yaml
rbac.yaml
crd.yaml
build-script-configmap.yaml
operator-deployment.yaml
registry-server-deployment.yaml
registry-server-service.yaml
docs-server-deployment.yaml (optional)
ingress.yaml
pdb.yaml
networkpolicy.yaml
```
**Требования к `values.yaml`:**
```yaml
global:
registryHostname: "terra.k8c.ru" # Переопределяется при миграции
namespace: "terraform-registry"
registry:
image:
repository: "naeel/terraform-registry-server" # → Harbor при миграции
tag: "latest"
pullPolicy: IfNotPresent
replicas: 1 # → 2 в prod
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
service:
port: 80
targetPort: 8080
healthcheck:
enabled: true
path: /healthz
port: 8080
operator:
image:
repository: "naeel/terraform-registry-operator"
tag: "latest"
replicas: 1
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 128Mi
ingress:
enabled: true
className: "nginx"
host: "terra.k8c.ru" # Переопределяется
tls:
enabled: true
issuer: "letsencrypt-prod" # НЕ ТРОГАТЬ LetsEncrypt issuer!
secretName: "registry-tls"
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
s3:
endpoint: "s3.msk-1.ngcloud.ru"
bucket: "terraform-registry"
useSSL: true
# credentials через existingSecret
existingSecret: "s3-credentials"
accessKeyField: "access-key"
secretKeyField: "secret-key"
pdb:
enabled: false # → true в prod
minAvailable: 1
networkPolicy:
enabled: false # → true при миграции
```
**Требования к `values-dev.yaml`:**
```yaml
global:
registryHostname: "terra.k8c.ru"
registry:
replicas: 1
pdb:
enabled: false
```
**Требования к `values-prod.yaml`:**
```yaml
global:
registryHostname: "registry.nubes.ru" # Целевой домен
registry:
image:
repository: "pearlharbor.registryk8s.services.ngcloud.ru/terraform/registry-server"
replicas: 2
operator:
image:
repository: "pearlharbor.registryk8s.services.ngcloud.ru/terraform/registry-operator"
pdb:
enabled: true
minAvailable: 1
networkPolicy:
enabled: true
```
**Ограничения:**
- НЕ менять исходные YAML в `k8s/` и `operator/manifests/` (они могут ещё использоваться)
- НЕ трогать CRD-ресурсы с LetsEncrypt issuerRef
- НЕ запускать `helm install/upgrade` — только создать файлы
- Helm chart — НОВЫЕ файлы в `charts/` (APPEND ONLY)
---
### A2. Externalize hardcoded values
**Цель:** Убрать все hardcoded пути и домены, заменить на env vars.
**Файл 1: `internal/core/client.go` строка ~18**
```go
// СЕЙЧАС:
f, err := os.OpenFile("/home/naeel/terra/debug_nubes.log", ...)
// НОВЫЙ КОД (добавить новую функцию в КОНЕЦ файла):
func debugLogPath() string {
if p := os.Getenv("NUBES_DEBUG_LOG"); p != "" {
return p
}
return filepath.Join(os.TempDir(), "nubes_debug.log")
}
```
**Ограничение:** НЕ менять строку 18 напрямую. Добавить функцию `debugLogPath()` в КОНЕЦ файла. Спросить оператора перед заменой вызова.
**Файл 2: `internal/provider/provider.go` строка ~103**
```go
// СЕЙЧАС:
InsecureSkipVerify: true,
// НУЖНО: Сделать конфигурируемым через provider schema + env var
```
**Инструкция:**
1. Добавить атрибут `insecure` в schema провайдера (Optional, bool, default false)
2. Добавить чтение env var `NUBES_INSECURE`
3. InsecureSkipVerify = config_value || env_value || false
4. Код добавлять В КОНЕЦ секции Configure(), не рефакторить существующий
**Файл 3: `universal_rebuild/internal/provider/provider.go`**
- Проверить аналогичную проблему с InsecureSkipVerify
- Применить тот же паттерн
**Ограничения:**
- НЕ менять сигнатуры существующих функций
- Новый код — APPEND ONLY
- InsecureSkipVerify=false по умолчанию (breaking change для текущих юзеров — СПРОСИТЬ оператора)
---
### A3. Health endpoints для registry-server
**Цель:** Добавить `/healthz`, `/readyz`, `/metrics` endpoints.
**Файл:** `registry-server-build/main.go`
**Инструкция:**
1. Прочитать текущий `main.go` полностью
2. Добавить в КОНЕЦ файла (новые handler-функции):
```go
func healthzHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
func readyzHandler(w http.ResponseWriter, r *http.Request) {
// Проверить доступность S3
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
```
3. Зарегистрировать handlers в main() — СПРОСИТЬ оператора перед добавлением в mux
**Ограничения:**
- НЕ менять существующие handlers
- НЕ запускать docker build
- Новые функции — APPEND ONLY
---
### A4. Operaционная документация
**Цель:** Создать набор операционных документов для DevOps Nubes.
**Создать файлы:**
**`docs/ops/RUNBOOK.md`:**
```markdown
# Runbook: Terraform Provider Registry
## Предпосылки
- Kubernetes cluster ≥ 1.27
- Helm ≥ 3.12
- Доступ к S3 (s3.msk-1.ngcloud.ru)
- Harbor registry (для образов)
## Установка
helm install terraform-registry ./charts/terraform-registry \
-f charts/terraform-registry/values-prod.yaml \
-n terraform-registry --create-namespace
## Обновление версии
1. Собрать новый образ (CI pipeline)
2. Обновить tag в values
3. helm upgrade terraform-registry ./charts/terraform-registry -f values-prod.yaml
## Проверка здоровья
kubectl -n terraform-registry get pods
curl https://<REGISTRY_HOST>/healthz
curl https://<REGISTRY_HOST>/.well-known/terraform.json
## Компоненты
- Registry Server — HTTP-сервер протокола Terraform Registry
- Operator — K8s controller для сборки provider binaries
- S3 — хранилище артефактов (бинарники + документация)
```
**`docs/ops/TROUBLESHOOTING.md`:**
```markdown
# Troubleshooting
## Registry Server не отвечает
1. kubectl -n terraform-registry get pods -l app=registry-server
2. kubectl -n terraform-registry logs -l app=registry-server --tail=100
3. Проверить ingress: kubectl get ingress -n terraform-registry
4. Проверить S3: curl -s https://s3.msk-1.ngcloud.ru (bucket access)
## Provider binary не скачивается
1. Проверить наличие в S3: s3cmd ls s3://terraform-registry/terraform-providers/...
2. Проверить SHA256SUMS сигнатуру
3. Проверить GPG ключ
## Operator не создаёт build job
1. kubectl -n terraform-registry get terraformproviderrelease
2. kubectl -n terraform-registry describe terraformproviderrelease <name>
3. kubectl -n terraform-registry get jobs
4. Проверить RBAC: operator ServiceAccount должен иметь права на jobs и secrets
## TLS / Certificate проблемы
- Проверить cert-manager: kubectl get certificates -n terraform-registry
- ⚠️ НЕ пересоздавать certificates с LetsEncrypt issuer (rate limits!)
- Для отладки использовать self-signed issuer
```
**`docs/ops/MONITORING.md`:**
```markdown
# Мониторинг
## Ключевые метрики
- registry_http_requests_total — кол-во запросов к registry
- registry_http_request_duration_seconds — latency
- registry_s3_operations_total — операции с S3
- registry_s3_errors_total — ошибки S3
## Алерты (Prometheus)
- RegistryDown: up == 0 (>2 min)
- RegistryHighLatency: p99 > 5s (>5 min)
- RegistryS3Errors: rate > 0.1/s (>5 min)
- RegistryPodRestart: увеличение restart count
## Grafana Dashboard
- Import dashboard ID: (создать при установке мониторинга)
```
**`docs/ops/UPGRADE.md`:**
```markdown
# Процедура обновления
## Provider version update (без downtime)
1. CI собирает новый provider binary
2. Создать TerraformProviderRelease CR с новой версией
3. Operator создаёт build job → артефакты в S3
4. Старые версии остаются доступны (immutable artifacts)
## Registry Server update (rolling)
1. Обновить image tag в Helm values
2. helm upgrade --set registry.image.tag=<new> terraform-registry ./charts/...
3. Проверить: kubectl rollout status deployment/registry-server -n terraform-registry
4. Rollback: helm rollback terraform-registry 1
## Operator update
1. Обновить operator image tag
2. helm upgrade ...
3. Проверить CRD compatibility: kubectl get crd terraformproviderreleases.terra.core.nubes.ru
```
**`docs/ops/ROLLBACK.md`:**
```markdown
# Процедура отката
## Helm rollback
helm rollback terraform-registry <revision>
helm history terraform-registry -n terraform-registry
## Emergency: Direct image rollback
kubectl -n terraform-registry set image deployment/registry-server \
registry-server=<HARBOR>/terraform/registry-server:<PREV_TAG>
## S3 artifacts (immutable — откат не нужен)
Все версии provider binary хранятся бессрочно.
Удаление только вручную через s3cmd.
```
---
## Группа B: Инфраструктурная подготовка
### B1. Dockerfile оптимизация
**Цель:** Убедиться что Dockerfile для registry-server и operator готовы к Harbor.
**Инструкция:**
1. Прочитать `registry-server-build/` и `operator/build/`
2. Проверить что Dockerfile использует multi-stage build
3. Проверить что нет hardcoded путей
4. Убедиться что base image — official (golang:1.24 + alpine/scratch)
5. НЕ запускать docker build — только проверить файлы
**Создать (если отсутствует):** `registry-server-build/.dockerignore`, `operator/.dockerignore`
---
### B2. CI Pipeline definition
**Цель:** Создать файл CI pipeline (GitLab CI / Tekton) для автосборки.
**Создать:** `devops/ci/pipeline.yaml`
```yaml
# GitLab CI - пример (адаптировать под конкретный CI Nubes)
stages:
- test
- build
- sign
- publish
variables:
HARBOR_HOST: "pearlharbor.registryk8s.services.ngcloud.ru"
S3_BUCKET: "terraform-registry"
PROVIDER_NAME: "nubes"
PROVIDER_NAMESPACE: "nubes"
test:
stage: test
image: golang:1.24
script:
- cd universal_rebuild
- go test ./...
- go vet ./...
build-provider:
stage: build
image: golang:1.24
script:
- cd universal_rebuild
- GOOS=linux GOARCH=amd64 go build -o bin/terraform-provider-${PROVIDER_NAME}_linux_amd64
- GOOS=darwin GOARCH=amd64 go build -o bin/terraform-provider-${PROVIDER_NAME}_darwin_amd64
- GOOS=windows GOARCH=amd64 go build -o bin/terraform-provider-${PROVIDER_NAME}_windows_amd64.exe
artifacts:
paths: [universal_rebuild/bin/]
build-images:
stage: build
script:
- docker build -t ${HARBOR_HOST}/terraform/registry-server:${CI_COMMIT_TAG} registry-server-build/
- docker build -t ${HARBOR_HOST}/terraform/registry-operator:${CI_COMMIT_TAG} operator/
- docker push ${HARBOR_HOST}/terraform/registry-server:${CI_COMMIT_TAG}
- docker push ${HARBOR_HOST}/terraform/registry-operator:${CI_COMMIT_TAG}
sign:
stage: sign
script:
- cd universal_rebuild/bin
- sha256sum terraform-provider-* > SHA256SUMS
- gpg --import $GPG_PRIVATE_KEY
- gpg --detach-sign SHA256SUMS
publish-to-s3:
stage: publish
script:
- s3cmd put bin/* s3://${S3_BUCKET}/terraform-providers/...
```
---
### B3. NetworkPolicy template
**Цель:** Подготовить NetworkPolicy для изоляции namespace.
**Включить в Helm chart:** `charts/terraform-registry/templates/networkpolicy.yaml`
```yaml
{{- if .Values.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "terraform-registry.fullname" . }}-netpol
namespace: {{ .Values.global.namespace }}
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- port: {{ .Values.registry.service.targetPort }}
protocol: TCP
egress:
- to: []
ports:
- port: 443 # S3, Vault
protocol: TCP
- port: 53 # DNS
protocol: UDP
- port: 53
protocol: TCP
{{- end }}
```
---
## Группа C: Domain Migration Plan
### C1. Domain migration (порядок действий)
**Это НЕ код — это инструкция для DevOps. Записать в `docs/ops/DOMAIN_MIGRATION.md`:**
```markdown
# Миграция домена terra.k8c.ru → registry.nubes.ru
## Фаза 1: Dual-domain (параллельная работа)
1. Настроить Ingress с двумя hosts: terra.k8c.ru + registry.nubes.ru
2. Оба домена указывают на один Registry Server
3. Обновить provider main.go: Address → registry.nubes.ru
4. Старый адрес terra.k8c.ru продолжает работать
## Фаза 2: Миграция клиентов
1. Документировать новый registry address для пользователей
2. .terraformrc mirror config для переходного периода:
provider_installation {
direct {
exclude = ["terra.k8c.ru/*/*"]
}
network_mirror {
url = "https://registry.nubes.ru/v1/providers/"
}
}
## Фаза 3: Редирект
1. terra.k8c.ru Ingress → 301 redirect на registry.nubes.ru
2. Мониторинг: отслеживать запросы на старый домен
## Фаза 4: Деком (через 6+ месяцев)
1. Убрать terra.k8c.ru из Ingress
2. DNS → удалить A/CNAME запись
```
---
## Группа D: Code Quality (из CODEBASE_ANALYSIS_AND_ROADMAP.md)
### D1. Deprecated-маркеры для legacy CreateGenericInstance
**Файл:** `internal/core/client.go`
**Инструкция:** Добавить КОММЕНТАРИИ (не код) перед каждым методом V1-V5:
```go
// Deprecated: Use CreateGenericInstanceUniversalV5 instead.
// This method is kept for backward compatibility and will be removed in v3.0.
func (c *UniversalClient) CreateGenericInstance(...) ...
```
**Методы для пометки:**
- `CreateGenericInstance` (V1)
- `CreateGenericInstanceUniversal` (V2)
- `CreateGenericInstanceUniversalV2` (V3)
- `CreateGenericInstanceUniversalV3` (V4)
- `CreateGenericInstanceUniversalV4` (V5)
**Ограничения:** ТОЛЬКО комментарии. НЕ менять код методов. НЕ удалять.
---
### D2. .gitignore для secrets
**Файл:** `.gitignore` (корень репозитория)
**Добавить в КОНЕЦ файла:**
```gitignore
# Secrets (should be in Vault, not in git)
secrets/*.asc
secrets/*.token
secrets/*.key
!secrets/.gitkeep
```
**Создать:** `secrets/.gitkeep` (пустой файл, чтобы директория осталась в git)
---
### D3. Unit tests для core layer
**Цель:** Создать минимальный набор тестов.
**Создать файлы:**
- `universal_rebuild/internal/core/client_test.go`
- `universal_rebuild/internal/resources_core/crud_test.go`
**Минимальные тесты для `client_test.go`:**
- `TestNormalizeValue_EmptyString`
- `TestNormalizeValue_NullString`
- `TestNormalizeValue_MapType`
- `TestNormalizeValue_ArrayType`
- `TestNormalizeValue_TrimSpace`
**Минимальные тесты для `crud_test.go`:**
- `TestIsStatusSuspended`
- `TestIsStatusNonAdoptable`
- `TestDeleteBehaviorDefault`
**Ограничения:**
- Тесты — НОВЫЕ файлы (не менять существующие)
- Использовать стандартный `testing` пакет Go
- НЕ запускать тесты (`go test`) без разрешения оператора
---
## Порядок выполнения
```
ФАЗА 0 (быстрые wins):
D1 → Deprecated комментарии [5 мин]
D2 → .gitignore для secrets [2 мин]
A2 → debugLogPath() function [10 мин]
ФАЗА 1 (Helm chart):
A1 → Полный Helm chart [30-60 мин]
ФАЗА 2 (Ops docs):
A4 → RUNBOOK, TROUBLESHOOTING и др. [20 мин]
C1 → DOMAIN_MIGRATION.md [10 мин]
ФАЗА 3 (Code quality):
D3 → Unit tests [30 мин]
A3 → Health endpoints [15 мин]
ФАЗА 4 (CI/CD):
B2 → CI pipeline definition [15 мин]
B1 → Dockerfile audit [10 мин]
```
---
## Правила для агента (напоминание)
1. **IMMUTABILITY POLICY** — НЕ менять существующий рабочий код
2. **APPEND ONLY** — новый код только в конец файла
3. **Комментарии — ЭТО НЕ ПРАВКА КОДА**, их можно и нужно добавлять
4. **НЕ запускать** docker build, kubectl apply, helm install
5. **НЕ трогать** ресурсы с LetsEncrypt issuerRef
6. **Спрашивать разрешения** перед изменением сигнатур функций
7. **Secrets в коде** — КАТЕГОРИЧЕСКИ нет
8. **Перед любой работой** — прочитать `REPO_CONTENTS.md`
9. **Файлы в `internal/resources_gen/`** — НЕ МЕНЯТЬ ВРУЧНУЮ (только через генератор)
10. **Минимальные ресурсы** — при создании K8s ресурсов ставить минимальный CPU/memory