199 lines
9.0 KiB
Markdown
199 lines
9.0 KiB
Markdown
# Terraform Registry — Полное описание
|
||
|
||
> Этот документ — точка входа для нового чата/агента. Содержит всё необходимое для понимания, сопровождения и доработки реестра провайдера.
|
||
|
||
---
|
||
|
||
## Что это такое
|
||
|
||
Кастомный Terraform Registry Server для провайдера `nubes` (облако Nubes / ngcloud.ru).
|
||
|
||
Когда разработчик пишет в своём `.tf`:
|
||
```hcl
|
||
terraform {
|
||
required_providers {
|
||
nubes = {
|
||
source = "terra.k8c.ru/nubes/nubes"
|
||
version = "5.0.18"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
...и выполняет `terraform init`, Terraform идёт к **этому** серверу за бинарниками провайдера.
|
||
|
||
---
|
||
|
||
## Структура папки
|
||
|
||
```
|
||
REGISTRY/
|
||
├── server/ — Go-код HTTP-сервера реестра (АКТУАЛЬНЫЙ)
|
||
├── operator/ — Kubernetes Operator (CRD TerraformProviderRelease) + старая копия server-кода в cmd/registry/
|
||
├── k8s/ — Kubernetes манифесты деплоя (namespace, ingress, deployment, service, TLS)
|
||
├── registrykeys/ — Go-модуль с публичным GPG-ключом (для верификации провайдера)
|
||
├── charts/ — Helm chart для деплоя registry-server
|
||
└── scripts/
|
||
└── build-and-push-registry-server.sh — сборка Docker-образа и push в registry
|
||
```
|
||
|
||
**Важно:** `server/` и `operator/cmd/registry/` — дублирующийся код. Актуальный и полный — только `server/main.go`. В `operator/cmd/registry/main.go` нет health-эндпоинтов и не удалены darwin-платформы. При правках менять только `server/`.
|
||
|
||
---
|
||
|
||
## Как работает registry-server
|
||
|
||
### Реализованный протокол
|
||
|
||
[Terraform Registry Protocol v1](https://developer.hashicorp.com/terraform/internals/provider-registry-protocol).
|
||
|
||
| Эндпоинт | Назначение |
|
||
|---|---|
|
||
| `GET /.well-known/terraform.json` | Discovery — говорит Terraform, где API реестра |
|
||
| `GET /v1/providers/{ns}/{name}/versions` | Список доступных версий и платформ |
|
||
| `GET /v1/providers/{ns}/{name}/{version}/download/{os}/{arch}` | URL для скачивания бинарника |
|
||
| `GET /v1/proxy?url=...` | Проксирование файлов из S3 (бинарники, SHA, GPG-сигнатура) |
|
||
| `GET /docs/{ns}/{name}/{version}/...` | Документация провайдера (статический HTML из S3) |
|
||
| `GET /healthz` | Health probe для Kubernetes |
|
||
| `GET /readyz` | Readiness probe для Kubernetes |
|
||
|
||
### Как определяются версии
|
||
|
||
Сервер листит S3 bucket в поиске файлов вида:
|
||
```
|
||
<hostname>/<namespace>/<name>/<version>/terraform-provider-<name>_<version>_linux_amd64.zip
|
||
```
|
||
Из имён файлов парсит версию и платформы. Поддерживаемые платформы: `linux_amd64`, `linux_arm64`, `windows_amd64`.
|
||
|
||
### Переменные окружения
|
||
|
||
| Переменная | Default | Назначение |
|
||
|---|---|---|
|
||
| `REGISTRY_HOSTNAME` | `localhost:8080` | Домен реестра (используется в URL ответов) |
|
||
| `S3_ENDPOINT` | — | Хост S3 без схемы, например `s3.msk-1.ngcloud.ru` |
|
||
| `S3_ACCESS_KEY` | — | S3 access key |
|
||
| `S3_SECRET_KEY` | — | S3 secret key |
|
||
| `S3_BUCKET` | `terraform-registry` | Имя бакета |
|
||
| `S3_USE_SSL` | — | Если `true` — HTTPS (в коде Secure: true захардкожено) |
|
||
|
||
### S3 структура бакета
|
||
|
||
```
|
||
terraform-registry/ ← бакет
|
||
└── terra.k8c.ru/
|
||
└── nubes/
|
||
└── nubes/
|
||
└── 5.0.18/
|
||
├── terraform-provider-nubes_5.0.18_linux_amd64.zip
|
||
├── terraform-provider-nubes_5.0.18_windows_amd64.zip
|
||
├── terraform-provider-nubes_5.0.18_SHA256SUMS
|
||
└── terraform-provider-nubes_5.0.18_SHA256SUMS.sig
|
||
docs/
|
||
└── nubes/
|
||
└── nubes/
|
||
└── 5.0.18/
|
||
└── index.html (и другие файлы документации)
|
||
```
|
||
|
||
---
|
||
|
||
## GPG-ключ
|
||
|
||
Terraform верифицирует подпись провайдера через GPG.
|
||
|
||
- Публичный ключ **встроен** в `server/main.go` (ASCII Armor, константа в коде).
|
||
- Также хранится в `registrykeys/public_key.go` (отдельный go-модуль).
|
||
- Приватный ключ — `secrets/private_key.asc` (НЕ в репо, gitignore).
|
||
|
||
**При ротации ключей:**
|
||
1. Сгенерировать новую пару `gpg --gen-key`
|
||
2. Обновить ASCII Armor в `server/main.go`
|
||
3. Пересобрать и передеплоить Docker-образ
|
||
4. Перезалить все артефакты провайдера, подписанные новым ключом
|
||
|
||
---
|
||
|
||
## Деплой в Kubernetes
|
||
|
||
### Кластер и namespace
|
||
|
||
- Namespace: `terra`
|
||
- Домен: `terra.k8c.ru` (планируемая миграция → `registry.nubes.ru`, см. `../docs/ops/DOMAIN_MIGRATION.md`)
|
||
- TLS: cert-manager с `letsencrypt-prod` issuer — **НЕ ТРОГАТЬ** сертификат руками!
|
||
|
||
### Что задеплоено
|
||
|
||
| Ресурс | Kind | Образ |
|
||
|---|---|---|
|
||
| `registry-server` | Deployment | `naeel/terraform-registry-server:gpg-key-20260208` |
|
||
| `registry-server` | Service | ClusterIP :8080 |
|
||
| `registry-ingress` | Ingress | host: `terra.k8c.ru` |
|
||
|
||
Credentials S3 — из секрета `s3-credentials` (ключи `access-key`, `secret-key`).
|
||
|
||
### Применение манифестов (только при смене конфигурации кластера)
|
||
|
||
```bash
|
||
kubectl apply -f k8s/operator/manifests/00-namespace.yaml
|
||
kubectl apply -f k8s/operator/manifests/00-rbac.yaml
|
||
kubectl apply -f k8s/operator/manifests/02-crd.yaml
|
||
kubectl apply -f k8s/operator/manifests/05-registry-server.yaml
|
||
```
|
||
|
||
### Диагностика (read-only)
|
||
|
||
```bash
|
||
kubectl -n terra get pods,svc,ingress,deploy
|
||
kubectl -n terra logs -l app=registry-server --tail=50
|
||
kubectl -n terra get certificate registry-tls -o yaml
|
||
```
|
||
|
||
---
|
||
|
||
## Сборка и публикация нового образа
|
||
|
||
Скрипт: `scripts/build-and-push-registry-server.sh`
|
||
|
||
```bash
|
||
cd REGISTRY
|
||
./scripts/build-and-push-registry-server.sh
|
||
```
|
||
|
||
Собирает Docker-образ из `server/` и пушит в Docker Hub (`naeel/terraform-registry-server:<tag>`).
|
||
|
||
После push нужно обновить тег образа в `operator/manifests/05-registry-server.yaml` и применить `kubectl apply`.
|
||
|
||
---
|
||
|
||
## Когда registry НЕ нужно трогать
|
||
|
||
Registry — stateless сервис. При выпуске новой версии провайдера (`nubes`) registry не меняется:
|
||
|
||
```
|
||
Новая версия провайдера:
|
||
1. go build → бинарники
|
||
2. devops/03_build_and_upload_provider.sh → бинарники в S3
|
||
3. devops/04_build_and_publish_docs.sh → документация в S3
|
||
✅ Registry автоматически начинает отдавать новую версию
|
||
❌ kubectl не нужен
|
||
❌ код registry не меняется
|
||
❌ Docker-образ не пересобирается
|
||
```
|
||
|
||
Registry пересобирается только если меняется **сам сервер**: новые эндпоинты, логика, ротация GPG-ключа.
|
||
|
||
---
|
||
|
||
## Связь с основным репо провайдера
|
||
|
||
Этот код был перемещён из основного репо `terraform/` в папку `REGISTRY/` для последующего выноса в отдельный репозиторий. Код провайдера и код реестра полностью независимы — нет общих go-модулей, нет импортов друг друга.
|
||
|
||
---
|
||
|
||
## Ограничения и правила работы
|
||
|
||
- **Ручные правки `operator/cmd/registry/`** — не делать, это устаревшая копия. Актуальный код — только `server/`.
|
||
- **Let's Encrypt cert-manager** (`letsencrypt-prod`) — не применять `kubectl apply` на Ingress-ресурсы без именённой необходимости (риск бана от CA).
|
||
- **docker build** — только с явного разрешения разработчика.
|
||
- **kubectl** — только read-only (`get`, `describe`, `logs`) без разрешения.
|
||
- **S3 credentials** — никогда не коммитить в репо. Только через секреты k8s или переменные окружения.
|