Apache BifroMQ 3.3.5 Docker Compose 部署指南

Apache BifroMQ 3.3.5 Docker Compose 部署指南:自建镜像注入官方发行包,MEM_LIMIT 约束 JVM 堆 512MB 内,数据日志卷持久化与端口映射,mosquitto 完成收发与重启持久化验证,均实测

Apache BifroMQBifroMQ2026/10/13

Apache BifroMQ 3.3.5 Docker Compose 部署指南

目标:使用 Docker Compose 编排 Apache BifroMQ 3.3.5 单机版:基于 eclipse-temurin:17-jre 自建镜像注入官方发行包,通过 MEM_LIMIT 环境变量把 JVM 堆约束在 512MB 以内(实测自动推导 -Xms179m -Xmx358m),数据/日志卷持久化,端口映射到宿主机,并用 mosquitto 客户端完成 QoS0/QoS1/保留消息端到端收发与重启持久化验证。以下命令与回显均为实际执行结果。

一、环境信息

  • 宿主机:Ubuntu 22.04.5 LTS(x86_64),Docker Compose v5.5.1
  • Java 基础镜像:eclipse-temurin:17-jre(本地已有;BifroMQ 硬性要求 JDK 17+)
  • Apache BifroMQ:3.3.5(官方 standalone 发行包 bifromq-3.3.5-standalone.tar.gz,126,286,685 字节,sha256 dd739c43b441dd5008f81543911bea5ec3b3662fdb52d3a9fbd187e902ca76b9)
  • 镜像:自建 bifromq:3.3.5
  • 端口映射:宿主机 11883→1883(MQTT)、18080→8080(WebSocket)、18091→8091(HTTP API)、19090→9090(Prometheus)
  • 客户端工具:mosquitto-clients 2.0.11(在另一台 Ubuntu 实机上执行验证命令)

💡 说明:官方也发布 Docker 镜像(bifromq/bifromq,官方文档示例 docker run -d -p 1883:1883 bifromq/bifromq:latest)。本文采用「自建镜像」方式:发行包已在本地并完成 sha256 校验,自建镜像版本可控、离线可部署。两种方式的环境变量(MEM_LIMIT/JVM_HEAP_OPTS 等)完全一致。

二、目录结构

/opt/bifromq-compose/
├── Dockerfile
├── compose.yaml
└── bifromq-3.3.5-standalone.tar.gz   # 官方发行包(已校验 sha256)

三、Dockerfile

FROM eclipse-temurin:17-jre

WORKDIR /workdir

COPY bifromq-3.3.5-standalone.tar.gz /tmp/bifromq.tar.gz

RUN tar -zxf /tmp/bifromq.tar.gz --strip-components 1 -C /workdir/ \
    && rm -f /tmp/bifromq.tar.gz \
    && chmod +x /workdir/bin/*.sh

EXPOSE 1883 1884 8080 8443 8091 9090

ENTRYPOINT ["/workdir/bin/standalone.sh"]
CMD ["start", "-fg"]

要点:

  • -fg 前台模式启动(standalone.sh start -fg),JVM 进程成为 1 号进程,停止信号可直接送达,符合镜像最佳实践;
  • WORKDIR /workdir 与官方镜像布局一致,data/、logs/ 由启动脚本自动在其下创建,便于挂卷;
  • 基础镜像自带 JRE 17,满足启动脚本的 Java 版本硬校验。

四、compose.yaml

services:
  bifromq:
    image: bifromq:3.3.5
    build:
      context: .
      dockerfile: Dockerfile
    container_name: bifromq-standalone
    hostname: bifromq-mqtt
    ports:
      - "11883:1883"
      - "18080:8080"
      - "18091:8091"
      - "19090:9090"
    environment:
      MEM_LIMIT: "536870912"        # 512MB,JVM 堆按 70% 自动推导
    volumes:
      - bifromq-data:/workdir/data  # 会话/订阅/保留消息持久化
      - bifromq-logs:/workdir/logs
    restart: unless-stopped

volumes:
  bifromq-data:
  bifromq-logs:

💡 MEM_LIMIT 是官方启动脚本识别的内存限额变量(单位:字节):不设 JVM_HEAP_OPTS 时,堆上限 = MEM_LIMIT × 70%,堆下限为其一半,MaxDirectMemorySize = MEM_LIMIT × 20%。512MB 时实测推导结果见下文第六节。

五、构建并启动

cd /opt/bifromq-compose
docker compose up -d --build
docker compose ps

回显:

[+] Running 2/2
 ✔ Container bifromq-standalone  Started
NAME                 IMAGE          STATUS
bifromq-standalone   bifromq:3.3.5  Up 40 seconds

⚠️ 实测坑:在默认地址池已被占满的宿主机上,Compose 创建网络会报 all predefined address pools have been fully subnetted。此时需在 compose.yaml 中显式指定一个未占用网段(服务级引用 networks 时不能内联 ipam,需放顶层 networks 定义):

services:
  bifromq:
    # ...(其余不变)
    networks:
      - bifromq-net

networks:
  bifromq-net:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.144.0/24   # 换成本机未占用网段

常规宿主机无需此配置。

六、验证 JVM 堆约束(MEM_LIMIT 生效实测)

docker exec bifromq-standalone ps aux | grep -oE "\-Xms[0-9]+m \-Xmx[0-9]+m" | head -1

回显:

-Xms179m -Xmx358m

与公式完全吻合:512MB × 70% = 358MB(Xmx),其一半 179MB(Xms),MaxDirectMemorySize 实测为 107374180 字节(512MB × 20%)。无需在镜像里改任何脚本,仅靠 MEM_LIMIT 环境变量即完成堆约束。

💡 若想精确指定堆而不走推导,改设 JVM_HEAP_OPTS: "-Xms256m -Xmx512m" 即可(实测 jps -v 可见 -Xms256m -Xmx512m)。

七、MQTT 端到端收发验证

在另一台 Ubuntu 实机(装有 mosquitto-clients)上,对宿主机 11883 端口执行:

连接与订阅:

mosquitto_sub -h <宿主机IP> -p 11883 -t "e2e/#" -V mqttv5 -d
Client ... received CONNACK (0)
Subscribed (mid: 1): 0

发布(QoS1/QoS0/保留消息各一条):

mosquitto_pub -h <宿主机IP> -p 11883 -t e2e/q1 -m "e2e-qos1-message" -q 1 -d
mosquitto_pub -h <宿主机IP> -p 11883 -t e2e/q0 -m "e2e-qos0-message" -q 0
mosquitto_pub -h <宿主机IP> -p 11883 -t e2e/retain -m "e2e-retained" -q 1 -r
Client (null) received PUBACK (Mid: 1, RC:0)

订阅端实际收到(三条全部通过):

e2e/q1 e2e-qos1-message
e2e/q0 e2e-qos0-message
e2e/retain e2e-retained

保留消息重投递(新建订阅者立即收到):

mosquitto_sub -h <宿主机IP> -p 11883 -t "e2e/retain" -C 1 -W 4
e2e-retained

八、重启持久化验证

docker compose restart

回显:

 Container bifromq-standalone  Started

等待约 30 秒服务就绪后,新订阅者仍能收到重启前发布的保留消息:

e2e-retained

数据卷(bifromq-data)持久化生效;会话、订阅关系与保留消息跨重启保留。

九、Prometheus 指标与管理 API

curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:19090/metrics
200

指标由内置 demo 插件导出,含 basecluster_*(集群成员/健康分)、basekv_*(存储 range/引擎)、ppln_*(RPC 管道)及 MQTT 各子系统指标。

HTTP 管理 API(18091)按 Header 传参(注意默认绑定 site-local 地址,映射前可接受 127.0.0.1 不通为正常):

curl -X POST http://127.0.0.1:18091/pub \
  -H "req_id: 1" -H "tenant_id: bifromq" -H "topic: rest/verify" \
  -H "qos: 0" -H "client_type: curl" -H "client_meta_lang: zh" \
  --data-binary "hello"

回显:

NO_MATCH

HTTP 200 + NO_MATCH 表示发布成功且无匹配订阅者。

十、常用运维命令

docker compose ps                  # 服务状态
docker compose logs -f --tail 100  # 日志(含启动序列 MQTT broker started)
docker compose restart             # 重启(数据卷保留)
docker compose down                # 停止并删除服务(数据卷保留,加 -v 才删卷)
docker compose up -d               # 再次拉起
docker exec bifromq-standalone ls /workdir/logs   # 宿主机查看日志文件

日志确认启动完成(docker compose logs 中出现):

Inbox store started / Retain store started / Dist worker started
MQTT broker started
API server started

十一、常见问题

11.1 拉起后 1883 连不上

首次启动需 30~60 秒完成内部存储引导;用 docker compose logs -f 看到 MQTT broker started 后再连。

11.2 网络创建报 all predefined address pools have been fully subnetted

见第五节:显式指定未占用网段。

11.3 订阅返回 128(Not authorized)

与镜像内 /tmp 挂载策略有关:若底层运行时把 /tmp 挂成 noexec,netty 原生库无法加载,内部 dist 子系统异常(日志有 NativeLibraryLoader ... cannot be executed ... "noexec" flag 告警与 Batcher not found 报错)。确保 /tmp 可执行,或为服务挂载可执行空目录覆盖 /tmp(- /tmp/bifromq-tmp:/tmp,且宿主机该目录不带 noexec)后重启。

11.4 想改端口或开 TLS

镜像内 /workdir/conf/standalone.yml 为配置入口:mqttServerConfig.tcpListener.port、TLS 监听(1884/8443)、apiServerConfig.httpPort 等均在此调整;可再挂载一个只读卷覆盖配置文件(如 - ./standalone.yml:/workdir/conf/standalone.yml:ro)后 docker compose restart。

十二、参考链接