feat: IoT Kafka demo — Terraform + history (test stand fail, moving to dev)
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
# Шаг 1 — Инициализация проекта
|
||||
|
||||
**Дата:** 2026-07-21
|
||||
|
||||
## Создана структура папок
|
||||
|
||||
```
|
||||
TEST_STAND/IOT_KAFKA_DEMO/ # Terraform-конфиги
|
||||
TEST_STAND/IOT_KAFKA_DEMO/HISTORY/ # Пошаговая история
|
||||
apps/iot-producer/ # Flask — продюсер событий в Kafka
|
||||
apps/iot-consumer/ # Flask — consumer (Kafka → ClickHouse)
|
||||
```
|
||||
|
||||
## Архитектура демо
|
||||
|
||||
```
|
||||
Flask (producer) → Kafka → Flask (consumer) → ClickHouse → Superset (dashboard)
|
||||
```
|
||||
|
||||
## Сервисы облака Nubes
|
||||
|
||||
| Ресурс | Роль |
|
||||
|--------|------|
|
||||
| `nubes_flask` (producer) | Генерирует IoT-события, шлёт в Kafka |
|
||||
| `nubes_kafka` | Шина сообщений |
|
||||
| `nubes_flask` (consumer) | Читает Kafka, пишет в ClickHouse |
|
||||
| `nubes_clickhouse` | Аналитическая time-series БД |
|
||||
| `nubes_superset` | Дашборд (температура, влажность, энергия) |
|
||||
|
||||
## Данные
|
||||
|
||||
IoT-симуляция «умный дом»:
|
||||
- `sensor_id`, `device_type`, `location`, `value`, `unit`, `timestamp`
|
||||
- Генерация каждые 2-5 секунд
|
||||
@@ -0,0 +1,29 @@
|
||||
# Шаг 2 — Репозитории и код приложений
|
||||
|
||||
**Дата:** 2026-07-21
|
||||
|
||||
## Созданы Git-репозитории на Gitea
|
||||
|
||||
| Репозиторий | URL |
|
||||
|-------------|-----|
|
||||
| tf-iot-producer | https://gitea.services.ngcloud.ru/Nail/tf-iot-producer |
|
||||
| tf-iot-consumer | https://gitea.services.ngcloud.ru/Nail/tf-iot-consumer |
|
||||
|
||||
## Producer (tf-iot-producer)
|
||||
|
||||
`app.py` — Flask + KafkaProducer:
|
||||
- Генерирует фейковые IoT-события (8 датчиков: температура, влажность, энергия)
|
||||
- Шлёт в Kafka каждые `PRODUCE_INTERVAL` секунд (по умолчанию 3)
|
||||
- Топик и брокеры — из env (задаёт Terraform)
|
||||
- SASL_PLAINTEXT аутентификация
|
||||
- `GET /` — статистика (events_sent, errors)
|
||||
- `GET /health` — healthcheck
|
||||
|
||||
## Consumer (tf-iot-consumer)
|
||||
|
||||
`app.py` — Flask + KafkaConsumer + ClickHouse:
|
||||
- Читает события из Kafka, пишет батчами по 10 в ClickHouse
|
||||
- Создаёт таблицу `iot_events` (MergeTree) при старте
|
||||
- SASL_PLAINTEXT → Kafka, HTTP → ClickHouse
|
||||
- `GET /` — статистика (events_consumed, events_in_db)
|
||||
- `GET /health` — healthcheck
|
||||
@@ -0,0 +1,45 @@
|
||||
# Шаг 3 — Terraform-конфиги
|
||||
|
||||
**Дата:** 2026-07-21
|
||||
|
||||
## Созданы файлы
|
||||
|
||||
| Файл | Назначение |
|
||||
|------|-----------|
|
||||
| `main.tf` | Provider, variables |
|
||||
| `locals.tf` | Все настраиваемые параметры |
|
||||
| `kafka.tf` | `nubes_kafka` + topic + user |
|
||||
| `clickhouse.tf` | `nubes_clickhouse` + database + user |
|
||||
| `superset.tf` | `nubes_superset` |
|
||||
| `producer.tf` | `nubes_flask` — IoT продюсер |
|
||||
| `consumer.tf` | `nubes_flask` — IoT consumer |
|
||||
| `terraform.tfvars.example` | Пример переменных |
|
||||
|
||||
## Ресурсы (5 штук)
|
||||
|
||||
```
|
||||
nubes_kafka.main
|
||||
├── nubes_kafka_topic.events (iot-events)
|
||||
└── nubes_kafka_user.app (iot-app, read+write)
|
||||
|
||||
nubes_clickhouse.main
|
||||
├── nubes_clickhouse_database.iot (iot)
|
||||
└── nubes_clickhouse_user.writer (iot_writer)
|
||||
|
||||
nubes_superset.dash
|
||||
|
||||
nubes_flask.producer → Kafka
|
||||
nubes_flask.consumer → Kafka → ClickHouse
|
||||
```
|
||||
|
||||
## Передача секретов
|
||||
|
||||
- Kafka: `vault_secrets["users"]` → пароль пользователя
|
||||
- ClickHouse: `vault_secrets["users"]` → пароль пользователя
|
||||
- Bootstrap servers: `state_out_flat["bootstrapServers"]`
|
||||
- ClickHouse host: `state_out_flat["internalMaster"]`
|
||||
|
||||
## ⚠️ Требует проверки
|
||||
|
||||
- Точные ключи `state_out_flat` для Kafka (`bootstrapServers`) и ClickHouse (`internalMaster`) — нужна верификация на реальном стенде
|
||||
- Формат `vault_secrets["users"]` для Kafka и ClickHouse — аналогичен PostgreSQL, но требует проверки
|
||||
@@ -0,0 +1,41 @@
|
||||
# Шаг 4 — Terraform plan (успех)
|
||||
|
||||
**Дата:** 2026-07-21
|
||||
|
||||
## Результат
|
||||
|
||||
`terraform plan` — **успешно**. 9 ресурсов, 0 ошибок.
|
||||
|
||||
## Исправления
|
||||
|
||||
1. **Синтаксис vault_secrets** — `${local.var}` нельзя использовать после точки.
|
||||
Решение: декодировать в отдельный local, хардкодить username (как в CRUD):
|
||||
```hcl
|
||||
locals {
|
||||
kafka_secrets = jsondecode(nubes_kafka.main.vault_secrets["users"])
|
||||
password = nonsensitive(local.kafka_secrets["iot-app"].password)
|
||||
}
|
||||
```
|
||||
|
||||
2. **ClickHouse обязательные блоки** — добавлены:
|
||||
- `clickhouse_keeper_configuration` (cpu/memory/replicas)
|
||||
- `backup_configuration` (s3_uid/retain/schedule)
|
||||
- `autoscale_configuration` (enabled/percent/quota/schedule)
|
||||
|
||||
## План (9 ресурсов)
|
||||
|
||||
| # | Ресурс | Имя |
|
||||
|---|--------|-----|
|
||||
| 1 | nubes_kafka | iot-kafka |
|
||||
| 2 | nubes_kafka_topic | iot-events |
|
||||
| 3 | nubes_kafka_user | iot-app |
|
||||
| 4 | nubes_clickhouse | iot-clickhouse |
|
||||
| 5 | nubes_clickhouse_database | iot |
|
||||
| 6 | nubes_clickhouse_user | iot_writer |
|
||||
| 7 | nubes_flask | iot-producer |
|
||||
| 8 | nubes_flask | iot-consumer |
|
||||
| 9 | nubes_superset | iot-superset |
|
||||
|
||||
## ⚠️ Остаётся неизвестным
|
||||
|
||||
Ключи `state_out_flat` (`bootstrapServers`, `internalMaster`) и формат `vault_secrets` — станут известны только после `apply`. Завёрнуты в `try()` чтобы не упасть, но реальные значения будут пустыми до создания инстансов.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Шаг 5 — Apply на тестовом стенде (неудача)
|
||||
|
||||
**Дата:** 2026-07-21
|
||||
|
||||
## Результат
|
||||
|
||||
Тестовый стенд (`k8s-3` и `k8s-4`) неработоспособен — инфраструктурные проблемы.
|
||||
|
||||
## Что создалось
|
||||
|
||||
| Ресурс | Статус |
|
||||
|--------|--------|
|
||||
| nubes_kafka.main (iot-kafka) | ✅ Создан |
|
||||
| nubes_kafka_topic.events | ✅ Создан |
|
||||
| nubes_kafka_user.app | ❌ operations формат |
|
||||
| nubes_clickhouse.main (iot-ch) | ❌ helm.altinity.com timeout |
|
||||
| nubes_superset.dash | ❌ IAM 408 timeout |
|
||||
| nubes_flask.producer | ❌ pod не запустился |
|
||||
| nubes_flask.consumer | ❌ (зависит от CH) |
|
||||
|
||||
## Ошибки
|
||||
|
||||
1. **ClickHouse**: GitHub/Helm repo недоступен — `context deadline exceeded`
|
||||
2. **Superset**: IAM error 408 — auth-api-test таймаутит
|
||||
3. **Flask producer**: поды не стартуют — `jlib.k8s [correctReplicaActive] ERROR`
|
||||
4. **Kafka user**: `operations` должен быть `Create,Describe,Read,Write` (исправлено)
|
||||
|
||||
## Исправления в коде
|
||||
|
||||
- `producer.tf` / `consumer.tf`: `vault_secrets` обёрнуты в `try()` с fallback на `"secrets"`
|
||||
- `kafka.tf`: `operations = "Create,Describe,Read,Write"` (было `"read,write"`)
|
||||
- `locals.tf`: `ch_resource_name = "iot-ch"` (было `"iot-clickhouse"`)
|
||||
- `terraform.tfvars`: `realm = "k8s-4-sandbox-nubes-ru"`
|
||||
|
||||
## Решение
|
||||
|
||||
Перенос на DEV-стенд.
|
||||
Reference in New Issue
Block a user