Files
SQS-service/HISTORY/2026-10-10-session-log.md
T

15 KiB
Raw Blame History

История правок shared-sqs — 2026-10-10 (публичная точка на ВМ, TLS, замеры)

Запись по требованию «документировать всё, включая собственные ошибки» (приказ 2026-09-24). Предыдущие: HISTORY/2026-10-07-session-log.md, doc/thinking/*-2026-10-08.md. Сессия велась двумя моделями: сначала DeepSeek Flash, затем DeepSeek Pro (архитектор) — Pro перепроверял выводы Flash, часть из них оказалась неверной (см. раздел 4).

1. Задача

Вынести публичную точку SQS на ВМ 5.172.178.213 (обход больного managed-шлюза) и проверить гипотезу из MANUAL-NEXT-2026-10-08.md (Шаг 1): нет ли на пути «интернет → ВМ» той же сетевой болезни (зависания ~51 с, таймауты 31–33 с). Требования владельца по пути: домен — только свой (sinefo.ru); kube5s из проекта убрать.

2. Хронология (что делалось и что получалось)

2.1. Сборка и запуск на ВМ

  • make build → shared-sqs v0.1.35 (статический, x86_64, 17 МБ).
  • scp → naeel@5.172.178.213:~/sqs-test/shared-sqs.
  • Запуск memory-only: SHARED_SQS_SEED_DEMO=true ./shared-sqs --admin-token=dev-token-123 --port=4100.
  • Локально на ВМ: /health → 200 {"status":"ok","version":"v0.1.35"}; ListQueues без подписи → 403 MissingAuthenticationToken (корректно).
  • ⚠️ Предупреждение Failure to find default config file — goaws.yaml на ВМ нет, приложение работает на встроенных дефолтах (см. 5.1).

2.2. Разведка ВМ

  • Публичный адрес — 5.172.178.213 (NAT); внутренний 10.10.102.21 (ens192), hostname naeel-vm.
  • Снаружи прилетают только 80/443. Проверка портов:
    • 8443 — занят DNAT: iptables -t nat: --dport 8443 -j DNAT --to-destination 95.179.252.111:443 (сервис vpn-transit-dnat, enabled/active) → весь трафик на 8443 уходит на Vultr до ВМ.
    • 8888/9443 — /dev/tcp показывает «OPEN», но локально никто не слушает и HTTP не отвечает (curl timeout) → это SYN-proxy провайдерского firewall, порты непригодны.
  • /etc/hosts на ВМ содержит внутренние имена: gitea.mgmt.nubes.ru, sqs.containerk8s.dev.nubes.ru → 185.247.187.151, tf-registry.containerk8s.services.ngcloud.ru, s3.msk-1.ngcloud.ru. Резолвер ВМ — публичный (8.8.8.8, 1.1.1.1), поэтому имена *.services.ngcloud.ru не резолвятся.

2.3. Блокер nginx (возник 10-08, снят 10-10)

  • 10-08: sudo nginx -t падал: host not found in upstream "contractor.pythonk8s.services.ngcloud.ru" in sites-enabled/check.kube5s.ru:44 — внутреннее имя не резолвится.
  • 10-10 (после ребута ВМ): конфиг check.kube5s.ru оказался изменён (catch-all location / на contractor убран, добавлен location /rf) → nginx -t проходит, nginx перезагружаем.
  • Следствие: переход к рабочему пути упростился (сначала была построена схема со вторым nginx, см. 2.4).

2.4. Второй nginx на 10443 (сделан, затем убран)

  • Владелец пробросил порт: firewall [22, 80, 443, 4443, 10443].
  • Проверено: 10443 реально доходит до ВМ (/health 200), 4443 — нет.
  • Поднят отдельный nginx: /etc/nginx-sqs/nginx.conf, pid /run/nginx-sqs.pid, listen 10443 → proxy_pass http://127.0.0.1:4100. Запуск sudo nginx -c /etc/nginx-sqs/nginx.conf.

2.5. Замеры (гипотеза ПОДТВЕРЖДЕНА)

Тест Инструмент Результат
HTTP, 30 запросов 1КБ/10КБ/100КБ/256КБ curl --aws-sigv4 30/30 200, max 0.99 с
HTTPS, 10 запросов 26КБ…260КБ curl --aws-sigv4 10/10 200, 0.7–3.2 с
Long-poll ReceiveMessage WaitTimeSeconds=20 curl 20.3 с, 200 (корректно)

Ни зависаний ~51 с, ни таймаутов 31–33 с. На пути «интернет → ВМ 213» болезни нет.

2.6. DNS

  • sinefo.ru делегирован в реестре .ru на ns3.ngcloud.ru / ns4.ngcloud.ru (проверено через a.dns.ripn.net).
  • sqs.sinefo.ru A 5.172.178.213 — публично резолвится. Ранее запись была 185.247.187.83, что = IP самого DNS-сервера ns3.ngcloud.ru, а не ВМ (исправлено владельцем).

2.7. TLS (Let's Encrypt)

  • sudo certbot certonly --webroot -w /var/www/acme -d sqs.sinefo.ru --non-interactive --agree-tos (аккаунт LE на ВМ уже существовал → без нового e-mail) → /etc/letsencrypt/live/sqs.sinefo.ru/.
  • Срок: до 2027-01-08, автопродление настроено.
  • ACME-челлендж обслуживается главным nginx (vhost 80 с location /.well-known/acme-challenge/).

2.8. Публичная точка (итог)

  • Главный nginx, /etc/nginx/conf.d/sqs-sinefo.conf:
    • 80: ACME-челлендж + редирект на https;
    • 443 ssl: сертификат sqs.sinefo.ru + proxy_pass http://127.0.0.1:4100, Host $http_host.
  • Проверено снаружи: https://sqs.sinefo.ru/health → 200 (cert valid), SigV4, 256 КБ за 1.05 с.

2.9. Уборка

  • Второй nginx (10443) остановлен, /etc/nginx-sqs удалён; порт 10443 свободен.
  • conf.d/sqs-sinefo.conf — заменён на нормальный vhost (было: HTTP-only левак от 10-08).
  • Из актуального дока doc/2026-08-13-migration-to-managed.md убран kube5s.ru (квинтет: iot.kube5s.ru→iot.nubes.ru, qu.kube5s.ru×3→sqs.containerk8s.dev.nubes.ru), коммит a47743f. В doc/legacy/ (история) не трогал.

2.10. Фикс QueueUrl (кодинг)

  • Проблема: QueueUrl = http://region.host:port/... (плейсхолдеры) — клиенты без endpoint_url сломаны.
  • Реализовано: Environment.ExternalURLBase + env SHARED_SQS_EXTERNAL_URL_BASE.
  • Ошибка по пути №1: env-override сначала поместил после models.CurrentEnvironment = envs[env] — не сработал: LoadYamlConfig делает ранний return без goaws.yaml. Перенёс в applyEnvironmentDefaults (вызывается через defer → всегда).
  • Ошибка по пути №2: после переноса всё равно не работало — демо-seed (app/cmd/seed.go) собирал URL своей копией логики, а не через tenantQueueURL. Вынес gosqs.TenantQueueURL, seed переведён на него.
  • Коммиты 469132b, ca0372b; тест app/gosqs/tenant_helpers_test.go. Проверено снаружи: list-queues → https://sqs.sinefo.ru/t-.../orders.

2.11. Устойчивость: systemd + локальный Redis

  • Установлен redis-server (7.0.15) на 213, включён AOF (appendonly yes).
  • systemd-юнит shared-sqs.service (Restart=always, enable) + /etc/shared-sqs.env.
  • Проверено: сообщение пережило рестарт; systemctl is-enabled/active → enabled/active.
  • Дефекты seed (обнаружены и исправлены, коммит c0aa618): демо-очереди не персистились; каждый старт плодил нового демо-тенанта (утечка при Restart=always). Фикс: SaveQueue+ SaveMessages + идемпотентность через store.List().
  • Управление: sudo systemctl {status,restart,stop} shared-sqs.

2.12. Прод-хардненинг

  • SHARED_SQS_SEED_DEMO=false; admin-token сменён на случайный 64-hex (в /etc/shared-sqs.env); logrotate для sqs.log.
  • Billing/JWT не настроены. Проверено: сервис работает на существующем тенанте из Redis.

2.13. Шаг 2 — разбиение data-plane / control-plane

  • router.NewDataPlane (публичный SQS API) + router.NewControlPlane (админка/метрики/UI).
  • main: два листенера — 0.0.0.0:4100 (публично) и 127.0.0.1:4101 (control-plane, только локально).
  • Проверено: публично /admin//metrics → 403 (наружу не доступны), SQS API работает; локально 4101/admin → 200. Коммит c1520c0.
  • Примечание: пока один процесс с двумя листенерами (общее in-memory состояние); два процесса — после Шага 3.

2.14. Шаг 3 — начало: дизайн + тенанты read-through Redis

  • Дизайн: doc/thinking/step3-state-extraction-design-2026-10-10.md (варианты A/B/C, рекомендация C→A, что замерить).
  • Код (коммит 779a71d): Redis-индекс ssq:tenant_ak (accessKey → JSON тенанта) + бэкфилл при старте; auth-middleware читает тенанта из Redis при промахе локальной памяти.
  • Нужно для ЛЮБОГО multi-instance варианта; в одном процессе — страховка.
  • Проверено: индекс заполнен (hlen ssq:tenant_ak = 1), регрессий нет.

3. Грабли (для повторного использования)

  1. proxy_set_header Host $host теряет порт → SigV4 SignatureDoesNotMatch. Нужен $http_host. (nginx $host — имя без порта; $http_host — заголовок целиком.)
  2. ~/.aws/config [default] содержит endpoint_url = https://s3.msk-1.ngcloud.ru → aws sqs ... без явного --endpoint-url уходит в S3 и получает 405 MethodNotAllowed (Ceph RGW, HostId=...-dc1-msk-1). Всегда задавать --endpoint-url.
  3. Креды демо-тенанта рандомны при каждом старте — брать из ~/sqs-test/sqs.log (seed: создан тенант ... AccessKey=...). При «address already in use» в логе креды мёртвого инстанса.
  4. pkill -f "http.server 10443" по SSH самоматчится на строку ssh-команды и убивает сессию — использовать pkill -x <имя>.
  5. Порт 8443 на 213 нельзя занимать — там DNAT транзита на Vultr.
  6. Managed Redis недоступен с 213: его endpoint — внутренний k8s DNS (redisk8s.<uid>.svc.cluster.local:6379), резолвится только изнутри кластера. С ВМ — только локальный Redis или внешний endpoint от NUBES.
  7. Локальный Redis на 213 не спасает от падения ВМ (SQS и Redis — на одной машине, SPOF).

4. ОШИБКИ (сводка, включая ошибки Flash)

# Что утверждалось/сделано Что на самом деле Исправление
1 «При ребуте ВМ nginx не поднимется» (из-за битого upstream) После ребута nginx active, 80/443 слушают Неверный вывод; снят при перепроверке
2 «.83 — мёртвый IP» 185.247.187.83 = живой DNS ns3.ngcloud.ru (порт 53); проверял только 80/443 Признано при перепроверке
3 Запуск второго инстанса при живом первом fatal: bind: address already in use; лог перезаписан кредами мёртвого → InvalidClientTokenId pkill -x shared-sqs, один инстанс, креды из лога
4 Второй nginx: Host $host SigV4 SignatureDoesNotMatch Host $http_host
5 Прямые DNS-выводы по регексу location / Первый grep не нашёл (паттерн с пробелом) — чуть не сделал ложный вывод Перечитал файл целиком (cat)
6 «Только 80/443 открыты» 8888/9443 «принимают» TCP (SYN-proxy), но пусты Уточнено: рабочие — только 80/443

5. Состояние и воспроизведение

5.1. Итоговое состояние

  • Работает: https://sqs.sinefo.ru (443, TLS) → shared-sqs на ВМ 213 (memory-only, 127.0.0.1:4100).
  • SQS: ~/sqs-test/shared-sqs, лог ~/sqs-test/sqs.log, pid меняется. Демо-тенант + 5 очередей.
  • QueueUrl — ИСПРАВЛЕНО (см. 2.10): https://sqs.sinefo.ru/<tenantID>/<queue>.

5.2. Как поднять заново

# на ВМ 213
cd ~/sqs-test && setsid nohup env SHARED_SQS_SEED_DEMO=true \
  ./shared-sqs --admin-token=dev-token-123 --port=4100 --loglevel=info > sqs.log 2>&1 </dev/null &
# креды демо-тенанта — в sqs.log
grep "seed: создан тенант" ~/sqs-test/sqs.log | tail -1
# проверка снаружи
curl -sS https://sqs.sinefo.ru/health

5.3. Откат

sudo rm /etc/nginx/conf.d/sqs-sinefo.conf && sudo nginx -t && sudo systemctl reload nginx
pkill -x shared-sqs
# бэкапы nginx на ВМ: /etc/nginx/conf.d.bak-*

6. Открытые вопросы

  1. Клиенты без явного endpoint_url — есть ли такие (вопрос №5 мануала). QueueUrl уже корректный.
  2. Egress ВМ: curl https://api.ipify.org с ВМ вернул пусто — влияет на billing (PG) и JWT-API.
  3. Дальше по мануалу: Шаг 2 (разбиение data-plane/control-plane), Шаг 3 (вынос состояния).