> ⛔⛔⛔ ЛЕГАСИ (2026-08-16) — СТАРЫЙ IoT (k8s-деплой). НЕ ПРИНИМАТЬ ВО ВНИМАНИЕ. Актуальное: HISTORY/2026-08-16-session-log.md # IoT Managed Service — Архитектура ## Общая схема ``` IoT Device (MQTT CONNECT) │ username="{ns}_{deviceId}", password=hex ▼ EMQX 5.5.1 (sless/emqx) │ POST /internal/mqtt/auth → iot-operator:9090 │ POST /internal/mqtt/acl → iot-operator:9090 ▼ │ MQTT PUBLISH → topic: "{ns}/telemetry/{deviceId}" ▼ iot-mqtt-bridge (cmd/mqtt-bridge) │ подписка на "+/telemetry/+" │ → Kafka topic "iot.telemetry" ▼ Kafka ▼ iot-kafka-consumer (cmd/kafka-consumer) │ consumer group "iot-pg-consumer" │ → per-tenant Postgres DB ▼ IoT Postgres (iot-postgres.sless.svc) │ DB: tenant_{namespace} │ Table: iot_telemetry ▼ REST API (iot-operator:9090) │ GET /v1/namespaces/{ns}/iot/telemetry ▼ Пользователь (Terraform / UI Console) ``` ## Компоненты | Компонент | Бинарник | Порт | Назначение | |-----------|----------|------|------------| | iot-operator | cmd/iot-operator | :9090 (API), :8081 (health) | Controller-manager + REST API | | mqtt-bridge | cmd/mqtt-bridge | — | MQTT→Kafka bridge | | kafka-consumer | cmd/kafka-consumer | — | Kafka→Postgres pipeline | ## CRD - **IoTDevice** (`iot.kube5s.ru/v1alpha1`) - Создание: пользователь через API / Terraform - Controller генерирует MQTT credentials → k8s Secret - Secret удаляется каскадно через OwnerReference ## Хранение - **IoT Postgres** — отдельный от sless PG - Management DB: `iot_platform` (таблица `tenant_credentials`) - Per-tenant DB: `tenant_{namespace}` (таблица `iot_telemetry`) ## Аутентификация - REST API (/v1/): Bearer JWT (middleware.Auth) - MQTT Auth (/internal/): вызывается EMQX, без JWT - Admin (/iot-admin/stats): ADMIN_STATS_TOKEN ## Docker образ - `naeel/iot-operator` (Docker Hub) - Все 3 бинарника в одном образе - `command: ["/iot-operator"]` или `["/mqtt-bridge"]` или `["/kafka-consumer"]` --- ## Актуальная архитектура (2026-04-12) > Kafka заменён на shared-SQS. Postgres заменён на managed. Новый кластер iot-naeel. ### Текущая схема ``` IoT Device (MQTT CONNECT) │ username="{ns}_{deviceId}", password=hex ▼ EMQX 5.5.1 (sless/emqx) │ POST /internal/mqtt/auth → iot-operator:9090 │ POST /internal/mqtt/acl → iot-operator:9090 ▼ │ MQTT PUBLISH → topic: "{ns}/telemetry/{deviceId}" ▼ iot-mqtt-bridge (cmd/mqtt-bridge) │ подписка на "+/telemetry/+" │ → AWS SDK SQS SendMessage → shared-SQS (https://qu.kube5s.ru) │ очередь: "iot-telemetry" (tenant: iot-service, id: t-96afe7e9f781f6ca) ▼ shared-SQS (namespace shared-sqs) │ AWS SQS-совместимый, multi-tenant ▼ iot-sqs-consumer (cmd/sqs-consumer) │ ReceiveMessage (WaitTimeSeconds=20, long polling) │ DeleteMessage после успешной записи (at-least-once) │ → per-tenant Postgres DB ▼ Managed PostgreSQL 17 (namespace dc5db45d-f8b4-4fd0-ad33-ec4dd017f2d5) │ Host: postgresqlk8s-master.dc5db45d-....svc.cluster.local │ User: super, DB: sqsdb │ Per-tenant DB: tenant_{namespace}, Table: iot_telemetry ▼ REST API (iot-operator:9090) │ GET /v1/namespaces/{ns}/iot/telemetry ▼ Пользователь (Terraform / UI Console) │ wss://iot.kube5s.ru/mqtt (WebSocket через Ingress) │ https://iot.kube5s.ru/console (UI) ``` ### Компоненты (актуальные) | Компонент | Бинарник | Порт | Назначение | |-----------|----------|------|------------| | iot-operator | cmd/iot-operator | :9090 (API), :8080 (metrics), :8081 (health) | Controller-manager + REST API | | mqtt-bridge | cmd/mqtt-bridge | — | MQTT → shared-SQS bridge | | sqs-consumer | cmd/sqs-consumer | — | shared-SQS → Postgres pipeline | ### Инфраструктура | Сервис | Тип | Namespace | Описание | |--------|-----|-----------|----------| | EMQX 5.5.1 | В кластере | sless | MQTT-брокер, HTTP auth/acl → iot-operator | | shared-SQS | В кластере | shared-sqs | AWS SQS-совместимая очередь, endpoint https://qu.kube5s.ru | | PostgreSQL 17 | Managed (оператор) | dc5db45d-... | per-tenant DB, тот же инстанс что и SQS billing | | cert-manager | В кластере | cert-manager | TLS сертификаты для iot.kube5s.ru | | nginx-ingress | В кластере | ingress | WSS/HTTPS проксирование | ### Секреты в namespace sless | Secret | Ключи | Источник | |--------|-------|----------| | iot-sqs-credentials | SQS_ENDPOINT, SQS_ACCESS_KEY, SQS_SECRET_KEY | shared-SQS tenant iot-service | | iot-postgres-secret | POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, IOT_PG_DSN | Managed PG | | iot-bridge-credentials | MQTT_USERNAME, MQTT_PASSWORD | Для mqtt-bridge → EMQX | ### Docker образ (актуальный) - `naeel/iot-operator:v0.2.0` (Docker Hub) - Все 3 бинарника в одном образе - `command: ["/iot-operator"]` или `["/mqtt-bridge"]` или `["/sqs-consumer"]` - Базовый: `gcr.io/distroless/static:nonroot` ### Кластер - Имя: `iot-naeel` - API: `https://185.247.187.149:6443` - Ingress IP: `185.247.187.151` - DNS: `iot.kube5s.ru → 185.247.187.147` --- ## Актуальная архитектура (2026-04-12) > Kafka заменён на shared-SQS. Postgres заменён на managed. Новый кластер iot-naeel. ### Текущая схема ``` IoT Device (MQTT CONNECT) │ username="{ns}_{deviceId}", password=hex ▼ EMQX 5.5.1 (sless/emqx) │ POST /internal/mqtt/auth → iot-operator:9090 │ POST /internal/mqtt/acl → iot-operator:9090 ▼ │ MQTT PUBLISH → topic: "{ns}/telemetry/{deviceId}" ▼ iot-mqtt-bridge (cmd/mqtt-bridge) │ подписка на "+/telemetry/+" │ → AWS SDK SQS SendMessage → shared-SQS (https://qu.kube5s.ru) │ очередь: "iot-telemetry" (tenant: iot-service, id: t-96afe7e9f781f6ca) ▼ shared-SQS (namespace shared-sqs) │ AWS SQS-совместимый, multi-tenant ▼ iot-sqs-consumer (cmd/sqs-consumer) │ ReceiveMessage (WaitTimeSeconds=20, long polling) │ DeleteMessage после успешной записи (at-least-once) │ → per-tenant Postgres DB ▼ Managed PostgreSQL 17 (namespace dc5db45d-f8b4-4fd0-ad33-ec4dd017f2d5) │ Host: postgresqlk8s-master.dc5db45d-....svc.cluster.local │ User: super, DB: sqsdb │ Per-tenant DB: tenant_{namespace}, Table: iot_telemetry ▼ REST API (iot-operator:9090) │ GET /v1/namespaces/{ns}/iot/telemetry ▼ Пользователь (Terraform / UI Console) │ wss://iot.kube5s.ru/mqtt (WebSocket через Ingress) │ https://iot.kube5s.ru/console (UI) ``` ### Компоненты (актуальные) | Компонент | Бинарник | Порт | Назначение | |-----------|----------|------|------------| | iot-operator | cmd/iot-operator | :9090 (API), :8080 (metrics), :8081 (health) | Controller-manager + REST API | | mqtt-bridge | cmd/mqtt-bridge | — | MQTT → shared-SQS bridge | | sqs-consumer | cmd/sqs-consumer | — | shared-SQS → Postgres pipeline | ### Инфраструктура | Сервис | Тип | Namespace | Описание | |--------|-----|-----------|----------| | EMQX 5.5.1 | В кластере | sless | MQTT-брокер, HTTP auth/acl → iot-operator | | shared-SQS | В кластере | shared-sqs | AWS SQS-совместимая очередь, endpoint https://qu.kube5s.ru | | PostgreSQL 17 | Managed (оператор) | dc5db45d-... | per-tenant DB, тот же инстанс что и SQS billing | | cert-manager | В кластере | cert-manager | TLS сертификаты для iot.kube5s.ru | | nginx-ingress | В кластере | ingress | WSS/HTTPS проксирование | ### Секреты в namespace sless | Secret | Ключи | Источник | |--------|-------|----------| | iot-sqs-credentials | SQS_ENDPOINT, SQS_ACCESS_KEY, SQS_SECRET_KEY | shared-SQS tenant iot-service | | iot-postgres-secret | POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, IOT_PG_DSN | Managed PG | | iot-bridge-credentials | MQTT_USERNAME, MQTT_PASSWORD | Для mqtt-bridge → EMQX | ### Docker образ (актуальный) - `naeel/iot-operator:v0.2.0` (Docker Hub) - Все 3 бинарника в одном образе - `command: ["/iot-operator"]` или `["/mqtt-bridge"]` или `["/sqs-consumer"]` - Базовый: `gcr.io/distroless/static:nonroot` ### Кластер - Имя: `iot-naeel` - API: `https://185.247.187.149:6443` - Ingress IP: `185.247.187.151` - DNS: `iot.kube5s.ru → 185.247.187.147`