Files
tf_provider/docs/MIGRATION_PLAN_FOR_AGENT.md
2026-06-30 15:45:24 +04:00

639 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# План миграции в 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