Files
tf_registry/HISTORY/direct-S3-load.md
2026-09-01 12:24:23 +03:00

10 KiB
Raw Permalink Blame History

Список задач обновлен

Проверялись следующие endpoint’ы registry:

https://tf-registry.containerk8s.services.ngcloud.ru/.well-known/terraform.json

Результат: HTTP 200

{"providers.v1":"/v1/providers/"}

Список версий:

https://tf-registry.containerk8s.services.ngcloud.ru/v1/providers/nubes-test/nubes/versions

Результат: HTTP 200

Опубликованы:

5.0.1
5.0.2
5.0.3
5.0.4
5.0.5
5.1.17

Download metadata для 5.0.5:

https://tf-registry.containerk8s.services.ngcloud.ru/v1/providers/nubes-test/nubes/5.0.5/download/linux/amd64

Результат: HTTP 200, ответ около 8 KB, содержит:

filename:
terraform-provider-nubes_5.0.5_linux_amd64.zip

download_url:
https://tf-registry.containerk8s.services.ngcloud.ru/v1/proxy?key=...

Фактический proxy URL:

https://tf-registry.containerk8s.services.ngcloud.ru/v1/proxy?key=tf-registry.containerk8s.services.ngcloud.ru%2Fnubes-test%2Fnubes%2F5.0.5%2Fterraform-provider-nubes_5.0.5_linux_amd64.zip

Проверка proxy:

HTTP: 200
Content-Type: application/octet-stream
Content-Length: 13083236

Но фактически за 40 секунд скачалось только:

20983 байт

и затем:

curl: (28) Operation timed out

Дополнительно проверялись:

nubes-test/nubes:5.1.17
nubes/nubes:2.0.6

На них результат такой же: metadata отдается быстро, а ZIP через /v1/proxy обрывается примерно на 1823 KB.

Проверялся также заголовок:

Range: bytes=0-1023

и диапазон из середины файла:

Range: bytes=1048576-1049599

Proxy игнорирует Range, отвечает HTTP 200 и снова начинает отдавать весь файл, после чего передача зависает.

Проверка DNS:

getent hosts tf-registry.containerk8s.services.ngcloud.ru

Результат:

5.172.178.231

Также проверялся Kubernetes API:

kubectl get ingress -A
kubectl get pods -A
kubectl get svc -A
kubectl get deploy -A
kubectl get configmap -A

Но текущий kubeconfig не имеет credentials:

the server has asked for the client to provide credentials
Unauthorized

Итог: API registry и metadata работают. Проблемный участок:

/v1/proxy -> S3 object -> HTTP streaming через Kubernetes

Именно там большой ZIP возвращается с HTTP 200, но поток фактически обрывается на десятках килобайт.

Список задач обновлен

Read

Read memory

Read , lines 1 to 80

Read , lines 1 to 80

Read , lines 1 to 80

Теперь у меня есть контекст по drhider. Давай сравню симптомы:

Read

Read

Анализ: сравнение проблем drhider и registry

Проблема в drhider (решена)

Аспект Детали
Симптом POST из браузера → тело запроса обрывалось на ~64КБ (HTTP 000, ~10с)
Направление Входящий трафик: браузер → кластер
Корень Managed-кластер, шлюз ingress обрывает тела входящих запросов >64КБ
Решение Браузер PUT файл на ВМ-буфер (обходит шлюз) → Flask тянет с ВМ (egress, без лимита)

Проблема в registry (сейчас)

Аспект Детали
Симптом GET /v1/proxy?key=... → HTTP 200 мгновенно, но данные обрываются на 18–23 КБ
Направление Исходящий трафик: кластер → Terraform клиент
Корень Тот же кластерный шлюз, но теперь режет streaming-ответ (буферизация / flush-лимит)

Это та же проблема?

Да, вероятно одна и та же инфраструктура (services.ngcloud.ru — managed Nubes, тот же managed-кластер что и pythonk8s.dev.nubes.ru). Только направление противоположное:

  • drhider: шлюз режет входящее тело
  • registry: шлюз режет исходящий stream большого файла

Дополнительный признак: у вас есть ещё одна задокументированная проблема — HTTP/2 резал git push к gitea (тот же шлюз, тот же паттерн). Range-запросы игнорируются — тоже поведение промежуточного буферизующего прокси.


Применим ли обход через ВМ?

Да, но схема зеркальная. В drhider проблема была на входе — данные шли в кластер. Здесь проблема на выходе — данные идут из кластера к Terraform.

Варианты обхода:

Вариант A — Redirect на S3 pre-signed URL (чище всего)

/v1/proxy вместо стриминга генерирует временную pre-signed S3 ссылку и возвращает 302 Location: <s3-presigned-url>. Terraform следует редиректу и скачивает ZIP напрямую с S3, минуя кластерный шлюз полностью.

Terraform → /v1/proxy?key=... → 302 Location: https://s3.../object?X-Amz-Expires=...
Terraform → S3 напрямую → 200 + 13MB ✅

Terraform go-getter (используется в terraform init) редиректы поддерживает.

Вариант B — Redirect на ВМ-прокси

Если S3 не публичный / нет pre-signed URL — /v1/proxy отдаёт 302 на эндпоинт ВМ (contracts.kube5s.ru/tf-proxy?key=...). ВМ скачивает файл с S3 и стримит Terraform клиенту. ВМ находится вне шлюза managed-кластера.

Вариант C — Через download_url в metadata (самое прозрачное)

Вместо того чтобы download_url указывал на /v1/proxy внутри кластера — указывать сразу на S3 pre-signed URL или ВМ-прокси. Не нужно менять /v1/proxy вообще.


Рекомендация

Вариант A или C — наиболее чистые. Смотреть, есть ли доступ к S3 с кредами для pre-signed URL из кода registry. Если есть — минимальное изменение: в /v1/proxy заменить стриминг на redirect(presigned_url, 302).

Нужно смотреть код registry (/v1/proxy handler) чтобы подтвердить технически — он в этом же репозитории или в отдельном?

Создано задач: 3

Список задач обновлен

Read

Read

Read

Read

Read

Read

Read

Картина полная. Вот анализ:


Диагностика: та же проблема, другая сторона

Код проблемы — proxy.go, proxyHandler:

obj, _ := s3Client.GetObject(ctx, bucketName, key, ...)
io.Copy(w, obj)  // ← Kubernetes шлюз режет этот stream

Тот же managed-кластер (containerk8s.services.ngcloud.ru — Nubes), тот же шлюз. В drhider он резал входящие тела >64KB. Здесь режет исходящий stream с S3 (~18–23KB — это первый буфер ответа, который шлюз успел пропустить до блокировки).

Content-Length: 13083236 выставляется, но данных доходит ~20KB — шлюз буферизует и не флашит остаток.


Решение: presigned URL redirect

minio-go уже импортирован, он умеет генерировать pre-signed URL:

// вместо GetObject + io.Copy:
presigned, err := s3Client.PresignedGetObject(ctx, bucketName, key, 15*time.Minute, url.Values{})
http.Redirect(w, r, presigned.String(), http.StatusFound)

Terraform следует 302. Terraform client скачивает ZIP напрямую с S3, кластерный шлюз больше не участвует.

Это затрагивает только proxy.go — 1 файл, примерно 10 строк замены.

ShasumsURL и ShasumsSignatureURL тоже идут через /v1/proxy — они маленькие (<10KB), работают и сейчас, но с redirect тоже будут работать корректно.


План

Файл: server/proxy.go

Изменение: в proxyHandler — убрать GetObject / Stat / io.Copy / установку заголовков, заменить на PresignedGetObject + http.Redirect 302. Добавить "net/url" в imports.

Верификация:

  1. go build nubes. — компиляция
  2. curl -v 'https://...registry.../v1/proxy?key=...' -L — должен получить 302, затем скачать 13MB полностью
  3. terraform init в тестовом проекте с этим провайдером

Делать?

Создано задач: 4

НИЧЕГО НЕ ДЕЛАЙ. КРАТКО ОТВЕТ ДАВАЙ - это надо менять код регистри ? и всё ?

10:03 Да. Только server/proxy.go — заменить стриминг на redirect к pre-signed S3 URL. Больше ничего.