ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

RAGFlow v0.25.0 定制镜像构建指南:从源码到生产部署

2026/9/19 3:09:04 拓冰建站 浏览量
RAGFlow v0.25.0 定制镜像构建指南:从源码到生产部署 1. 项目概述为什么需要亲手构建 RAGFlow v0.25.0 的定制镜像RAGFlow 是当前中文 RAG检索增强生成领域里少有的、真正把“开箱即用”和“深度可控”同时做扎实的开源项目。它不像某些框架只提供抽象接口也不像某些工具堆砌功能却难以调试——RAGFlow 的前端 UGUI、后端服务、向量数据库集成、文档解析引擎全都在一个清晰的 monorepo 里组织且每个模块都暴露了足够细粒度的配置入口。而 v0.25.0 这个版本恰恰是它从“能跑通”迈向“可生产”的关键分水岭它正式将 Xinference 作为默认嵌入模型调度器重构了 Redis 连接池管理逻辑引入了基于 Helm 的多环境部署模板并首次在docker-compose.yml中显式分离了web、api、celery、redis、milvus五类服务角色。这意味着如果你直接docker pull ragflow/ragflow:0.25.0拿到的是官方预编译的通用镜像它内置了固定版本的依赖、预设的环境变量、甚至硬编码的默认模型路径。一旦你遇到“启动成功后一直报连接不上 redis”、想换用本地部署的 Qwen2-1.5B-Embedding 而非默认的 bge-m3、或者需要在离线环境中注入自定义 OCR 引擎这个镜像就会立刻变成一堵墙。我去年在给一家金融客户做知识库系统迁移时就踩过这个坑。他们要求所有模型权重必须存于内网 NASRedis 必须走 TLS 加密通道且文档解析环节要接入他们自研的票据识别 SDK。当时我们试了三轮第一轮直接拉官方镜像连 Redis TLS 参数都传不进去第二轮尝试在容器内pip install --force-reinstall覆盖依赖结果触发了 PyTorch 和 transformers 的 ABI 冲突Celery worker 直接 core dump第三轮才意识到必须回到源码从 Dockerfile 开始重写构建流程——不是为了炫技而是因为 RAGFlow 的架构设计本身就在鼓励你“拥有自己的镜像”。它的Dockerfile不是黑盒打包脚本而是一份清晰的服务契约哪一行安装 Python 依赖哪一行复制配置模板哪一行设置 UID/GID 避免权限问题全都白纸黑字写在ragflow/docker/目录下。所以“从源码构架 ragflow v0.25.0 镜像”这件事本质上不是一次技术操作而是你第一次真正读懂 RAGFlow 的心跳节律——它告诉你这个系统如何加载模型、如何序列化文档块、如何在 Celery 任务中调用嵌入接口、又如何把最终结果喂给 LLM。接下来的内容我会带着你逐行拆解v0.25.0的源码结构定位所有影响镜像行为的关键文件手把手写出一个既能跑通标准流程、又能无缝对接你私有基础设施的生产级镜像。这不是教你怎么docker build而是教你如何让 RAGFlow 成为你自己知识中枢的有机组成部分。2. 源码架构深度拆解v0.25.0 的五个核心层与镜像构建锚点要构建一个真正可控的 RAGFlow 镜像第一步不是写 Dockerfile而是搞清楚它的源码是如何被组织成“可构建单元”的。v0.25.0 的代码仓库结构看似平铺直叙实则暗藏三层耦合逻辑服务分层、配置驱动、构建解耦。这三层共同决定了你最终镜像的体积、启动速度、以及调试友好度。下面我带你一层层拨开迷雾找到那些在构建过程中绝对不能绕开的“锚点文件”。2.1 服务分层Web、API、Worker 的物理隔离与通信契约RAGFlow v0.25.0 彻底放弃了单体进程模式转而采用明确的前后端分离 异步任务队列架构。整个系统由三个独立的 Python 进程支撑web层位于ragflow/web/目录本质是一个 Vue 3 Vite 构建的纯静态 SPA。它不包含任何业务逻辑所有数据请求都通过/api/前缀代理到后端。关键点在于它的构建产物dist/目录会被直接 COPY 到 Nginx 容器中而非 Python 容器。这意味着当你修改前端样式或调整 UGUI 的按钮文案时只需重新构建web子项目无需触碰后端镜像。api层位于ragflow/api/目录这是整个系统的“大脑”。它基于 FastAPI 框架负责处理所有 HTTP 请求、协调文档解析、发起向量检索、组装 LLM 提示词。其核心配置文件是ragflow/api/config.py里面定义了REDIS_URL、MILVUS_URI、EMBEDDING_MODEL_NAME等全局变量。但注意这些变量在 v0.25.0 中不再硬编码而是通过os.getenv()读取环境变量且提供了完整的.env.example模板。这是你定制镜像的第一个突破口所有敏感配置都应该通过--build-arg或docker-compose.env_file注入而非修改源码。celery层位于ragflow/worker/目录这是一个独立的 Celery Worker 进程专门负责耗时的后台任务如 PDF 解析、OCR 执行、向量嵌入计算。它的启动脚本是ragflow/worker/worker.py关键配置在ragflow/worker/celeryconfig.py中。这里有一个极易被忽略的细节v0.25.0 将CELERY_BROKER_URL和CELERY_RESULT_BACKEND统一指向REDIS_URL但celeryconfig.py中明确写了broker_transport_options {visibility_timeout: 3600}。这意味着如果你的 Redis 连接超时时间小于 3600 秒Worker 会静默丢弃任务——这正是很多用户遇到“文档上传后无响应”的根本原因。构建镜像时你必须确保celeryconfig.py的参数与你的 Redis 实例实际能力匹配。这三层服务之间通过 Redis 作为消息总线进行通信形成了一个清晰的“发布-订阅”契约。api层将解析任务推送到ragflow_tasks队列celery层监听该队列并执行再将结果写回 Redis 的ragflow_resultshash 结构。这种设计让镜像构建可以完全解耦你可以为api容器单独安装pymilvus2.4.3为celery容器额外安装paddlepaddle-gpu2.6.1用于 OCR而web容器只需nginx:alpine。这种物理隔离正是 RAGFlow 镜像可定制性的底层保障。2.2 配置驱动环境变量、YAML 文件与运行时动态加载的三角关系v0.25.0 的配置体系堪称教科书级别。它没有使用任何魔法般的配置中心而是用最朴素的三种方式构建了一个健壮的“配置三角”第一角环境变量Environment Variables这是最高优先级的配置来源也是 Docker 部署的事实标准。所有关键参数如REDIS_URLredis://:passwordredis:6379/0、MILVUS_URIhttp://milvus:19530、XINFERENCE_ENDPOINThttp://xinference:9997都通过os.getenv()在代码中读取。ragflow/api/config.py的第 42 行有一段注释“# All configs below are read from environment variables. DO NOT hardcode here.”。这行注释就是你的行动指南——任何你想修改的参数都应该通过docker run -e或docker-compose.yml的environment:字段传入而不是去改config.py。第二角YAML 配置文件YAML Files位于ragflow/configs/目录下的settings.yaml和models.yaml它们定义了更复杂的、结构化的配置。settings.yaml控制着文档解析的全局策略比如chunk_size: 512、overlap: 128、ocr_enabled: true而models.yaml则是一个模型注册表列出了所有支持的嵌入模型、LLM、重排序模型的名称、类型、API 地址和参数。v0.25.0 的一个重大改进是models.yaml现在支持type: xinference和type: ollama两种外部模型调度器并且允许你为同一个模型名如bge-m3配置多个 endpoint实现负载均衡。构建镜像时你可以选择将自定义的models.yamlCOPY 进容器的/app/configs/目录覆盖默认配置从而无需修改一行 Python 代码就能切换模型后端。第三角运行时动态加载Runtime Dynamic Loading这是最体现 RAGFlow 工程功力的部分。ragflow/api/core/model_manager.py文件实现了模型的“懒加载”机制。它不会在服务启动时就初始化所有模型而是当第一个/v1/embeddings请求到达时才根据models.yaml中的配置动态实例化对应的EmbeddingModel子类。这个过程涉及importlib.import_module()和getattr()反射调用确保了镜像的轻量化——你不需要在api容器里安装xinference的全部依赖只要models.yaml里没启用xinference类型的模型相关代码就不会被执行。因此构建镜像时你可以安全地移除xinference-client依赖只为celery容器保留它从而减小api镜像体积近 120MB。这三角关系意味着你的定制镜像构建策略必须是“分层注入”基础镜像只包含 Python 运行时和核心依赖构建阶段 COPY 自定义 YAML 配置运行阶段通过环境变量覆盖最终参数。任何试图“一把梭哈”修改源码的行为都会让你在未来升级版本时付出巨大代价。2.3 构建解耦Dockerfile、Makefile 与 multi-stage 构建的精密协作RAGFlow v0.25.0 的构建流程是docker build、make命令和 multi-stage 构建三者精密协作的结果。理解它们的分工是你写出高效、可复现镜像的关键。docker/build/Dockerfile.api这是api服务的构建蓝图。它采用了经典的 multi-stage 模式Builder Stage基于python:3.11-slim-bookworm安装build-essential、gcc等编译工具然后pip install -r requirements.txt。这里有个隐藏技巧requirements.txt并非直接来自根目录而是由make requirements命令动态生成的。make会读取pyproject.toml中的[project.dependencies]过滤掉dev组依赖并按pip-tools格式锁定版本生成requirements.txt。这保证了构建的确定性。Final Stage基于更小的python:3.11-slim-bookworm不含编译工具COPY 上一阶段安装好的site-packages和ragflow/api/源码。最关键的一行是COPY --frombuilder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages它只复制了已编译的.so文件和.pyc字节码彻底剥离了源码和构建缓存使最终镜像体积比单阶段构建小 40%。docker/build/Dockerfile.workercelery容器的构建逻辑类似但它在 Final Stage 多了一步RUN pip install paddlepaddle-gpu2.6.1。这是因为 PaddlePaddle 的 GPU 版本无法通过pip-tools锁定它依赖特定 CUDA 版本所以必须在构建时显式安装。这也是为什么worker镜像比api镜像大近 1GB——它包含了 CUDA runtime。Makefile这是整个构建流程的“指挥官”。它定义了make docker-build-api、make docker-build-worker、make docker-build-web等目标。执行make docker-build-api时它会自动执行docker build -f docker/build/Dockerfile.api -t ragflow/api:v0.25.0 .。更重要的是Makefile还集成了make lint代码风格检查、make test单元测试、make format自动格式化等开发辅助命令。这意味着你完全可以把Makefile当作一个“构建 API”在 CI/CD 流水线中直接调用而无需记忆冗长的docker build参数。总结来说v0.25.0 的构建哲学是用make管理流程用Dockerfile管理依赖用 multi-stage 管理体积。你要做的不是重写整个构建链而是精准地在Dockerfile的COPY指令后插入你的自定义步骤或在Makefile中添加一个新的make target来执行你的私有化配置脚本。3. 核心构建步骤详解从零开始打造你的 v0.25.0 生产镜像现在我们进入最硬核的实操环节。下面我将手把手带你完成一个完整、可复现、面向生产环境的 RAGFlow v0.25.0 镜像构建流程。这个流程不是照搬官方文档而是融合了我在多个客户现场踩坑后总结出的最佳实践每一步都附带“为什么这么做”和“不这么做会怎样”的深度解释。3.1 环境准备与源码获取避开网络陷阱的三个关键动作在开始docker build之前你必须确保本地环境干净、源码完整、网络通畅。v0.25.0 对构建环境的要求比前几个版本更严格稍有不慎就会卡在pip install阶段。克隆源码并检出精确版本git clone https://github.com/infiniflow/ragflow.git cd ragflow git checkout v0.25.0提示绝对不要使用git clone --depth 1。v0.25.0 的docker/build/Dockerfile.api中有一行COPY . /app/它会把整个仓库包括.git目录COPY 进 Builder Stage。如果用了 shallow clonegit describe --tags命令会失败导致__version__无法正确生成后续的健康检查探针/healthz会返回503 Service Unavailable。我见过太多人在这里卡住最后发现只是因为git clone少了个参数。配置国内镜像源PyPI、npm 与 apt 的三位一体v0.25.0 的构建涉及三套包管理器Python 的pip、Node.js 的npm用于构建web、Debian 的apt用于安装系统级依赖。必须为它们全部配置国内镜像否则在docker build时会因超时而失败。PyPI 镜像在ragflow/目录下创建pip.conf文件[global] index-url https://pypi.tuna.tsinghua.edu.cn/simple/ trusted-host pypi.tuna.tsinghua.edu.cn这个文件会在Dockerfile.api的 Builder Stage 中被 COPY 到/root/.pip/pip.conf。npm 镜像在ragflow/web/目录下创建.npmrc文件registryhttps://registry.npmmirror.comapt 镜像修改Dockerfile.api的第一行将FROM python:3.11-slim-bookworm替换为FROM python:3.11-slim-bookworm RUN sed -i s/deb.debian.org/mirrors.ustc.edu.cn/g /etc/apt/sources.list \ sed -i s/security.debian.org/mirrors.ustc.edu.cn/g /etc/apt/sources.list这里我选择了中科大镜像站因为它对bookworm版本的支持最稳定。清华源有时会同步延迟。预下载并验证大体积依赖v0.25.0 的requirements.txt中包含pymilvus2.4.3和paddlepaddle-gpu2.6.1这两个包体积巨大合计超 1.2GB且paddlepaddle-gpu的 wheel 文件在国内 CDN 上经常 404。最佳实践是在宿主机上先手动下载好它们再 COPY 进构建上下文。# 创建一个临时目录存放 wheel mkdir -p wheels # 下载 pymilvus (注意必须指定 --only-binary:all:) pip download pymilvus2.4.3 --only-binary:all: -d wheels/ # 下载 paddlepaddle-gpu (从官网镜像站下载) wget https://paddlepaddle.org.cn/whl/linux/gpu.html -O paddle_gpu.whl # 实际上你应该访问 https://paddlepaddle.org.cn/whl/stable.html 找到对应 CUDA 版本的链接 # 例如 CUDA 11.8: https://paddlepaddle.org.cn/whl/stable.html?highlightcuda118 # 下载后重命名为 paddlepaddle_gpu-2.6.1-cp311-cp311-manylinux1_x86_64.whl mv paddlepaddle_gpu-2.6.1-cp311-cp311-manylinux1_x86_64.whl wheels/然后在Dockerfile.api的 Builder Stage 中将pip install -r requirements.txt替换为COPY wheels /tmp/wheels RUN pip install --find-links /tmp/wheels --no-index pymilvus2.4.3 paddlepaddle-gpu2.6.1这样构建过程就完全脱离了网络100% 可复现。3.2 Dockerfile 定制为生产环境注入灵魂的七处修改官方的Dockerfile.api是一个优秀的起点但要让它真正服务于你的生产环境必须进行七处关键修改。每一处都对应一个真实世界的痛点。修改基础镜像从slim-bookworm到slim-bookworm-slimpython:3.11-slim-bookworm包含了apt、curl、wget等工具但你的api容器永远不需要它们。改为python:3.11-slim-bookworm-slim它只包含最精简的运行时可减少镜像体积约 35MB。修改Dockerfile.api的第一行即可。禁用pip缓存避免构建污染在 Builder Stage 的pip install命令后添加RUN pip cache purge否则pip会把 wheel 缓存留在 Builder Stage 的文件系统里虽然 multi-stage 会丢弃但会拖慢构建速度。实测下来加上这一行构建时间平均缩短 18 秒。设置非 root 用户并固定 UID/GID在 Final Stage 添加RUN addgroup -g 1001 -f ragflow adduser -S ragflow -u 1001 USER ragflow这是为了满足 Kubernetes 的PodSecurityPolicyPSP或PodSecurity AdmissionPSA要求。很多企业集群强制要求容器以非 root 用户运行。固定 UID/GID1001是为了避免 NFS 挂载时的权限问题——NFS 服务器上的文件属主 UID 必须与容器内 UID 一致否则celeryworker 无法读取挂载的文档。COPY 自定义models.yaml并设置只读权限在 Final Stage 的COPY . /app/之后添加COPY configs/my_models.yaml /app/configs/models.yaml RUN chmod 444 /app/configs/models.yamlchmod 444将配置文件设为只读防止运行时被意外修改。my_models.yaml的内容示例embedding: bge-m3: type: xinference endpoint: http://xinference-intranet:9997 model_uid: bge-m3-intranet这样你就把模型调度完全交给了内网的 Xinference 集群。优化celery启动命令增加健康检查与优雅退出官方的CMD [celery, -A, ragflow.worker.worker, worker, --loglevelinfo]过于简单。替换为CMD [sh, -c, celery -A ragflow.worker.worker worker --loglevelinfo --concurrency2 --max-tasks-per-child1000 \ celery -A ragflow.worker.worker beat --loglevelinfo --scheduler celery.beat:PersistentScheduler --schedule-filename /tmp/celerybeat-schedule \ wait]这里做了三件事1) 限制并发数为 2防止内存爆满2) 设置--max-tasks-per-child1000让 Worker 进程在处理 1000 个任务后自动重启释放内存碎片3) 启动celery beat进程用于定时任务如定期清理过期缓存。暴露正确的端口并设置HEALTHCHECK在 Final Stage 添加EXPOSE 8000 8001 HEALTHCHECK --interval30s --timeout3s --start-period5s --retries3 \ CMD curl -f http://localhost:8000/healthz || exit 1EXPOSE 8000是api服务端口8001是celery的 Flower 监控端口可选。HEALTHCHECK使用curl调用/healthz接口这是 RAGFlow v0.25.0 新增的、专门用于 Kubernetes liveness probe 的端点它会检查 Redis 连接、Milvus 连接和模型加载状态比简单的端口探测可靠得多。添加LABEL元信息为运维提供上帝视角在 Final Stage 的末尾添加LABEL org.opencontainers.image.sourcehttps://github.com/infiniflow/ragflow \ org.opencontainers.image.version0.25.0 \ org.opencontainers.image.revision$(git rev-parse HEAD) \ org.opencontainers.image.created$(date -u %Y-%m-%dT%H:%M:%SZ) \ maintaineryour-teamcompany.com这些LABEL会被docker inspect命令读取Kubernetes 的kubectl describe pod也能看到。当你在生产环境排查问题时一眼就能知道这个镜像是从哪个 commit 构建的、由谁维护、构建时间是什么时候。3.3 构建与验证一次成功的docker build应该输出什么执行完所有定制后你就可以运行构建命令了。但请注意这不是一个“按下回车就完事”的过程你需要关注构建日志中的关键信号。执行构建命令# 在 ragflow/ 根目录下执行 make docker-build-api # 或者直接使用 docker build docker build -f docker/build/Dockerfile.api -t ragflow/api:v0.25.0-prod .解读构建日志的关键信号一个健康的构建过程日志中应该出现以下几行它们是成功的“黄金指标”Step 5/15 : RUN pip install --find-links /tmp/wheels --no-index pymilvus2.4.3 paddlepaddle-gpu2.6.1这行表示你成功绕过了网络使用了本地 wheel。Step 8/15 : COPY --frombuilder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages这行表示 multi-stage 构建成功只复制了必要的依赖。Step 12/15 : RUN addgroup -g 1001 -f ragflow adduser -S ragflow -u 1001这行表示非 root 用户创建成功。Step 14/15 : HEALTHCHECK --interval30s ...这行表示健康检查已正确配置。如果你在日志中看到ERROR: Could not find a version that satisfies the requirement xxx那一定是你的wheels/目录里缺少了某个包或者--find-links路径写错了。本地验证镜像三步快速确认构建完成后不要急着推送到镜像仓库先在本地做三步验证检查镜像大小docker images | grep ragflow/api。一个定制后的v0.25.0-prod镜像大小应该在1.25GB左右。如果超过1.5GB说明你可能在 Builder Stage 没有pip cache purge或者错误地 COPY 了.git目录。检查用户和权限docker run --rm -it ragflow/api:v0.25.0-prod sh -c id ls -l /app/configs/models.yaml。输出应该显示uid1001(ragflow)且models.yaml的权限是-r--r--r--。检查健康检查docker run -d --name test-api -p 8000:8000 ragflow/api:v0.25.0-prod然后docker ps查看STATUS列应该很快从starting变成healthy。如果一直是unhealthy用docker logs test-api查看错误90% 的情况是REDIS_URL环境变量没传对。4. 常见问题与实战排错那些只有亲手构建过才会懂的坑即使你严格按照上述步骤操作也难免会遇到一些“只在此山中云深不知处”的诡异问题。这些问题往往不会出现在官方文档里但却是生产环境中的高频故障。下面我把我过去半年记录的 12 个真实案例浓缩成一张速查表并附上独家的排查思路和根治方案。4.1 Redis 连接问题从“连接不上”到“连接超时”的本质区别这是 RAGFlow 用户反馈最多的问题但“连接不上”只是一个表象背后至少有四种完全不同的根因。现象根本原因排查命令根治方案Connection refusedREDIS_URL地址错误或 Redis 服务根本没起来docker exec -it redis_container ping redis检查docker-compose.yml中 Redis 服务的container_name是否为redisapi容器的networks是否与 Redis 在同一网络TimeoutError: Timeout waiting for connectionceleryconfig.py中的visibility_timeout大于 Redis 的timeout配置docker exec -it redis_container redis-cli CONFIG GET timeout将 Redis 的timeout设为0永不过期或在celeryconfig.py中将visibility_timeout改为1800Authentication requiredREDIS_URL中的密码错误或 Redis 未启用requirepassdocker exec -it redis_container redis-cli -a wrong_password INFO使用redis-cli -a correct_password INFO测试确认密码正确后更新REDIS_URLConnection closed by serverapi容器和celery容器使用了不同的 Redis 连接池导致连接被复用冲突docker logs api_container搜索redis在api/config.py和worker/celeryconfig.py中确保REDIS_URL的db参数不同例如api用db0celery用db1注意v0.25.0 的api和celery默认都连接db0这是个设计缺陷。我建议你永远为它们分配不同的 DB这是最简单、最有效的隔离方案。4.2 文档解析失败PDF、Word、Excel 的三重地狱RAGFlow 的文档解析引擎基于unstructured库它在 v0.25.0 中默认启用了pdfminer和pypdf双引擎。但现实是没有一个引擎是完美的。PDF 解析空白页这是最常见的问题根源在于 PDF 的字体嵌入方式。pdfminer对 Type3 字体支持极差。解决方案是在settings.yaml中强制指定pdf_engine: pypdf并确保pypdf版本 4.2.0v0.25.0 的requirements.txt锁定的是4.1.0你需要手动升级。Word 文档乱码unstructured在解析.docx时会调用python-docx而python-docx对中文宋体的支持有 Bug。解决方案是在Dockerfile.api的 Final Stage 中添加RUN pip install python-docx1.1.0这个版本修复了大部分乱码问题。Excel 表格解析错行unstructured的xlsx解析器会把合并单元格识别为多行。这不是 Bug而是设计。解决方案是在settings.yaml中设置table_extraction_enabled: false然后在应用层用pandas重新解析 Excel将结果以text/plain格式传给 RAGFlow。4.3 模型加载失败Xinference、Ollama 与本地模型的兼容性矩阵v0.25.0 支持三种模型后端但它们的 API 兼容性并不完美。后端支持的模型类型常见失败原因解决方案Xinferenceembedding,llm,rerankXinference 的model_uid与models.yaml中的model_name不一致在 Xinference Web UI 中点击模型右侧的Copy Model UID粘贴到models.yaml的model_uid字段OllamallmOllama 的ollama run命令拉取的模型其modelfile中的FROM指令指定了错误的 base model使用ollama show model_name查看模型详情确认base字段是否为llama3或qwen2如果不是需要重新ollama create本地 HuggingFaceembeddingtransformers版本与模型不兼容例如bge-m3需要transformers4.40.0在Dockerfile.api的 Builder Stage 中pip install transformers4.40.0并确保sentence-transformers版本与之匹配实操心得我建议在生产环境中永远不要混合使用多种后端。要么全部用 Xinference推荐因为它支持模型热加载和 GPU 显存监控要么全部用 Ollama适合快速 PoC。混合使用会极大增加调试复杂度。4.4 镜像体积爆炸从 1.2GB 到 3.5GB 的罪魁祸首一个定制镜像体积失控通常不是因为你装了太多东西而是因为你没删干净东西。罪魁祸首 1.git目录如前所述COPY . /app/会把整个仓库 COPY 进去。一个v0.25.0的.git目录大小约为180MB。解决方案在Dockerfile.api的COPY . /app/之前添加COPY --chownragflow:ragflow . /app/并在docker build时使用.dockerignore文件内容为.git .gitignore __pycache__ *.pyc罪魁祸首 2pip缓存和__pycache__即使你用了 multi-stageBuilder Stage 的pip install也会产生大量缓存。解决方案在 Builder Stage 的末尾添加RUN rm -rf /root/.cache/pip