本文覆盖常规同盘项目与跨盘依赖项目两种使用场景,同时包含「依赖清单在线安装」与「完整依赖文件夹打包」两种依赖处理方案,可根据实际情况选择。

一、标准方案:依赖清单在线安装(推荐)

这是 Docker 通用最佳实践,不复制本地虚拟环境或完整依赖文件夹,仅通过依赖清单文件(如 Python 的 requirements.txt)在镜像构建时自动在线安装依赖,生成的镜像体积小、跨平台兼容性强。

1.1 常规同盘场景(项目与依赖清单在同一目录)

适用于项目代码与依赖清单都在同一盘符、同一项目目录下的普通场景。

目录结构

Plain Text
C:\my-project\          # 项目根目录
├── A/                  # 项目代码文件夹
│   └── main.py         # 程序入口
├── requirements.txt    # 依赖清单文件
└── Dockerfile

Dockerfile 编写

dockerfile
# 选择基础运行环境
FROM python:3.10-slim

# 设置容器内工作目录
WORKDIR /app

# 复制项目代码
COPY A /app/A

# 复制依赖清单文件
COPY requirements.txt /app/requirements.txt

# 在线安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 容器启动命令
CMD ["python", "A/main.py"]

构建镜像

在项目根目录打开终端执行:

powershell
cd C:\my-project
docker build -t my-project:v1 .

1.2 跨盘场景(依赖清单在其他盘符)

如果 requirements.txt 不在项目目录,而在其他盘符(如 D:\libs\requirements.txt),有两种处理方式:

方式 1:复制清单到项目目录(最简单)

将其他盘符的 requirements.txt 复制到项目根目录,后续操作与 1.1 完全一致。

方式 2:多构建上下文(不移动文件)

使用 Docker BuildKit 多上下文功能,直接读取跨盘的依赖清单:

dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY --from=project . /app/A
COPY --from=deps requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
CMD ["python", "A/main.py"]

构建命令:

powershell
docker buildx build `
  --build-context project=C:/my-project/A `
  --build-context deps=D:/libs `
  -t my-project:v1 `
  -f Dockerfile .

二、离线方案:打包完整依赖文件夹(特殊依赖适用)

适用于依赖无法在线安装、需要离线运行,或依赖文件夹包含二进制 SDK、模型文件等特殊场景。

2.1 常规同盘场景

如果依赖文件夹与项目在同一盘符、同一上级目录下,直接在 Dockerfile 中复制即可。

目录结构

Plain Text
C:\my-project\
├── A/          # 项目代码
├── B/          # 依赖文件夹
└── Dockerfile

Dockerfile 编写

dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY A /app/A
COPY B /app/B
RUN pip install --no-cache-dir -r B/requirements.txt
CMD ["python", "A/main.py"]

2.2 跨盘场景(依赖在其他盘符)

Docker 构建时有「构建上下文」规则:只能读取命令执行目录及其子目录内的文件,无法直接读取其他盘符 / 上级目录的文件,需先统一目录结构。

步骤 1:整理目录结构

  1. 找到项目根目录,例如 C:\my-project\,存放代码文件夹 A
  1. 找到其他盘符的依赖文件夹,例如 D:\libs\B
  1. 将整个 B 文件夹复制到 C:\my-project\ 下,最终结构与 2.1 一致:

Plain Text
C:\my-project\          
├── A/                  
│   └── main.py         
├── B/                  
│   └── requirements.txt
└── Dockerfile

步骤 2:创建 .dockerignore 优化体积(可选)

在项目根目录新建 .dockerignore 文件,排除无用文件,大幅减小镜像大小:

Plain Text
.git
.venv
node_modules
*.log
__pycache__
.vscode
.idea

步骤 3:构建镜像

powershell
cd C:\my-project
docker build -t my-project:v1 .

参数说明:

  • -t my-project:v1:给镜像命名并标记版本
  • 末尾的 .:代表以当前目录作为构建上下文,绝对不能省略

构建完成后执行 docker images,列表中出现 my-project:v1 即为成功。

三、镜像导出与分享

方式 1:本地文件传输(无需账号)

导出镜像

powershell
docker save -o my-project-v1.tar my-project:v1

执行后项目根目录生成 my-project-v1.tar,将该文件发送给朋友即可。

朋友导入并运行

前置准备:朋友电脑需安装 Docker Desktop(Windows/Mac)或 Docker 引擎(Linux)。

  1. 导入镜像

powershell
docker load -i my-project-v1.tar

执行 docker images 能看到对应镜像即为导入成功。

  1. 启动容器
  • 普通命令行 / 脚本项目:

powershell
docker run --rm my-project:v1

  • Web / 接口服务项目(需端口映射,容器内端口以 8080 为例):

powershell
docker run -d -p 8080:8080 --name my-app my-project:v1

参数说明:

  • -d:后台静默运行
  • -p 8080:8080:本地 8080 端口映射到容器内 8080 端口
  • --name my-app:给容器命名便于管理
  1. 验证运行
  • 命令行项目:查看终端输出
  • Web 项目:浏览器访问 http://localhost:8080

方式 2:云端仓库分享(适合多次分享)

  1. 注册并登录 Docker Hub

powershell
docker login

  1. 给镜像打标签(替换为你的 Docker Hub 用户名)

powershell
docker tag my-project:v1 你的用户名/my-project:v1

  1. 推送镜像到云端

powershell
docker push 你的用户名/my-project:v1

  1. 朋友直接拉取运行

powershell
docker pull 你的用户名/my-project:v1
docker run -d -p 8080:8080 你的用户名/my-project:v1

四、备选挂载方案:运行时挂载依赖(适合 GB 级大体积依赖)

如果依赖体积很大(如 AI 模型、大型 SDK),不想打进镜像导致文件过大,可使用「镜像仅打包代码 + 运行时挂载依赖」的方案。

你这边的操作

  1. Dockerfile 仅打包项目代码

dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY A /app/A
CMD ["python", "A/main.py"]

  1. 构建镜像并导出 tar 包
  1. 将「镜像 tar 包」和「依赖文件夹压缩包」一并发给朋友

朋友那边的操作

  1. 解压依赖文件夹到本地任意路径,例如 D:\deps\B
  1. 导入镜像
  1. 启动容器时添加挂载参数

powershell
docker run -d -p 8080:8080 -v D:/deps/B:/app/B my-project:v1

格式规则:-v 本地依赖绝对路径:容器内依赖路径
容器内的路径 /app/B 必须和代码中读取依赖的路径完全一致,否则会出现依赖找不到的错误。

五、常见问题排查

  1. 构建报错「找不到文件」:检查依赖文件 / 文件夹是否在构建上下文目录内,确认 Dockerfile 中路径拼写正确。
  1. 运行提示找不到依赖:挂载方案请核对容器内路径与代码读取路径是否完全匹配;自包含方案请检查 Dockerfile 中 COPY 路径与依赖安装命令是否正确。
  1. Web 项目无法访问:检查端口映射参数是否正确,确认本地端口未被其他程序占用。

更多推荐