# IoT на Nubes — чек-лист деплоя (актуально на 2026-10-11) > Детальная процедура — `deployment-nubes-production.md`. Здесь — конкретные > шаги текущего стенда. Секреты НЕ хранятся в репо (`*.key` в `.gitignore`); > значения `<>` берутся из `pg.key`/deck/генератора. ## 0. Готово - **Образы в Gitea** (`gitea.services.ngcloud.ru/nail`): - `iot-service:v0.1.13` (+ latest) - `iot-emqx:v0.2.4` (+ latest) - **shared-SQS** тенант `demo-service` (`SSAK-b8fb2b3000c178b865091686`, регион `us-east-1`): - очередь `iot-telemetry` — создана; - DLQ `iot-telemetry-dlq` — создана. - публичный endpoint: `https://sqs.sinefo.ru`. - **PostgreSQL** managed: хост `postgresqlk8s-master.509145c3-ba71-4687-a084-d9dcbc88d3d2.svc.cluster.local:5432` (из `pg.key`). ✅ **создано через Nubes API (test):** пользователь `iotservice` (role `ddl_user` → CREATEDB+CREATEROLE), БД `iotdb` (owner `iotservice`). Пароль `iotservice` — в vault инстанса. ## 1. PostgreSQL — ✅ ГОТОВО Пользователь `iotservice` (role `ddl_user`, права CREATEDB+CREATEROLE) и БД `iotdb` (owner `iotservice`) созданы через Nubes API (test): операции `create_user` (svcOperationId 241) и `create_database` (245) на инстансе `509145c3-…`. ⚠ Гранулярность: имя PG-пользователя подчиняется платформенному regex `^[A-Za-z0-9]+$` → `iot_service` НЕЛЬЗЯ (только `iotservice`). Пароль: GET `/instances/509145c3-…/vault/users` (Nubes API, test) → поле `iotservice.password`. Подключение: ``` IOT_PG_DSN = postgresql://iotservice:@postgresqlk8s-master.509145c3-ba71-4687-a084-d9dcbc88d3d2.svc.cluster.local:5432/iotdb?sslmode=require ``` Таблицы (`iot_devices`, per-tenant БД телеметрии) создаются кодом при старте. ## 2. EMQX-контейнер (создаётся ПЕРВЫМ в deck, CPU ≥ 1000m) Образ: `gitea.services.ngcloud.ru/nail/iot-emqx:v0.2.4`, порт из EXPOSE = `8083`. Env (все — при создании, потом не меняются): | Переменная | Значение | |---|---| | `EMQX_AUTHENTICATION__1__SERVER` | `postgresqlk8s-master.509145c3-ba71-4687-a084-d9dcbc88d3d2.svc.cluster.local:5432` | | `EMQX_AUTHENTICATION__1__DATABASE` | `iotdb` | | `EMQX_AUTHENTICATION__1__USERNAME` | `iotservice` | | `EMQX_AUTHENTICATION__1__PASSWORD` | `` | | `EMQX_AUTHORIZATION__SOURCES__1__SERVER` | как AUTHENTICATION | | `EMQX_AUTHORIZATION__SOURCES__1__DATABASE` | `iotdb` | | `EMQX_AUTHORIZATION__SOURCES__1__USERNAME` | `iotservice` | | `EMQX_AUTHORIZATION__SOURCES__1__PASSWORD` | `` | | `EMQX_LOG__CONSOLE_HANDLER__LEVEL` | `warning` | ⚠ Не задавать `...__URL` (HTTP-auth старой схемы — уронит под). SSL обязателен. После создания — записать **UUID namespace EMQX** (нужен в `MQTT_HOST`). ## 3. iot-service-контейнер (создаётся ВТОРЫМ) Образ: `gitea.services.ngcloud.ru/nail/iot-service:v0.1.13`, порт из EXPOSE = `9090`. Env (обязательные — секреты; необязательные имеют дефолты в образе): | Переменная | Значение | |---|---| | `IOT_PG_DSN` | `postgresql://iotservice:@postgresqlk8s-master.509145c3-ba71-4687-a084-d9dcbc88d3d2.svc.cluster.local:5432/iotdb?sslmode=require` | | `SQS_ACCESS_KEY` | `SSAK-b8fb2b3000c178b865091686` | | `SQS_SECRET_KEY` | `<из Admin API / лога сервиса>` | | `MQTT_USERNAME` | `iot-bridge` (device_id строки бриджа) | | `MQTT_PASSWORD` | `<сгенерировать>` | | `JWT_HMAC_SECRET` | `<сгенерировать>` | | `SQS_ENDPOINT` | `https://sqs.sinefo.ru` (не дефолт: shared-sqs НЕ в кластере, а на ВМ 213) | | `SQS_QUEUE_NAME` | `iot-telemetry` (дефолт) | | `SQS_DLQ_NAME` | `iot-telemetry-dlq` (дефолт) | | `MQTT_HOST` | `` | | `MQTT_PORT` | `8083` (дефолт) | | `AUTH_TEST_MODE` | `false` | При старте монолит: подключается к PG, создаёт схему, `EnsureBridgeDevice(MQTT_USERNAME, MQTT_PASSWORD)` → строка `__bridge/iot-bridge` в `iot_devices` для EMQX-auth. ## 4. Проверка - `/health` и `/ready` (порт 9090) → 200. - В логе: `bridge: MQTT connected`, `bridge: subscribed`, `consumer: SQS queue resolved`. - EMQX: `curl https:///mqtt` → 400 (норма). wss-рука — клиент с subprotocol `mqtt`.