python项目打包报错。
每次修改代码或文件结构后,都必须重新构建镜像,以确保 Docker 容器内运行的是最新的代码。Bash。
当你准备将 Python Flask 项目部署到生产环境时,将它打包成 Docker 镜像是一个非常好的做法。这样可以确保你的应用在任何环境中都能以相同的方式运行。使用 docker-compose 可以让你更轻松地管理和运行容器。
下面是打包 Flask 项目并使用 docker-compose 部署的详细步骤。
第一步:创建项目文件
首先,确保你的项目根目录包含以下关键文件:
-
app.py: 你的 Flask 应用主文件。 -
requirements.txt: 包含所有 Python 依赖(包括flask和gunicorn)的列表。 -
Dockerfile: 用于构建 Docker 镜像的脚本。 -
docker-compose.yml: 用于定义和运行 Docker 容器。
这是一个简单的 app.py 示例:
Python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, Dockerized Flask App!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
第二步:创建 requirements.txt
这个文件列出了你的应用需要的所有 Python 包。我们使用 Gunicorn 作为生产环境的 WSGI 服务器,因为它比 Flask 内置的开发服务器更健壮。
Flask==2.3.2
gunicorn==20.1.0
第三步:编写 Dockerfile
Dockerfile 是一个脚本,告诉 Docker 如何从你的源代码构建一个镜像。使用 多阶段构建(Multi-stage build) 是一个好习惯,它可以显著减小最终镜像的大小。
Dockerfile
# Stage 1: Build a virtual environment with dependencies
FROM python:3.9-slim AS builder
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Stage 2: Create a slim production image
FROM python:3.9-slim
WORKDIR /app
# Copy the installed dependencies from the builder stage
COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# Copy your application source code
COPY . .
# Expose the port that the app runs on
EXPOSE 5000
# Define the command to run the application using Gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
代码解释:
-
FROM python:3.9-slim AS builder: 我们使用一个轻量级的 Python 镜像作为构建阶段的基础。 -
COPY requirements.txt .: 复制依赖文件。 -
RUN pip install --no-cache-dir -r requirements.txt: 安装依赖。--no-cache-dir可以避免在镜像中保留 pip 缓存,从而减小镜像大小。 -
FROM python:3.9-slim: 最终的生产镜像,只包含运行应用所需的文件。 -
COPY --from=builder ...: 这是多阶段构建的关键。 我们从builder阶段复制已安装的依赖,而不是再次下载和安装,这样最终镜像就不会包含构建工具,变得更小、更安全。 -
COPY . .: 复制你的项目代码到镜像中。 -
EXPOSE 5000: 声明容器会监听5000端口。 -
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]: 使用gunicorn启动应用。app:app表示从app.py文件中找到名为app的 Flask 应用实例。
第四步:编写 docker-compose.yml
docker-compose.yml 文件用于定义和运行多容器应用。这里我们只定义一个服务,但它让整个过程变得非常简单。
YAML
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/app
restart: always
代码解释:
-
version: '3.8': 指定 Docker Compose 文件的版本。 -
services: 定义所有服务。 -
web: 这是你服务的名称,可以自定义。 -
build: .: 告诉 Docker Compose 在当前目录寻找Dockerfile来构建镜像。 -
ports: - "5000:5000": 将主机的5000端口映射到容器的5000端口。这样你就可以通过http://localhost:5000访问应用了。 -
volumes: - .:/app: (可选,主要用于开发) 将主机上的项目目录挂载到容器的/app目录。当你在本地修改代码时,容器内的代码也会自动更新。 -
restart: always: 确保容器在退出时自动重启。
第五步:构建和运行
有了以上所有文件后,在项目根目录打开终端,只需一条命令就可以完成构建和运行:
Bash
docker-compose up --build
-
--build参数会强制 Docker Compose 重新构建镜像。在第一次运行时或者当你修改了Dockerfile时,这是一个好习惯。
如果你想在后台运行容器,可以使用 -d 参数:
Bash
docker-compose up -d --build
现在,你的 Flask 应用已经在 Docker 容器中成功运行,你可以通过浏览器访问 http://localhost:5000 来查看它
部署后报错
The error ModuleNotFoundError: No module named 'create_app' means your Python application can't find the create_app module when it tries to start.
既然 create_app.py 和 run.py 都在 src 目录下,那么 ModuleNotFoundError 错误的原因是 Python 无法在它的模块搜索路径中找到 create_app。
当你用 gunicorn src.run:app 启动应用时,Python 会将 src 目录作为一个模块来导入。但是,当 run.py 试图执行 from create_app import create_app 时,它默认只在 src 模块内部寻找 create_app,而不是在整个 /app 根目录下。
要解决这个问题,你需要显式地告诉 Python,项目的根目录 /app 也是一个模块搜索路径。
解决方法:更新 Dockerfile
你只需要在 Dockerfile 中添加一个环境变量,将项目的根目录 /app 加入到 Python 的搜索路径中。
这是修改后的 Dockerfile,请特别注意 ENV PYTHONPATH=/app 这行。
Dockerfile
# Stage 1: Build a virtual environment with dependencies
FROM python:3.9-slim AS builder
WORKDIR /app
# 安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Stage 2: Create a slim production image
FROM python:3.9-slim
WORKDIR /app
# 从 builder 阶段复制已安装的依赖
COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# 复制你的整个项目代码
COPY . .
# 关键改动在这里:将 /app 添加到 Python 的模块搜索路径
ENV PYTHONPATH=/app
# 暴露 Flask 应用运行的端口
EXPOSE 5000
# 使用 Gunicorn 启动应用,并指定入口
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "src.run:app"]
修改后的 Dockerfile 有什么作用?
-
ENV PYTHONPATH=/app这一行告诉 Docker,在运行容器时将/app目录作为 Python 查找模块的根目录。 -
这样一来,当
run.py试图导入create_app时,Python 就会在/app目录下寻找create_app这个模块,从而成功找到src/create_app.py。
完成这个修改后,重新构建并运行你的容器:
Bash
docker-compose up --build
你的应用现在应该能正确地找到 create_app.py 并成功启动。
1. 确保 src 是一个合法的包
你的项目文件结构必须是这样的:
.
├── src/
│ ├── __init__.py # 确保这个文件存在且在 src 目录下
│ ├── create_app.py
│ └── run.py
├── Dockerfile
├── requirements.txt
└── docker-compose.yml
__init__.py 文件可以是空的,但它必须存在。它是 Python 识别 src 目录为包的唯一标记。
2. 确保 run.py 使用了正确的相对导入
在你的 src/run.py 文件中,导入 create_app 的语句必须是相对导入。
错误的导入方式:
Python
# 这会导致 ModuleNotFoundError 错误
from create_app import create_app
正确的导入方式:
Python
# 使用相对导入,' . ' 表示在当前包中寻找
from .create_app import create_app
3. 确保 Dockerfile 中的 CMD 命令正确
你的 Dockerfile 应该使用 gunicorn 的命令来启动应用,这个命令会告诉 Python 从 /app 根目录开始寻找 src 这个包。
Dockerfile
# ... (其他设置) ...
# 将 /app 添加到 Python 的模块搜索路径
ENV PYTHONPATH=/app
# 暴露 Flask 应用运行的端口
EXPOSE 5000
# 正确的启动命令:gunicorn 导入 src 包中的 run 模块,并找到 app 实例
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "src.run:app"]
如果你已经按照上面的步骤检查并修改了文件,那么问题应该已经解决了。
最后一步:重新构建镜像
每次修改代码或文件结构后,都必须重新构建镜像,以确保 Docker 容器内运行的是最新的代码。
Bash
docker-compose up --build
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)