如何让Flask容器从另一个Docker容器中渲染HTML页面?
解决方案
核心问题分析
你遇到的TemplateNotFound错误,本质是Flask默认从自身容器内的templates目录查找模板文件,但目标HTML文件存放在另一个流水线容器中,且Flask未配置正确的文件访问路径。要实现需求,需要完成容器间文件共享和Flask路由/模板路径配置两步。
步骤1:实现容器间文件共享
使用Docker卷(推荐)或绑定挂载,将流水线容器中存放HTML的training/metadata目录共享给Flask容器:
方式1:使用Docker卷(适合生产环境)
- 创建一个专用卷:
docker volume create html_shared_volume
- 启动流水线容器时,将
training/metadata目录挂载到卷:
docker run -d -v html_shared_volume:/path/to/training/metadata your-pipeline-image
(替换/path/to/training/metadata为流水线容器内实际的目录路径)
- 启动Flask容器时,同样挂载该卷到容器内的指定目录(比如
/app/shared_metadata):
docker run -d -v html_shared_volume:/app/shared_metadata -p 5002:5002 your-flask-image
方式2:使用绑定挂载(适合开发调试)
如果是本地开发,可直接将主机上的目录作为中间层共享(假设流水线容器的training/metadata目录映射到主机的./local_metadata):
# 启动流水线容器 docker run -d -v ./local_metadata:/path/to/training/metadata your-pipeline-image # 启动Flask容器 docker run -d -v ./local_metadata:/app/shared_metadata -p 5002:5002 your-flask-image
步骤2:配置Flask应用访问共享文件
根据你的需求,有两种实现方式:直接返回静态HTML文件(推荐,因为HTML是预先生成的),或修改Flask模板搜索路径。
方式1:直接返回静态HTML文件(无需Jinja渲染)
这种方式更高效,适合预先生成的静态HTML:
from flask import Flask, send_from_directory, abort app = Flask(__name__) # 共享目录在Flask容器内的路径 SHARED_METADATA_DIR = '/app/shared_metadata' @app.route('/<dir_type>/<num>/<file_name>') def serve_html(dir_type, num, file_name): # 校验目录类型,防止路径遍历攻击 if dir_type not in ['evaluation', 'validation']: abort(403, description="Invalid directory type") # 构造完整文件路径 target_file = f"{dir_type}/{num}/{file_name}.html" try: return send_from_directory(SHARED_METADATA_DIR, target_file) except FileNotFoundError: abort(404, description="HTML file not found") if __name__ == '__main__': app.run(host='0.0.0.0', port=5002)
方式2:修改Flask模板搜索路径(使用Jinja渲染)
如果需要Jinja模板的动态渲染能力(比如后续要添加变量),可以将共享目录添加到Flask的模板路径:
from flask import Flask, render_template, abort app = Flask(__name__) # 将共享目录设置为模板目录 app.template_folder = '/app/shared_metadata' @app.route('/<dir_type>/<num>/<file_name>') def render_html(dir_type, num, file_name): if dir_type not in ['evaluation', 'validation']: abort(403, description="Invalid directory type") template_path = f"{dir_type}/{num}/{file_name}.html" try: return render_template(template_path) except: abort(404, description="Template file not found") if __name__ == '__main__': app.run(host='0.0.0.0', port=5002)
注意事项
- 权限问题:确保流水线容器生成的HTML文件和目录权限允许Flask容器读取。可以让两个容器使用相同的UID/GID运行,或在流水线容器中设置文件权限为
644、目录权限为755。 - 路径遍历防护:路由中添加
dir_type校验,避免恶意请求访问共享目录外的文件。
内容的提问来源于stack exchange,提问作者Daniil Yefimov
相关产品推荐
相关产品推荐

