如何在Docker容器中实现flask-serial正常运行?
我用Python和Flask开发了一个Web应用,用来展示通过UART接收的数据,原本在Raspberry Pi Zero上运行正常,依赖flask-serial模块处理串口连接。但改成Docker镜像部署(搭配Nginx处理SSL证书、gunicorn预编译脚本提升性能)后,串口消息无法转发到Python脚本和flask-serial。尝试过参考pyserial的教程修复,但pyserial在Flask项目中无法正常工作。
相关代码配置
主脚本代码
import os from flask_migrate import Migrate from flask_minify import Minify from sys import exit from apps import create_app, db from flask_serial import Serial app = create_app(app_config) Migrate(app, db) ser = Serial(app) # 处理UART消息 @ser.on_message() def handle_message(msg): # 业务逻辑处理
apps/init.py 内容
from flask import Flask def create_app(config): app = Flask(__name__) # flask_serial插件配置 app.config['SERIAL_TIMEOUT'] = 0.2 app.config['SERIAL_PORT'] = '/dev/ttyS0' app.config['SERIAL_BAUDRATE'] = 115200 app.config['SERIAL_BYTESIZE'] = 8 app.config['SERIAL_PARITY'] = 'N' app.config['SERIAL_STOPBITS'] = 1 register_extensions(app) register_blueprints(app) configure_database(app) return app
docker-compose.yaml 内容
version: '3.3' services: mywebapp: container_name: mywebapp restart: always env_file: .env build: . networks: - db_network - web_network volumes: - /dev:/dev privileged: true tty: true nginx: container_name: nginx restart: always image: "nginx:latest" ports: - "80:80" - "443:443" volumes: - ./nginx:/etc/nginx/conf.d - ./certs:/etc/ssl/certs networks: - web_network depends_on: - mywebapp networks: db_network: driver: bridge web_network: driver: bridge
Dockerfile 内容
FROM python:3.9 # 设置环境变量 ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 COPY requirements.txt . # 安装Python依赖 RUN pip install --upgrade pip RUN pip install --no-cache-dir -r requirements.txt COPY . . # 启动gunicorn CMD ["gunicorn", "--config", "gunicorn-cfg.py", "run:app"]
启动命令
docker-compose up --build
可能的解决思路
检查串口设备权限
虽然已挂载/dev:/dev并开启privileged: true,但容器内用户可能没有访问/dev/ttyS0的权限。可在Dockerfile中添加:RUN usermod -aG dialout root或者进入容器手动执行
chmod 666 /dev/ttyS0测试权限是否正常。解决gunicorn多进程冲突
flask-serial的串口监听是单进程模式,gunicorn默认多worker进程会导致多个进程抢占串口资源。修改gunicorn-cfg.py,强制设置单worker:workers = 1验证容器内串口可用性
进入容器执行命令,确认串口设备存在且可访问:docker exec -it mywebapp bash # 查看设备是否存在 ls -l /dev/ttyS0 # 用pyserial测试连接 python -c "import serial; ser = serial.Serial('/dev/ttyS0', 115200); print(ser.is_open); ser.close()"调整
flask-serial初始化时机
将Serial的初始化和消息处理函数移到create_app内部,确保与Flask上下文绑定:# 修改apps/__init__.py from flask_serial import Serial def create_app(config): app = Flask(__name__) # ... 原有配置 ... ser = Serial(app) @ser.on_message() def handle_message(msg): # 业务逻辑处理 # ... 其他注册操作 ... return app确认串口设备路径正确性
Raspberry Pi Zero的UART设备可能是/dev/ttyAMA0而非/dev/ttyS0(取决于蓝牙是否占用串口)。在宿主机执行ls -l /dev/serial/by-id/确认实际设备路径,再修改app配置中的串口路径。
内容的提问来源于stack exchange,提问作者sieller

