docs: полная документация v0.2.3 — архитектура, API, деплой, тестирование
Новые файлы: - doc/architecture/current-v0.2.3.md — актуальная архитектура - doc/api/endpoints-v0.2.3.md — полная документация REST API - doc/deployment-v0.2.3.md — инструкция деплоя v0.2.3 - doc/run-and-test.md — руководство по запуску и E2E тесту Обновлено: - doc/progress.md — секция документации - doc/thinking/2026-04-12.md — лог мышления
This commit is contained in:
@@ -0,0 +1,295 @@
|
||||
# IoT Managed Service — Актуальный деплой (v0.2.3)
|
||||
|
||||
> Дата: 2026-04-12
|
||||
> Образ: `naeel/iot-operator:v0.2.3`
|
||||
> Ветка: `feature/replace-kafka-with-sqs`
|
||||
> Кластер: `iot-naeel`
|
||||
> Автор: GitHub Copilot (Claude Opus 4.6)
|
||||
|
||||
---
|
||||
|
||||
## Обзор
|
||||
|
||||
Три бинарника из одного Docker-образа `naeel/iot-operator:v0.2.3`:
|
||||
|
||||
| Бинарник | Deployment | Назначение |
|
||||
|----------|-----------|------------|
|
||||
| `/iot-operator` | iot-operator | Controller-manager (IoTDevice CRD) + REST API :9090 |
|
||||
| `/mqtt-bridge` | iot-mqtt-bridge | MQTT (EMQX) → shared-SQS bridge |
|
||||
| `/sqs-consumer` | iot-sqs-consumer | shared-SQS → Postgres pipeline |
|
||||
|
||||
Плюс:
|
||||
- EMQX 5.5.1 — MQTT-брокер (отдельный образ `emqx/emqx:5.5.1`)
|
||||
|
||||
---
|
||||
|
||||
## Кластер
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| Имя | `iot-naeel` |
|
||||
| API | `https://185.247.187.149:6443` |
|
||||
| Ingress IP | `185.247.187.151` |
|
||||
| DNS | `iot.kube5s.ru → 185.247.187.147` |
|
||||
| Namespace | `sless` |
|
||||
| kubeconfig | `~/.kube/config` на ВМ (токен 24ч, обновлять через auth.k8s.ngcloud.ru) |
|
||||
|
||||
---
|
||||
|
||||
## Секреты (namespace sless)
|
||||
|
||||
Перед первым деплоем создать 3 секрета:
|
||||
|
||||
### 1. iot-bridge-credentials (MQTT bridge → EMQX)
|
||||
|
||||
```bash
|
||||
kubectl create secret generic iot-bridge-credentials -n sless \
|
||||
--from-literal=MQTT_USERNAME="iot-bridge-internal" \
|
||||
--from-literal=MQTT_PASSWORD="<пароль bridge>"
|
||||
```
|
||||
|
||||
Используется:
|
||||
- **iot-operator** — для проверки bridge auth в `/internal/mqtt/auth` (env: MQTT_BRIDGE_USERNAME, MQTT_BRIDGE_PASSWORD)
|
||||
- **iot-mqtt-bridge** — для подключения к EMQX (envFrom: secretRef)
|
||||
|
||||
### 2. iot-sqs-credentials (shared-SQS)
|
||||
|
||||
```bash
|
||||
kubectl create secret generic iot-sqs-credentials -n sless \
|
||||
--from-literal=SQS_ENDPOINT="https://qu.kube5s.ru" \
|
||||
--from-literal=SQS_ACCESS_KEY="SSAK-a9964f2723bc6d347f48d153" \
|
||||
--from-literal=SQS_SECRET_KEY="<secret_key>"
|
||||
```
|
||||
|
||||
Используется:
|
||||
- **iot-mqtt-bridge** — для SendMessage
|
||||
- **iot-sqs-consumer** — для ReceiveMessage + DeleteMessage
|
||||
|
||||
### 3. iot-postgres-secret (Managed PostgreSQL)
|
||||
|
||||
```bash
|
||||
kubectl create secret generic iot-postgres-secret -n sless \
|
||||
--from-literal=IOT_PG_DSN="postgres://super:<password>@postgresqlk8s-master.dc5db45d-f8b4-4fd0-ad33-ec4dd017f2d5.svc.cluster.local:5432/sqsdb?sslmode=disable"
|
||||
```
|
||||
|
||||
Используется:
|
||||
- **iot-sqs-consumer** — для записи телеметрии в per-tenant DB
|
||||
|
||||
---
|
||||
|
||||
## Процедура деплоя (пошагово)
|
||||
|
||||
### Все команды выполнять на ВМ через SSH
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_ed25519 naeel@5.172.178.213
|
||||
cd /home/naeel/terra/IoT
|
||||
```
|
||||
|
||||
### 0. Сборка образа (если код менялся)
|
||||
|
||||
```bash
|
||||
docker build --no-cache -t naeel/iot-operator:v0.2.3 .
|
||||
docker push naeel/iot-operator:v0.2.3
|
||||
```
|
||||
|
||||
### 1. CRD (один раз, cluster-wide)
|
||||
|
||||
```bash
|
||||
kubectl apply -f config/crd/bases/iot.kube5s.ru_iotdevices.yaml
|
||||
```
|
||||
|
||||
### 2. EMQX
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployments/k8s/emqx.yaml
|
||||
kubectl apply -f deployments/k8s/emqx-ws-ingress.yaml
|
||||
```
|
||||
|
||||
### 3. Postgres secret (один раз)
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployments/k8s/iot-postgres.yaml
|
||||
```
|
||||
|
||||
### 4. SQS secret (один раз)
|
||||
|
||||
```bash
|
||||
kubectl get secret iot-sqs-credentials -n sless
|
||||
# Если нет — создать (см. секцию Секреты выше)
|
||||
```
|
||||
|
||||
### 5. Bridge credentials (один раз)
|
||||
|
||||
```bash
|
||||
kubectl get secret iot-bridge-credentials -n sless
|
||||
# Если нет — создать (см. секцию Секреты выше)
|
||||
```
|
||||
|
||||
### 6. Operator
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployments/k8s/iot-operator.yaml
|
||||
kubectl rollout status deployment/iot-operator -n sless
|
||||
```
|
||||
|
||||
### 7. MQTT Bridge
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployments/k8s/iot-mqtt-bridge.yaml
|
||||
kubectl rollout status deployment/iot-mqtt-bridge -n sless
|
||||
```
|
||||
|
||||
### 8. SQS Consumer
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployments/k8s/iot-sqs-consumer.yaml
|
||||
kubectl rollout status deployment/iot-sqs-consumer -n sless
|
||||
```
|
||||
|
||||
### 9. Проверка
|
||||
|
||||
```bash
|
||||
kubectl get pods -n sless
|
||||
# Ожидаемый результат:
|
||||
# emqx-xxx 1/1 Running
|
||||
# iot-operator-xxx 1/1 Running
|
||||
# iot-mqtt-bridge-xxx 1/1 Running
|
||||
# iot-sqs-consumer-xxx 1/1 Running
|
||||
|
||||
kubectl logs -n sless deployment/iot-operator --tail=5
|
||||
kubectl logs -n sless deployment/iot-mqtt-bridge --tail=5
|
||||
kubectl logs -n sless deployment/iot-sqs-consumer --tail=5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Обновление образа (rollout)
|
||||
|
||||
```bash
|
||||
# 1. Собрать новый образ
|
||||
docker build --no-cache -t naeel/iot-operator:v0.2.4 .
|
||||
docker push naeel/iot-operator:v0.2.4
|
||||
|
||||
# 2. Обновить тег во ВСЕХ трёх YAML
|
||||
sed -i 's/v0.2.3/v0.2.4/g' deployments/k8s/iot-operator.yaml \
|
||||
deployments/k8s/iot-mqtt-bridge.yaml \
|
||||
deployments/k8s/iot-sqs-consumer.yaml
|
||||
|
||||
# 3. Применить
|
||||
kubectl apply -f deployments/k8s/iot-operator.yaml
|
||||
kubectl apply -f deployments/k8s/iot-mqtt-bridge.yaml
|
||||
kubectl apply -f deployments/k8s/iot-sqs-consumer.yaml
|
||||
|
||||
# 4. Проверить
|
||||
kubectl get pods -n sless -w
|
||||
```
|
||||
|
||||
**ВАЖНО:** Если образ с тем же тегом — Kubernetes не скачает новый (кэш на нодах). Всегда менять тег.
|
||||
|
||||
---
|
||||
|
||||
## Компоненты: env vars
|
||||
|
||||
### iot-operator
|
||||
|
||||
| Переменная | Значение | Источник |
|
||||
|-----------|----------|----------|
|
||||
| MQTT_BRIDGE_USERNAME | iot-bridge-internal | Secret iot-bridge-credentials (key: MQTT_USERNAME) |
|
||||
| MQTT_BRIDGE_PASSWORD | (пароль) | Secret iot-bridge-credentials (key: MQTT_PASSWORD) |
|
||||
|
||||
### iot-mqtt-bridge
|
||||
|
||||
| Переменная | Значение | Источник |
|
||||
|-----------|----------|----------|
|
||||
| MQTT_BROKER_URL | tcp://emqx.sless.svc:1883 | YAML env |
|
||||
| SQS_QUEUE_NAME | iot-telemetry | YAML env |
|
||||
| SQS_REGION | us-east-1 | YAML env |
|
||||
| MQTT_USERNAME | iot-bridge-internal | Secret iot-bridge-credentials |
|
||||
| MQTT_PASSWORD | (пароль) | Secret iot-bridge-credentials |
|
||||
| SQS_ENDPOINT | https://qu.kube5s.ru | Secret iot-sqs-credentials |
|
||||
| SQS_ACCESS_KEY | SSAK-... | Secret iot-sqs-credentials |
|
||||
| SQS_SECRET_KEY | (secret) | Secret iot-sqs-credentials |
|
||||
|
||||
### iot-sqs-consumer
|
||||
|
||||
| Переменная | Значение | Источник |
|
||||
|-----------|----------|----------|
|
||||
| SQS_QUEUE_NAME | iot-telemetry | YAML env |
|
||||
| SQS_REGION | us-east-1 | YAML env |
|
||||
| SQS_ENDPOINT | https://qu.kube5s.ru | Secret iot-sqs-credentials |
|
||||
| SQS_ACCESS_KEY | SSAK-... | Secret iot-sqs-credentials |
|
||||
| SQS_SECRET_KEY | (secret) | Secret iot-sqs-credentials |
|
||||
| IOT_PG_DSN | postgres://... | Secret iot-postgres-secret |
|
||||
|
||||
---
|
||||
|
||||
## Managed PostgreSQL
|
||||
|
||||
| Параметр | Значение |
|
||||
|---------|----------|
|
||||
| Версия | PostgreSQL 17 |
|
||||
| Host | postgresqlk8s-master.dc5db45d-f8b4-4fd0-ad33-ec4dd017f2d5.svc.cluster.local |
|
||||
| Port | 5432 |
|
||||
| User | super |
|
||||
| DB | sqsdb |
|
||||
| Тип | Managed (оператор в другом namespace) |
|
||||
|
||||
Per-tenant изоляция: для каждого namespace создаётся отдельная DATABASE `tenant_{namespace}` с таблицей `iot_telemetry`.
|
||||
|
||||
---
|
||||
|
||||
## shared-SQS (очередь)
|
||||
|
||||
| Параметр | Значение |
|
||||
|---------|----------|
|
||||
| Endpoint | https://qu.kube5s.ru |
|
||||
| Tenant | iot-service (ID: t-96afe7e9f781f6ca) |
|
||||
| Очередь | iot-telemetry |
|
||||
| Протокол | AWS SQS API (AWS SDK compatible) |
|
||||
|
||||
---
|
||||
|
||||
## Версии образов (история)
|
||||
|
||||
| Версия | Дата | Изменения |
|
||||
|--------|------|-----------|
|
||||
| v0.2.3 | 2026-04-12 | Bridge auth fix (BridgeUsername/BridgePassword), debug logs |
|
||||
| v0.2.2 | 2026-04-12 | Bridge auth (первая попытка, проблема с табами) |
|
||||
| v0.2.1 | 2026-04-12 | Bridge auth (проблема IsSuperuser field) |
|
||||
| v0.2.0 | 2026-04-12 | Kafka->SQS, managed PG, новый кластер iot-naeel |
|
||||
| v0.1.69 | 2026-04-06 | Kafka Async write fix (1000/1000 тест) |
|
||||
| v0.1.68 | 2026-04-06 | Kafka pipeline (bridge->Kafka->consumer->Postgres) |
|
||||
| v0.1.50 | 2026-04-04 | Первый IoT: controller + API + mqtt-bridge (RabbitMQ) |
|
||||
|
||||
---
|
||||
|
||||
## Известные ошибки и решения (v0.2.x)
|
||||
|
||||
### mqtt-bridge: MQTT connect timeout / CrashLoopBackOff
|
||||
|
||||
**Симптом:** bridge не подключается к EMQX, логи "MQTT connect timeout"
|
||||
|
||||
**Причина:** EMQX вызывает `/internal/mqtt/auth` при CONNECT. Bridge username `iot-bridge-internal` не содержит `_` -> MQTTAuth парсит namespace_deviceId -> ошибка -> deny -> EMQX возвращает not_authorized -> bridge retry 30с -> выглядит как timeout.
|
||||
|
||||
**Решение (v0.2.3):** В Handler добавлены поля BridgeUsername/BridgePassword. MQTTAuth проверяет bridge credentials ДО парсинга namespace_deviceId. Если username совпадает — allow.
|
||||
|
||||
### Docker image cache на k8s нодах
|
||||
|
||||
**Симптом:** после `docker push` новый образ не используется, pod стартует со старым кодом.
|
||||
|
||||
**Причина:** imagePullPolicy=Always работает, но если тег не изменился Kubernetes может использовать кэш ноды.
|
||||
|
||||
**Решение:** Всегда менять тег при пересборке (v0.2.1 -> v0.2.2 -> v0.2.3 и т.д.)
|
||||
|
||||
### EMQX: required_field node.cookie/node.data_dir
|
||||
|
||||
**Симптом:** EMQX CrashLoopBackOff при первом старте
|
||||
|
||||
**Причина:** EMQX 5.x требует явных node.cookie и node.data_dir
|
||||
|
||||
**Решение:** В emqx.conf (ConfigMap) обязательны:
|
||||
```hocon
|
||||
node { name = "emqx@127.0.0.1", cookie = "...", data_dir = "/opt/emqx/data" }
|
||||
```
|
||||
После изменения ConfigMap: `kubectl rollout restart deployment/emqx -n sless`
|
||||
Reference in New Issue
Block a user