feat(iot): MQTT over WebSocket workaround via nginx-ingress
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.
This commit is contained in:
@@ -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
|
||||||
@@ -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` и т.д.
|
||||||
Reference in New Issue
Block a user