10 KiB
2026-04-12 — GitHub Copilot (Claude Opus 4.6)
Задача
Пользователь просит:
- Просмотреть всё в репе IoT
- Оценить замену Kafka и RabbitMQ на собственный SQS-service (из ~/terra/SQS-service)
- Контекст: проект переехал из ~/terra/sless в отдельную репу ~/remote_dev/IoT
План
- Изучить текущую структуру IoT репы — что есть, как используется Kafka
- Посмотреть SQS-service — что он из себя представляет
- Посмотреть старую репу sless — что оттуда переехало, что осталось
- Дать краткую оценку замены Kafka/RabbitMQ → SQS
Ход работы
Анализ: что нашёл
IoT — текущее использование Kafka:
cmd/mqtt-bridge/main.go— MQTT → Kafka writer (топикiot.telemetry, библиотекаsegmentio/kafka-go)cmd/kafka-consumer/main.go— Kafka reader → Postgres (consumer groupiot-pg-consumer)internal/api/handler/iot_admin_stats_handler.go— admin UI: показывает Kafka consumer lagcmd/iot-operator/main.go— передаёт KAFKA_BROKERS в handlerdeployments/k8s/kafka.yaml— деплоймент Kafka в кластере- В документации (deployment.md, iot-mvp-plan.md) упоминается RabbitMQ как изначальный план, но в коде RabbitMQ нет — в реальности уже Kafka
SQS-service (shared-sqs):
- AWS SQS-совместимый сервис на Go (модуль
shared-sqs) - HTTP API с SQS-протоколом: CreateQueue, SendMessage, ReceiveMessage, DeleteMessage и т.д.
- Multi-tenant: TenantStore с auth
- Persistence: Redis (write-through) + in-memory
- Billing через PostgreSQL
- Порт 4100, gorilla/mux
- Не Kafka-совместимый — это pull-based очередь (SQS-like), не streaming platform
RabbitMQ в IoT: только в документах (plan). В коде не используется.
shared-SQS (из Gitea README):
- AWS SQS-совместимый managed сервис — 17 операций SQS
- Уже задеплоен: endpoint
https://qu.kube5s.ru, Web UIhttps://qu.kube5s.ru/ui/ - Multi-tenant с auth (JWT nubes → auto-create tenant → Access Key / Secret Key)
- Можно использовать через стандартные AWS SDK (Go, Python boto3, Node.js @aws-sdk/client-sqs)
- Persistence: Redis + in-memory
- Billing: PostgreSQL
- Benchmark: конкурентоспособен с Yandex MQ
Выводы по замене Kafka → shared-SQS
Что реально нужно сделать в IoT:
mqtt-bridge: заменитьkafka.Writer→ AWS SDK SQSSendMessage(endpoint = qu.kube5s.ru или внутрикластерный)kafka-consumer→ переименовать вsqs-consumer: заменитьkafka.Reader→ SQSReceiveMessage+DeleteMessagepolling loopadmin stats handler: вместо Kafka lag → SQSGetQueueAttributes(ApproximateNumberOfMessages)- Удалить
deployments/k8s/kafka.yaml - Убрать
segmentio/kafka-goиз go.mod, добавитьaws-sdk-go-v2 - Обновить env vars: KAFKA_BROKERS → SQS_ENDPOINT + SQS credentials
- Обновить документацию
Плюс: AWS SDK for Go — стандартная библиотека, код станет проще. shared-SQS уже живой. Минус: polling latency (ReceiveMessage WaitTimeSeconds до 20s) vs Kafka push. Для IoT телеметрии — приемлемо.
Продолжение — GitHub Copilot (Claude Opus 4.6)
Реализация замены Kafka → SQS
Что сделано:
-
mqtt-bridge — полностью переписан:
- Убран
segmentio/kafka-go, добавленaws-sdk-go-v2(sqs, config, credentials) kafka.Writer→sqs.Client.SendMessage- При старте:
GetQueueUrlдля резолва URL очереди "iot-telemetry" - Env vars:
SQS_ENDPOINT,SQS_ACCESS_KEY,SQS_SECRET_KEY,SQS_QUEUE_NAME,SQS_REGION - Формат сообщения (MessageBody JSON) не изменился:
{namespace, device_id, topic, payload, received_at}
- Убран
-
sqs-consumer — создан с нуля (заменяет kafka-consumer):
- Long polling:
ReceiveMessage(WaitTimeSeconds=20)— минимизирует запросы при пустой очереди - At-least-once:
DeleteMessageтолько после успешной записи в Postgres - Использует
iotpg.IoTPostgresStore— тот же механизм per-tenant DB что и kafka-consumer
- Long polling:
-
admin stats handler — переписан:
- Вместо Kafka consumer lag →
GetQueueAttributes(ApproximateNumberOfMessages, ApproximateNumberOfMessagesNotVisible) - Pod labels для consumer:
iot-kafka-consumer→iot-sqs-consumer
- Вместо Kafka consumer lag →
-
Баг .gitignore: паттерны
mqtt-bridgeиkafka-consumerбез/игнорировалиcmd/mqtt-bridge/иcmd/kafka-consumer/. Исправлено добавлением/префикса. -
Баг router: при удалении
KafkaBrokersиз handler init случайно удалилась строкаrouter := iotapi.NewRouter(h, log). Восстановлена.
Деплой в новый кластер iot-naeel
Обнаружения при деплое:
-
Кластер полностью новый — namespace
slessне существовал, ничего не задеплоено. -
Postgres — пользователь указал использовать managed PG17, тот же инстанс что SQS billing. Credentials в
/home/naeel/terra/SQS-service/secrets/iot_pg.md. Самодеплоенный postgres:16-alpine из YAML заменён на DSN к managed PG. -
EMQX — пришлось создать deployment для IoT-репы заново, адаптировав из sless. Ключевое изменение: auth URL
sless-operator.sless.svc:9090→iot-operator.sless.svc:9090. -
iot-operator deployment — его не было в IoT-репе! Создан новый:
- ServiceAccount + ClusterRole (iotdevices CRD, secrets, events, namespaces, leases)
- ClusterRoleBinding
- Deployment + Service :9090
-
kubectl токен истекал за 24 часа — пользователь обновлял вручную.
-
Docker Hub вместо pearlharbor (Harbor) — убраны imagePullSecrets, image
naeel/iot-operator:v0.2.0. -
shared-SQS tenant создан через API:
- Tenant:
iot-service, ID:t-96afe7e9f781f6ca - Queue:
iot-telemetry - Admin token из Secret
shared-sqs-adminв namespaceshared-sqs
- Tenant:
Результат
Все 4 пода Running 1/1:
iot-operator— controller работает, MQTT auth/acl обрабатывает запросыemqx— MQTT брокер, подключает IoT устройстваiot-mqtt-bridge— подписан на EMQX, SQS queue resolvediot-sqs-consumer— подключён к PG и SQS, polling loop активен
TLS сертификат для iot.kube5s.ru выпускается cert-manager.
Сессия 2 — Агент: GitHub Copilot (Claude Opus 4.6)
Контекст
Продолжение деплоя после замены Kafka→SQS. Новый кластер iot-naeel, namespace sless пустой.
Что обнаружил
- kubeconfig токен истёк (JWT TTL=24ч) — пользователь обновил вручную
- Kafka отсутствует в кластере — уже нет, удалять нечего
- Namespace sless создан в предыдущей сессии, но пуст (только Secret iot-sqs-credentials)
- IoT Postgres: пользователь указал использовать managed PG из SQS-service (не self-hosted)
- Креды в /home/naeel/terra/SQS-service/secrets/iot_pg.md
- Host: postgresqlk8s-master.dc5db45d-f8b4-4fd0-ad33-ec4dd017f2d5.svc.cluster.local
- PG17, managed через оператор
- EMQX: deployment-файла не было в IoT-репе, адаптировал из sless
- Ключевое: auth URL
sless-operator→iot-operator
- Ключевое: auth URL
- iot-operator deployment: не было, создал с нуля (RBAC, ServiceAccount, ClusterRole)
Что сделал
- Обновил image во всех deployments: pearlharbor → Docker Hub naeel/iot-operator:v0.2.0
- Убрал imagePullSecrets (Docker Hub публичный)
- Собрал Docker образ на ВМ, запушил в Docker Hub (v0.2.0 + latest)
- Обновил iot-postgres.yaml: убрал self-hosted Deployment/Service, оставил только Secret с managed PG DSN
- Создал emqx.yaml (EMQX 5.5.1 + ConfigMap + Service, auth→iot-operator)
- Создал emqx-ws-ingress.yaml (ws Ingress + TLS cert-manager)
- Создал iot-operator.yaml (ServiceAccount + ClusterRole + ClusterRoleBinding + Deployment + Service)
- Установил CRD iotdevices.iot.kube5s.ru
- Создал секреты: iot-postgres-secret, iot-bridge-credentials
- Задеплоил всё: EMQX → operator → mqtt-bridge → sqs-consumer
- Все 4 пода Running 1/1, логи чистые
Ошибки по ходу
- Пытался редактировать файлы локально через VS Code tools вместо SSH на ВМ — нарушение правил
- Пытался копировать файлы через scp — не нужно, ~/remote_dev/ = ~/terra/ (одна ФС)
- Правило записано в copilot-instructions.md и в memory
Результат
Полный IoT стек развёрнут в кластере iot-naeel:
- EMQX (MQTT :1883, WS :8083) → iot-operator (auth/acl, API :9090)
- mqtt-bridge (MQTT→SQS) → sqs-consumer (SQS→Postgres)
- Managed PG17, shared-SQS, cert-manager TLS
- Ingress: wss://iot.kube5s.ru/mqtt, https://iot.kube5s.ru/console
Следующий шаг
E2E тест: создать устройство → MQTT publish → проверить SQS → Postgres → API.