From 6e3e473551e6df086a8b6ce1ffe7f8f1d988538e Mon Sep 17 00:00:00 2001 From: Naeel Date: Sat, 4 Apr 2026 14:06:17 +0300 Subject: [PATCH] feat(iot): MQTT over WebSocket workaround via nginx-ingress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port 1883 blocked by NSX-T Edge firewall (DevOps to open on Monday). Temporary solution: EMQX WebSocket listener (8083) via nginx-ingress. - Service emqx-ws: selector app=emqx, port 8083 - Ingress emqx-mqtt-websocket: iot.kube5s.ru/mqtt → emqx-ws:8083 - pathType: Exact (prevents trailing slash redirect breaking WS handshake) - ssl-redirect: false (IoT devices cannot follow HTTP 301 redirects) - DNS A record iot.kube5s.ru → 185.247.187.147 created by user Tested: Connected rc=0 via paho-mqtt WebSocket from inside cluster. --- deployments/k8s/emqx-ws-ingress.yaml | 51 +++++++++++++++++++++++++ doc/thinking/2026-04-04-02.md | 57 ++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 deployments/k8s/emqx-ws-ingress.yaml create mode 100644 doc/thinking/2026-04-04-02.md diff --git a/deployments/k8s/emqx-ws-ingress.yaml b/deployments/k8s/emqx-ws-ingress.yaml new file mode 100644 index 0000000..df382fe --- /dev/null +++ b/deployments/k8s/emqx-ws-ingress.yaml @@ -0,0 +1,51 @@ +# Создано: 2026-04-04 +# ВРЕМЕННЫЙ WORKAROUND: MQTT over WebSocket через порт 443. +# Причина: порт 1883 заблокирован NSX-T Edge firewall на уровне облака. +# Решение: EMQX WebSocket listener (8083) проксируется через nginx-ingress. +# +# IoT устройство подключается: ws://iot.kube5s.ru/mqtt +# DNS A-запись: iot.kube5s.ru → 185.247.187.147 (создана через Nubes API, zoneUid=498096ee) +# +# Когда DevOps откроет порт 1883 — этот файл можно удалить. +--- +apiVersion: v1 +kind: Service +metadata: + name: emqx-ws + namespace: sless + # Отдельный Service чтобы не путать — WebSocket порт для Ingress +spec: + selector: + app: emqx + ports: + - name: mqtt-ws + port: 8083 + targetPort: 8083 + protocol: TCP +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: emqx-mqtt-websocket + namespace: sless + annotations: + kubernetes.io/ingress.class: nginx + # ssl-redirect=false: IoT устройства не умеют следовать 301 редиректам при WebSocket upgrade + nginx.ingress.kubernetes.io/ssl-redirect: "false" + # WebSocket: nginx-ingress автоматически добавляет Upgrade/Connection при proxy-http-version=1.1 + nginx.ingress.kubernetes.io/proxy-http-version: "1.1" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" +spec: + ingressClassName: nginx + rules: + - host: iot.kube5s.ru + http: + paths: + - path: /mqtt + pathType: Exact + backend: + service: + name: emqx-ws + port: + number: 8083 diff --git a/doc/thinking/2026-04-04-02.md b/doc/thinking/2026-04-04-02.md new file mode 100644 index 0000000..af201a4 --- /dev/null +++ b/doc/thinking/2026-04-04-02.md @@ -0,0 +1,57 @@ +# Лог мышления — 2026-04-04-02 + +## Агент: GitHub Copilot (Claude Sonnet 4.6) + +Продолжение сессии от 2026-04-04 (файл 2026-04-04.md достиг 681 строки). + +--- + +## Задача: MQTT WebSocket через nginx-ingress — отладка 404 → 400 + +### Контекст + +Порт 1883 заблокирован NSX-T Edge firewall на уровне облака. +Временный workaround: EMQX WebSocket listener (8083) → nginx-ingress → `iot.kube5s.ru/mqtt`. + +### Что нашёл + +**Проблема 1 — 404:** Ingress не получил ADDRESS (IP не присвоен). +- Причина: annotation `nginx.ingress.kubernetes.io/configuration-snippet` заблокирован в nginx-controller v1.12.6. + По умолчанию `allow-snippet-annotations=false`. +- Решение: убрал `configuration-snippet` из Ingress. +- Результат: Ingress получил sync (Scheduled for sync), но ADDRESS всё ещё пустой — это нормально для данного контроллера. + +**Проблема 2 — 400:** После удаления snippet стало 400 вместо 404. +- nginx конфиг для `iot.kube5s.ru` правильный: + - `proxy_set_header Upgrade $http_upgrade` — ЕСТЬ (nginx-ingress добавляет автоматически) + - `proxy_http_version 1.1` — ЕСТЬ + - `proxy_send_timeout/read_timeout 3600s` — ЕСТЬ + - `proxy_pass → sless-emqx-ws-8083` — ЕСТЬ +- Значит 400 приходит от EMQX, а не от nginx. + +### Гипотезы почему EMQX возвращает 400 + +EMQX WebSocket listener конфиг: +``` +listeners.ws.default { + bind = "0.0.0.0:8083" + max_connections = 512 +} +``` + +Нет явного `websocket.path`. По умолчанию EMQX ожидает путь `/mqtt`. +Но nginx из-за `pathType: Prefix` на `/mqtt` может передавать путь без trailing slash. + +**Вариант A**: nginx передаёт запрос на `/mqtt` (без `/`) — EMQX ожидает `/mqtt` → должно работать. +**Вариант B**: EMQX в 5.5.1 ожидает `ws://host/mqtt` без всякого proxy path rewrite и есть баг с `X-Forwarded-Proto` — nginx шлёт `http`, а EMQX может редиректить. +**Вариант C**: `ssl_redirect: true` в nginx конфиге означает что HTTP запрос перенаправляется на HTTPS, и там 400. + +### Следующий шаг + +Проверить `$ssl_redirect = true` в nginx server block для нашего хоста: +- Если да — nginx делает redirect HTTP→HTTPS +- Добавить аннотацию `nginx.ingress.kubernetes.io/ssl-redirect: "false"` или тестировать через HTTPS + +### Правило (новое) + +Если файл `doc/thinking/ГГГГ-ММ-ДД.md` стал большим — создавать `ГГГГ-ММ-ДД-02.md`, `ГГГГ-ММ-ДД-03.md` и т.д.