如何在Docker容器中实现Flask与notification.py子进程并行运行?
解决Flask与notification.py并行运行的问题
问题根源
subprocess.run()是阻塞调用,会卡住Flask启动流程,必须等notification.py运行结束才会继续,导致Flask无法正常启动。subprocess.Popen()没效果,大概率是因为你用了stdout=subprocess.PIPE但未读取输出,子进程会因输出缓冲区被占满而挂起,看起来像没运行。
可行方案
方案1:用Python multiprocessing模块(单进程内并行)
直接用Python自带的多进程模块启动脚本,更可控:
from multiprocessing import Process import os import sys def run_notification(): BASE_DIR = os.path.dirname(os.path.abspath(__file__)) notification_path = os.path.join(BASE_DIR, "notifications_script.py") # 导入脚本并执行(假设脚本有main入口函数) sys.path.insert(0, BASE_DIR) import notifications_script notifications_script.main() # 在Flask启动前启动子进程 if __name__ == '__main__': p = Process(target=run_notification) p.daemon = True # 设置为守护进程,Flask退出时自动结束 p.start() # 启动Flask应用 from app import app app.run(host='0.0.0.0', port=5000)
如果notification.py是直接执行的脚本(无main函数),可以配合subprocess并处理输出:
from multiprocessing import Process import subprocess import os def run_notification(): BASE_DIR = os.path.dirname(os.path.abspath(__file__)) notification_path = os.path.join(BASE_DIR, "notifications_script.py") # 重定向输出到容器日志,避免缓冲区阻塞 subprocess.Popen( ['python', notification_path], shell=False, stdout=open('/proc/self/fd/1', 'w'), stderr=subprocess.STDOUT ) if __name__ == '__main__': p = Process(target=run_notification) p.daemon = True p.start() from app import app app.run(host='0.0.0.0', port=5000)
方案2:Docker多容器部署(推荐)
既然已经用Docker,把Flask和notification拆成两个独立容器,用Docker Compose管理,更符合容器化最佳实践:
# docker-compose.yml version: '3.8' services: flask-app: build: ./flask ports: - "5000:5000" # 按需添加环境变量、卷挂载等配置 depends_on: - notification-service notification-service: build: ./flask # 复用Flask镜像,或单独构建 command: python notifications_script.py # 按需添加环境变量、卷挂载等配置
两个服务独立运行,互不干扰,日志也能分开查看。
方案3:用Supervisor管理单容器内多进程
如果必须在同一个容器运行,用Supervisor进程管理器同时启动Flask和脚本:
- Dockerfile中安装supervisor:
RUN apt-get update && apt-get install -y supervisor
- 创建
supervisord.conf配置文件:
[supervisord] nodaemon=true [program:flask] command=gunicorn -w 4 -b 0.0.0.0:5000 app:app # 生产环境用gunicorn替代内置服务器 directory=/app stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:notification] command=python notifications_script.py directory=/app stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0
- Dockerfile最后设置启动命令:
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf CMD ["supervisord"]
内容的提问来源于stack exchange,提问作者mick_dev
相关产品推荐
相关产品推荐

