Docker Compose多容器调用与跨容器模块导入问题求助
解决方案
问题1:跨容器导入模块失败的根本原因与解决思路
容器是完全隔离的独立运行环境,每个容器拥有自己的文件系统、进程空间,本地运行时两个服务共享同一个Python环境,但Docker中mqtt_subscriber容器内根本不存在python_can的代码文件,所以无论怎么设置sys.path都无法跨容器导入模块——这是Docker隔离性的核心特性,不是路径配置问题。
正确的做法是:放弃跨容器导入代码的思路,通过Docker API来控制python_can容器的启停。
问题2:避免自动启动python_can容器的实现方案
不在docker-compose.yml中声明python_can服务,提前构建好它的镜像,然后在mqtt_subscriber中通过Python的Docker SDK动态启停容器,既避免自动启动,又保持服务独立性。
具体操作步骤
1. 构建python_can镜像(提前完成,不依赖docker-compose)
进入项目根目录ODS,执行构建命令:
docker build -t python-can-image ./python_can
2. 配置mqtt_subscriber服务
- 修改requirements.txt:添加Docker SDK依赖,在
mqtt_subscriber/requirements.txt中加入一行:docker - 修改mosquitto_subscriber.py:用Docker SDK实现容器启停逻辑,示例代码片段:
import docker import paho.mqtt.client as mqtt # 初始化Docker客户端(通过挂载的/var/run/docker.sock与宿主机Docker交互) docker_client = docker.from_env() CAN_CONTAINER_NAME = "python_can_container" def on_mqtt_message(client, userdata, msg): payload = msg.payload.decode("utf-8").strip() if payload == "1": # 启动容器:存在则启动,不存在则创建并启动 try: container = docker_client.containers.get(CAN_CONTAINER_NAME) if container.status != "running": container.start() except docker.errors.NotFound: docker_client.containers.run( image="python-can-image", name=CAN_CONTAINER_NAME, network_mode="host", detach=True, volumes={"/var/run/docker.sock": {"bind": "/var/run/docker.sock", "mode": "ro"}} ) print("python_can容器已启动") elif payload == "0": # 停止容器:存在则停止 try: container = docker_client.containers.get(CAN_CONTAINER_NAME) if container.status == "running": container.stop() print("python_can容器已停止") except docker.errors.NotFound: print("python_can容器不存在,无需停止") # 以下为MQTT客户端初始化、连接等代码(保持原有逻辑即可) mqtt_client = mqtt.Client() mqtt_client.on_message = on_mqtt_message # ... 其他MQTT配置 ...
3. 简化docker-compose.yml
移除python_can服务,最终配置如下:
version: '3' services: mqtt_subscriber: build: context: . dockerfile: ./mqtt_subscriber/Dockerfile network_mode: "host" restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock
4. 启动mqtt_subscriber服务
docker-compose up -d
额外优化点
- 修改
python_can/Dockerfile的CMD指令:去掉末尾的&(Docker容器本身以进程为核心,&是shell后台运行语法,容器内不需要):CMD ["python3", "./python_can/can_logger.py"]
内容的提问来源于stack exchange,提问作者Adriana Treviño
相关产品推荐
相关产品推荐

