From 582902e47ac900cd018a0f90b2e7d9c554825b95 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Sun, 11 Oct 2026 15:01:31 +0300 Subject: [PATCH] =?UTF-8?q?fix(emqx):=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B7=20?= =?UTF-8?q?=D1=81=20=D0=BE=D0=B4=D0=BD=D0=B8=D0=BC=20EXPOSE=20(scratch)=20?= =?UTF-8?q?+=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=20=D0=B1=D0=B5=D0=B7?= =?UTF-8?q?=20salt=5Frounds=20=E2=80=94=20=D0=BF=D0=BB=D0=B0=D1=82=D1=84?= =?UTF-8?q?=D0=BE=D1=80=D0=BC=D0=B0=20=D1=82=D1=80=D0=B5=D0=B1=D1=83=D0=B5?= =?UTF-8?q?=D1=82=20=D1=80=D0=BE=D0=B2=D0=BD=D0=BE=20=D0=BE=D0=B4=D0=B8?= =?UTF-8?q?=D0=BD=20=D0=BF=D0=BE=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HISTORY/2026-10-11-session-log.md | 39 +++++++++++++++++++++++++++++++ emqx/Dockerfile | 26 ++++++++++++++++----- emqx/emqx.conf | 6 ++++- 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/HISTORY/2026-10-11-session-log.md b/HISTORY/2026-10-11-session-log.md index aa2f3af..fd2f451 100644 --- a/HISTORY/2026-10-11-session-log.md +++ b/HISTORY/2026-10-11-session-log.md @@ -52,3 +52,42 @@ - `go build ./...`, `go vet ./...`, `go test -race ./...` — зелёные. - Push: `54fe1f5..f41a9fe` в `origin/master`. + +## 5. Деплой на Nubes (Terraform) — образ EMQX, 2026-10-11 + +`terraform apply` упал на `nubes_http.iot_emqx` через ~70 с (стадия validation, +22.0 с): платформа требует РОВНО ОДИН `EXPOSE` в образе, иначе +«Не указан applicationUsePort…». У `emqx/emqx:5.5.1` — 7 EXPOSE +(18083/1883/4370/5369/8083/8084/8883). Параметра `applicationUsePort` у +провайдера nubes 3.1.0 нет (проверено: `generated/prod/resources_yaml/98_http.yaml` ++ `generated/prod/docs-rendered/http.md` + исходники провайдера — совпадений нет), +поэтому лечится только пересборкой образа. + +Что сделано (образ `nail/iot-emqx:v0.2.5`): + +1. `emqx/Dockerfile` — multi-stage: `FROM emqx/emqx:5.5.1 AS base` → + `FROM scratch` → `COPY --from=base / /`. EXPOSE/ENV/VOLUME наследуемого образа + НЕ переносятся в `scratch`, поэтому остаётся единственный `EXPOSE 8083`. + ENV `LANG`/`LC_ALL`/`PATH` объявлены заново. `USER emqx` + `WORKDIR /opt/emqx` + + штатные `ENTRYPOINT`/`CMD` базы. + - ⛔ Попытка `FROM debian:bookworm-slim` + `COPY --from=base / /` НЕ работает: + `cannot copy to non-directory: /bin` — в bookworm `/bin` симлинк (usrmerge), + в emqx-образе (Debian 11) `/bin` — реальный каталог. +2. `emqx/emqx.conf` — удалён `salt_rounds = 10` из `password_hash_algorithm`: + схема 5.5.1 его НЕ принимает (`unknown_fields, unknown => "salt_rounds"` → + `call_hocon_failed`, контейнер не стартует). Роль поля нулевая: EMQX только + сверяет bcrypt-хеш из БД, cost берётся из самого хеша. + +Верификация образа (локально): +- `docker inspect … --format '{{json .Config.ExposedPorts}}'` → `{"8083/tcp":{}}`; +- запуск контейнера → `Listener tcp:default on 0.0.0.0:1883 started`, + `Listener ws:default on 0.0.0.0:8083 started`, `EMQX 5.5.1 is running now!`, + статус `running`. Ошибки `econnrefused` к `127.0.0.1:5432` в тесте ожидаемы + (PG рядом нет). +- Реестр Gitea: теги `latest`, `v0.2.4`, `v0.2.5`. +- `terraform.tfvars` / `terraform.tfvars.example`: `iot_emqx_version = "v0.2.5"`. + +⚠️ Блокер деплоя: инстанс `iot-emqx` (`3bdaef8e-e880-4419-870a-bd0158826751`) +остался в состоянии `not created` после неудачного apply и держит имя. По +документации платформы такие инстансы через API не удаляются — удалять вручную +в ЛК (deck). `terraform state list` пуст (в state ничего не записалось). diff --git a/emqx/Dockerfile b/emqx/Dockerfile index c6dbaf0..45b6687 100644 --- a/emqx/Dockerfile +++ b/emqx/Dockerfile @@ -1,14 +1,28 @@ # EMQX для IoT на платформе Nubes. # Образ: gitea.services.ngcloud.ru/nail/iot-emqx (Gitea registry платформы). # -# БАЗА — официальный emqx/emqx:5.5.1 (проверен на платформе: заводится, логи в -# stdout). Добавляем только наш emqx.conf (auth/ACL, listeners, логи). -# ⚠️ У образа 7 EXPOSE-портов (наследие базы) — deck-UI при СОЗДАНИИ требует -# один порт; в НАШЕМ кластере используется kubectl set image, вопрос одного -# EXPOSE для чужого кластера — отдельная задача (тикет Nubes). +# ⚠️ ВАЖНО: платформа Nubes требует РОВНО ОДИН EXPOSE у образа (иначе create падает +# с «Не указан applicationUsePort, а expose в Dockerfile содержит несколько портов»). +# База emqx/emqx:5.5.1 имеет 7 EXPOSE (18083/1883/4370/5369/8083/8084/8883), а EXPOSE +# не удаляется из наследуемого образа. Поэтому копируем rootfs базового образа в чистый +# (EXPOSE НЕ переносится) и выставляем единственный порт 8083. +# +# БАЗА — официальный emqx/emqx:5.5.1. Добавляем только наш emqx.conf (auth/ACL, listeners, логи). -FROM emqx/emqx:5.5.1 +FROM emqx/emqx:5.5.1 AS base + +FROM scratch +COPY --from=base / / + +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 +ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin COPY emqx.conf /opt/emqx/etc/emqx.conf EXPOSE 8083 + +USER emqx +WORKDIR /opt/emqx +ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"] +CMD ["/opt/emqx/bin/emqx", "foreground"] diff --git a/emqx/emqx.conf b/emqx/emqx.conf index 8115376..08f49fd 100644 --- a/emqx/emqx.conf +++ b/emqx/emqx.conf @@ -41,7 +41,11 @@ authentication = [ } password_hash_algorithm { name = bcrypt - salt_rounds = 10 + ## ⚠ salt_rounds НЕ поддерживается схемой 5.5.1 (проверено на образе + ## emqx/emqx:5.5.1: «unknown_fields, unknown => "salt_rounds"» и + ## call_hocon_failed). Оставлять его нельзя — контейнер не стартует. + ## Роль поля нулевая: EMQX только СВЕРЯЕТ хеш из БД, а cost берётся из + ## самого bcrypt-хеша, не из конфига. } query = "SELECT mqtt_password AS password_hash FROM iot_devices WHERE enabled = true AND (namespace || '_' || device_id = ${username} OR (namespace = '__bridge' AND ${username} = device_id)) LIMIT 1" }