Files
IoT/HISTORY/2026-08-16-session-log.md
T

172 lines
13 KiB
Markdown
Raw 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.
# Журнал сессии — 2026-08-16 (IoT: интеграция с shared-sqs, выбор пути миграции)
**Рабочая папка:** /home/naeel/nubes/IoT
> Правило этой сессии (задано пользователем): ВСЁ документировать в HISTORY,
> каждый шаг — сразу.
---
## 1. Контекст (состояние на входе)
- Пользователь завершил handoff по shared-sqs:
- `HANDOFF-NEW-CHAT.md` — в SQS-репозитории, закоммичен и запушен (`5fa34c2`).
- `doc/sqs-integration.md` — создан в IoT-репозитории, **не закоммичен** (untracked).
- `2026-08-13-migration-to-managed.md` — также untracked в IoT-репо.
- Git IoT: HEAD `368ff06` (feature/replace-kafka-with-sqs), origin отстаёт на 1 коммит
(HEAD не запушен: «fix(ingress): remove cert-manager + ssl-redirect»).
## 2. `doc/sqs-integration.md` — что важно для IoT (прочитан, суть)
- shared-sqs: прод v0.1.35, все тесты зелёные (api 22/22, sdk 15/15, FIFO/DLQ e2e),
нагрузка 168 591 операция — 0 сервисных ошибок.
- Внешний endpoint: `https://sqs.containerk8s.dev.nubes.ru` (регион us-east-1).
- Внутренний endpoint (поды того же кластера Nubes, realm iot-naeel):
`http://containerk8s.f1ffb134-7d16-45bd-8bef-69f6ec8ab33c.svc.cluster.local:4100`.
- Проблемы ПЛАТФОРМЫ (не сервиса):
1. Таймауты каждые 31–33с на внешнем пути (~5.5% запросов без ответа 30с).
Доказано tcpdump; внутри кластера потерь нет (port-forward 24977 раундов, 0 сбоев).
2. MSS=1448 при MTU 1400 → тела >~1400 байт виснут ~51с (PMTUD сломан).
Тикет Nubes подготовлен (`SQS-service/doc/thinking/nubes-ticket.md`).
- Рекомендации интеграции: AWS SDK + override endpoint; главная — внутренний адрес
(обходит шлюз полностью); ретраи ≥3, read_timeout ≥30с (для внешнего пути);
сообщения до ~1300 байт; VisibilityTimeout 30с+; FIFO требует MessageGroupId
(dedup 5 мин); DLQ через RedrivePolicy; лимит 50 очередей на тенанта.
- Креды детерминированы из email: tenantID `t-`+sha256(email)[:8],
AccessKey `SSAK-`+sha256(email)[:12], SecretKey sha256(email+":shared-sqs:secret-key:v1").
- Блокер прода — только тикет Nubes (для интернет-клиентов); для внутренней
интеграции блокеров нет.
## 3. Как сейчас развёртывается IoT (факты из репозитория)
- Код полностью на Go 1.25, модуль `gitea.services.ngcloud.ru/Nail/IoT`.
- Один образ Docker Hub `naeel/iot-operator:v0.2.6` (distroless), три бинарника:
`/iot-operator`, `/mqtt-bridge`, `/sqs-consumer`.
- Собственный k8s кластер `iot-naeel`, namespace `sless`, API `185.247.187.149:6443`.
- Деплой с ВМ: `ssh naeel@5.172.178.213`, каталог `/home/naeel/terra/IoT`,
`kubectl apply -f deployments/k8s/` (kubeconfig на ВМ, токен ~24ч).
- Компоненты:
- `iot-operator` — controller-manager (CRD IoTDevice) + REST API :9090;
- `iot-mqtt-bridge` — EMQX → SQS SendMessage;
- `iot-sqs-consumer` — SQS → Postgres (long poll 20с, delete после записи);
- EMQX 5.5.1 — MQTT-брокер (HTTP auth → operator).
- Секреты (ns sless): `iot-bridge-credentials`, `iot-sqs-credentials`
(`SQS_ENDPOINT=https://qu.kube5s.ru` — старый внешний адрес, устарел),
`iot-postgres-secret` (managed PG, `...svc.cluster.local:5432/sqsdb`).
- Ingress: устройства по `wss://iot.kube5s.ru/mqtt`.
- Миграция на managed Node.js (план от 13.08) — НЕ выполнена; Node.js-кода в репо нет.
## 4. Обсуждение: HTTP-контейнер vs Managed Node.js (вывод этой сессии)
- Вывод AI: HTTP-контейнер (как у shared-sqs) лучше: Go сохраняется целиком,
Dockerfile готов, схема доказана shared-sqs, внутренняя сеть без таймаутов.
Managed Node.js = полный rewrite (aedes, Express, @aws-sdk/client-sqs, pg) — запасной.
- Открытый риск контейнера: поддержка WebSocket upgrade на платформенном ingress
не проверена (устройства ходят по wss).
- Устройства в любом варианте ходят через внешний шлюз Nubes — проблемы шлюза
(5.5% таймаутов, MSS) остаются риском для wss в обоих вариантах.
## 5. Чтение SQS-репозитория (`/home/naeel/nubes/SQS-service`) — выяснено
- **План Node.js фактически отменён.** `doc/2026-08-13-migration-to-nubes.md`:
«Код не меняется вообще. Только инфраструктура».
- shared-sqs мигрировал в **«Простой HTTP контейнер» (nubes_http)** через deck-UI,
realm `iot-naeel`. Домен `sqs.containerk8s.dev.nubes.ru`, `/health` OK.
- Технические факты платформы (из HISTORY 13–14.08):
- Контейнер = k8s deployment `containerk8s`, namespace = UUID инстанса
(`f1ffb134-7d16-45bd-8bef-69f6ec8ab33c`), контейнер в поде называется `app`, порт 4100.
- Внутренний DNS: `containerk8s.<uuid-inst>.svc.cluster.local:4100`.
- Внешний: `*.containerk8s.dev.nubes.ru`, ingress/TLS встроены в контейнер.
- Образ — ТОЛЬКО публичный Docker Hub (Gitea/GHCR приватные платформа не тянет).
- Обновление образа — уникальным тегом (`latest` кэшируется зеркалом
`mirror.k8s.ngcloud.ru`); через `kubectl set image deployment/containerk8s app=...`
(правки через kubectl не откатываются — ownerReferences нет).
- Env vars — в deck-UI; Managed Redis — `redisk8s.<uuid>.svc.cluster.local:6379`.
- JWT-валидация: `https://lk-api-gateway.ngcloud.ru/api/v1/svc`
(deck-api*.ngcloud.ru — ЛЕГАСИ, не использовать).
- Long-running работает: SQS long-poll 20с; HTTP-соединение через ingress
держится ~150с (не режется).
- **WebSocket в SQS-истории не упоминается вообще** — поддержка wss на платформе
не проверялась. Единственный реальный риск контейнерного пути для IoT.
## 6. Вывод и следующий шаг
- Путь миграции IoT (кандидат): «Простой HTTP контейнер» в realm `iot-naeel`,
Go без переписывания; убрать operator/CRD → таблица `iot_devices` в Postgres;
bridge и consumer остаются Go.
- Первая проверка перед стартом: WebSocket upgrade (wss) через платформенный
ingress — тестовый контейнер с WS-эндпоинтом + `wscat`.
- ЖДЁМ решения пользователя по пути миграции.
---
## 7. Создан ws-probe — тестовый контейнер для проверки wss
**Команда пользователя:** «делай» (создать пробник + залить образ на Docker Hub;
для запуска в deck-UI нужен путь до образа).
**Что сделано** (все шаги):
1. Создан каталог `ws-probe/` в IoT-репозитории:
- `main.go` — Go echo-сервер на `gorilla/websocket`: `GET /health` (JSON
status+version), `GET /ws` (echo + ping каждые 20с, read-deadline 60с,
сбрасывается pong'ами — мёртвые соединения закрываются), `GET /` (HTML).
Без кредов, без внешних зависимостей.
- `Dockerfile` — multi-stage golang:1.25 → distroless/static:nonroot,
порт 8080 (меняется env `PORT`), версия через ldflags.
- `Makefile` — `docker-build`/`docker-push`, `VERSION=v0.1.0`, `IMAGE=naeel/iot-ws-probe`.
- `go.mod`/`go.sum` — отдельный модуль (gorilla/websocket v1.5.3), чтобы
не тащить зависимость в основной go.mod IoT.
2. `.gitignore` — добавлен `ws-probe/ws-probe` (сборочный бинарник).
3. Локальные проверки: `go vet` OK; smoke: `/health` → `{"status":"ok","version":"v0.1.0"}`;
WS-апгрейд → `HTTP/1.1 101 Switching Protocols` (Sec-WebSocket-Accept корректный).
4. Docker: логин в Docker Hub под `naeel` активен (проверен `docker info`).
5. Образ собран и запушен (публичный):
- **`naeel/iot-ws-probe:v0.1.0`** (и `:latest`),
- digest `sha256:dc029be3e79fb37f15ce23477096e340ab181b96c0132dc2e443f341e36f0688`,
- размер 10.9MB.
6. Коммиты: `27cb40e` (ws-probe), `2a7ecd2` (HISTORY). Пуш НЕ делался (не просили).
**Инструкция для deck-UI («Простой HTTP контейнер»):**
- Образ: **`naeel/iot-ws-probe:latest`** — стабильный путь БЕЗ уникального тега.
⛔ ПРАВИЛО (от пользователя): в deck-UI путь к образу фиксируется при создании
и НЕ редактируется — с тегом `:v0.1.0` мы не смогли бы поменять версию.
Обновление версии — новым пушем в `latest` + redeploy.
⚠️ Оговорка: зеркало платформы кэширует `latest` (случай shared-sqs) — если
redeploy подтянет старый digest, запасной путь: `kubectl set image
deployment/containerk8s app=naeel/iot-ws-probe:<новый-уникальный-тег>`.
- Env vars: не нужны (порт 8080 — дефолт; при необходимости `PORT`).
- Никаких кредов не требуется.
**Критерии проверки wss после деплоя** (будут применены):
- `curl -i -H "Connection: Upgrade" -H "Upgrade: websocket" ...` → 101;
- `wscat -c wss://<домен>/ws` → подключение, echo, соединение живёт 5–10 мин;
- переподключения стабильны; ping/pong проходят.
**Следующий шаг:** пользователь создаёт контейнер в deck-UI с этим образом —
далее тест wss по критериям выше.
---
## 8. Контейнер задеплоен в deck-UI — тест wss (16.08, ~07:26 GMT+03)
**Контейнер:** `https://testiot.containerk8s.dev.nubes.ru/` (создан пользователем
в deck-UI, образ `naeel/iot-ws-probe:latest`).
**Результаты проверок (первые):**
1. `GET /health` → `{"status":"ok","version":"v0.1.0"}` — под стянул наш образ.
2. `GET /` → HTML-страница ws-probe (200).
3. **WebSocket upgrade через платформенный ingress → `HTTP/1.1 101 Switching Protocols`**,
`Sec-WebSocket-Accept` корректный, HSTS на месте. (В выводе curl первая строка
`HTTP/1.1 200 Connection established` — локальный CONNECT-прокси машины,
ответ 101 пришёл от платформы.)
4. **`wscat -c wss://.../ws -x "probe-echo-1"` → echo вернулось, exit 0.**
Двусторонний обмен работает.
**КЛЮЧЕВОЙ ВЫВОД:** платформа Nubes («Простой HTTP контейнер») пропускает
WebSocket upgrade — wss для устройств возможен, путь контейнера подтверждён.
**Длительный тест стабильности** (запущен 08:26:10 по `date` = 07:26 GMT+03):
- скрипт `/tmp/ws-stability-test.py`: соединение 10 мин, echo каждые 10с,
ping/pong обе стороны (клиент ping_interval=25, сервер ping 20с),
лог с таймстемпами. Результат будет дописан ниже.