You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu Server上Docker容器内无法接收MQTT消息的排查

MQTT容器部署后无法接收消息的排查与解决

问题描述

我有一段在Ubuntu Server上运行正常的Python MQTT代码,但部署到Docker容器后无法接收MQTT Broker的消息。已确认容器能连接到外部Broker(用nc -zv mqtt.eclipseprojects.io 1883测试连接成功),只有在Docker Compose中设置network_mode: host时才能正常工作,但这种方式不适合生产环境。

代码如下:

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Callback function when the client connects to the broker
def on_connect(client, userdata, flags, rc):
    logging.info(f"Connected with result code {rc}")
    client.subscribe("mytopic/123")  # Subscribe to the specified topic

# Callback function when a message is received
def on_message(client, userdata, msg):
    logging.info(f"Received message: {msg.payload.decode()} from topic: {msg.topic}")

def main():
    # Load MQTT configuration
    config = {
        "dh_login": "login",
        "dh_password": "pass",
        "host": "mqtt.eclipseprojects.io",
        "port": 1883,
        "topic": "topic/123",
        "qos": 1,
        "mqtt_username": "user",
        "mqtt_password": "pass" 
    }

    # MQTT Broker configuration
    host = config["host"]
    port = config["port"]
    topic = config["topic"]
    qos = config["qos"]
    
    # Create an MQTT client
    client = mqtt.Client()

    # Set MQTT username and password
    client.username_pw_set(config["mqtt_username"], config["mqtt_password"])

    # Set the callback functions
    client.on_connect = on_connect
    client.on_message = on_message

    # Connect to the MQTT broker
    client.connect(host, port, 60)
    
    # Start the loop to receive messages
    client.loop_forever()

if __name__ == "__main__":
    main()

可能的原因

  • 订阅主题不匹配:代码中on_connect回调硬编码订阅"mytopic/123",但配置里的目标主题是"topic/123",如果实际消息发送到后者,客户端根本没订阅正确主题,自然收不到消息。
  • 客户端ID冲突:默认情况下paho-mqtt会生成随机客户端ID,但容器环境中若出现重复ID,Broker可能踢掉旧连接或导致消息路由异常。
  • 会话持久化配置缺失:若使用QoS>0但未开启持久会话,容器重启后Broker不会保存未推送的消息;客户端ID变化也会导致会话丢失。

解决方法

1. 修正订阅主题不匹配问题

将硬编码的订阅主题改为配置变量,避免不一致:

# 创建客户端时传递配置数据
client = mqtt.Client(userdata={"topic": topic, "qos": qos})

def on_connect(client, userdata, flags, rc):
    logging.info(f"Connected with result code {rc}")
    # 使用userdata中的配置订阅主题
    client.subscribe(userdata["topic"], userdata["qos"])

2. 设置唯一客户端ID

为每个容器实例生成唯一客户端ID,避免冲突:

import uuid

# 创建带唯一ID的客户端,同时开启持久会话(可选,需QoS配合)
client = mqtt.Client(
    client_id=f"mqtt-client-{uuid.uuid4()}",
    clean_session=False
)

3. 完善网络与会话配置

  • 保持Docker默认bridge网络模式,无需特殊端口映射(MQTT连接是客户端主动发起的TCP连接,Broker推送消息基于已建立的连接,无需额外端口暴露)。
  • 若使用QoS 1/2,确保开启clean_session=False,让Broker保存未确认的消息,容器重启后可重新接收。

验证步骤

  1. 查看容器日志,确认输出Connected with result code 0,证明on_connect回调正常执行。
  2. 手动发送测试消息到目标主题:
    mosquitto_pub -h mqtt.eclipseprojects.io -t "topic/123" -m "test message"
    
  3. 检查容器日志是否输出接收到的消息。

内容的提问来源于stack exchange,提问作者Gray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 08:42:20