☰
Dify main 镜像国内拉取:docker compose 换源与版本锁定实践
2026/10/8 14:40:51 网站建设 项目流程

简介:面向国内网络环境开发的Dify Main镜像打包版,专供需要快速部署Dify服务的开发者使用。压缩包采用zip格式,整体大小20.29MB,解压后共2000个文件:1411个Python脚本承载核心业务逻辑,370个JSON文件保存配置与数据结构,103个CSS负责前端样式,另有41个Markdown文档、25个JavaScript、23个YAML编排文件、12个Shell脚本及少量HTML、XML、SQL文件,构成一套可离线加载的完整Docker镜像资源。文件结构清晰,适合具备基础Docker操作能力的中级开发者直接导入使用。目前已有1481人学习下载,验证了其实用价值。这份资源针对国内访问国外镜像源缓慢、不稳定等痛点,已预先完成适配,导入后按需配置即可启动,省去繁琐的拉取与换源步骤,帮助开发者在受限网络下高效完成Dify环境搭建与测试。

1. 国内拉不动 dify-main 镜像?问题往往不在网络,而在镜像标签的“伪最新”

做 LLM 应用落地的人,多半都遇到过这个场景:从 GitHub 拉下 dify-main 源码,docker compose 一跑,前端半天起不来,日志里全是 “manifest unknown” 或 “timeout exceeded”。你以为是网不好,换了加速器还是卡,最后发现是 Dify 官方在 Docker Hub 上的latest标签早就不是 main 分支的最新构建了。所谓“国内可以的镜像版本 dify-main”,指的就是能明确锁定 main 分支、在国内网络环境下能稳定拉取的一套镜像方案。

这篇文章不聊怎么配代理,只讲三件事:Dify 镜像到底由哪几个组件组成、怎么把镜像源换成国内可用的地址并锁定 main 版本、以及换源后最容易踩的四个坑。适合正在做 Dify 私有化部署、或者想跟进 main 分支新特性的开发者。你不需要懂 Kubernetes,只要会 docker compose 就能照着走完。

2. dify-main 镜像拆解:不能只换一个镜像,要把组件链路理清

2.1 Dify 部署时拉取的镜像清单与依赖关系

Dify 的 docker-compose 编排里,核心镜像并不是一个“全家桶”,而是多个独立服务。常见做法是官方仓库里的docker-compose.yaml会引用这些镜像:

  • langgenius/dify-api:后端 API 服务,承载所有业务逻辑、模型接入、数据集管理。
  • langgenius/dify-web:前端静态资源服务,负责 Web 界面。
  • langgenius/dify-sandbox:代码执行沙箱,用于运行工作流里的 Python/Node.js 代码片段。
  • nginx:反向代理,把前端和后端路由起来(有些版本直接用langgenius/dify-nginx)。
  • 依赖基础设施:postgres、redis、weaviate或qdrant、ssrf_proxy、plugin_daemon等。

如果你只把dify-api和dify-web换成国内镜像,其他镜像仍然从 Docker Hub 拉取,部署速度不会有质的提升。更关键的是,plugin_daemon和sandbox这两个镜像经常被忽略,而它们恰好是 main 分支迭代最频繁的部分。所谓“镜像版本 dify-main”,必须做到整个 compose 文件里所有image:字段都指向同一套镜像仓库,并且 API、Web、Sandbox 之间版本一致。

2.2 国内镜像源选型:加速器、个人仓库、还有自建缓存

拉取 Docker 镜像的国内可用方案大致有三种:

  1. Docker Hub 官方加速器。这类加速器通常由云厂商提供,用法是在/etc/docker/daemon.json里配置registry-mirrors。优点是不改 compose 文件,缺点是加速器只对 Docker Hub 官方仓库生效,而且高峰期不稳定。另外很多加速器地址已经失效,需要先测试连通性。

  2. 把镜像推到自己的阿里云/腾讯云容器镜像服务个人版。你在能访问 Docker Hub 的机器上docker pull再docker tag然后docker push到个人仓库,部署机器从个人仓库拉取。这个方案在国内最稳,但需要手动同步,且个人版有命名空间限制。

  3. 自建 Docker Registry 缓存。适合团队内部多台机器重复拉取,用registry:2配合pull-through cache模式。这个对 dify-main 的场景有点重,但如果你要频繁升级 main 分支,值得考虑。

我一般会用第二种。因为“国内可以的镜像版本”本质上是“可获取的镜像版本”,而不是“最快的加速器”。把镜像推到自己的仓库,等于把版本控制权握在手里,还能顺便解决 docker pull 的 rate limit 问题。

3. 用国内可用的镜像版本跑通 dify-main:docker compose 改源实操

3.1 获取 dify-main 源码并定位镜像配置

先从 GitHub 拉取 Dify 仓库的 main 分支。注意不要用master或者 Release 包,因为很多 Release 包里的docker-compose.yaml引用的镜像标签是latest,而不是精确的 main 构建。

git clone https://github.com/langgenius/dify.git cd dify git checkout main git pull origin main

拉下来之后,先看docker-compose.yaml里所有image:字段,再打开.env文件。Dify 的 compose 文件里大量使用了环境变量替换,比如${DIFY_IMAGE:-langgenius/dify-api:latest},所以改镜像地址不一定非要去改 YAML,改.env里的变量就行。

这里有一个关键点:main 分支的docker-compose.yaml里,API 和 Web 的镜像默认是:latest,而latest并不代表 main 分支最新代码。Dify 官方是把main的每次构建都推送到:main标签上的。所以在.env里要明确设置成langgenius/dify-api:main,不要依赖默认值。

3.2 修改 .env 与 docker-compose.yaml 指定镜像版本和 registry

假设你已经把镜像推到了自己的镜像仓库,比如registry.cn-shanghai.aliyuncs.com/myteam/dify-api,并且 tag 保留了main。那么.env里可以这样写:

# .env 关键片段 DIFY_IMAGE=registry.cn-shanghai.aliyuncs.com/myteam/dify-api:main DIFY_WEB_IMAGE=registry.cn-shanghai.aliyuncs.com/myteam/dify-web:main DIFY_SANDBOX_IMAGE=registry.cn-shanghai.aliyuncs.com/myteam/dify-sandbox:main DIFY_PLUGIN_DAEMON_IMAGE=registry.cn-shanghai.aliyuncs.com/myteam/plugin_daemon:main

如果你不想用个人仓库,也可以直接指向某个加速器能拉到的地址,但加速器通常只对docker.io生效,对registry.cn-shanghai...这种地址无效。最省事的做法是:在.env里只保留镜像名,把registry-mirrors配置好,但这样你依然依赖 Docker Hub 的可用性。

改完.env,还需要检查docker-compose.yaml里是否有硬编码的镜像名。有些版本的ssrf_proxy或nginx服务直接写了 `` 这样的全路径,这时需要手动替换:

sed -i 's|langgenius/dify-api:latest|registry.cn-shanghai.aliyuncs.com/myteam/dify-api:main|g' docker-compose.yaml

执行完sed之后,建议grep -n "image:" docker-compose.yaml检查一遍,确保没有漏网的:latest。

3.3 启动与验证:如何确认跑的是 main 分支代码

镜像改好之后,执行:

docker compose up -d

第一次启动会拉取所有镜像,如果网络不稳定,可能会失败。可以分步拉取:

docker compose pull docker compose up -d

验证当前跑的是不是 main 分支代码,不要只看容器状态,要进容器里看版本。

docker exec -it docker-api-1 python -c "from dify import __version__; print(__version__)"

如果这个命令报错,说明 API 容器里的工作目录不是直接暴露 Python 包的,你可以换一种方式:

docker logs docker-api-1 2>&1 | grep -i "version"

Dify 启动日志里通常会打印后端服务版本号、提交时间等信息。更直接的办法是调用 API 的健康检查接口:

curl http://localhost:5001/health

返回{"status":"ok"}只能说明服务活着,不能说明是 main。要确认代码分支,可以在启动时挂一个临时命令:

docker run --rm -it --entrypoint bash registry.cn-shanghai.aliyuncs.com/myteam/dify-api:main -c "cat /app/README.md | head -5"

但这个只能证明镜像本身是 main,不能证明运行中的容器。实践中,我一般会通过 Web 界面的“关于”页看版本号,或者调用/console/api/setup接口看返回的版本字段。总之,不要认为镜像 tag 是main就万事大吉,拉取下来的镜像也可能被覆盖过,最好在启动后做一次版本核对。

4. 镜像版本不一致的四大避坑记录:现象、原因与解决

4.1 现象一:前端页面能打开,但所有 API 请求返回 401 或 404

现象:dify-web正常启动,浏览器能打开登录页,但登录时提示“请求失败”,打开控制台发现/console/api/login返回 404 或 401。

原因:这是最经典的版本不一致问题。dify-web镜像和dify-api镜像不是同一个main构建。前端代码里包含的路由规则、API 路径参数和后端不匹配,比如前端要求/console/api/setup带telemetry字段,而后端还没更新这个字段,或者反过来。

解决:把.env里所有*_IMAGE统一到同一天构建的 tag。如果你用的是:main标签,Docker Hub 上的main是滚动更新的,可能在你pull的过程中前后端镜像分别拉到了不同时间点的构建。要彻底避免,就用带 commit hash 的 tag,比如main-20250101-abc1234567,或者把镜像拉到本地后docker tag成固定版本,再推送自己的仓库。日常开发中,我在.env里会写一个DIFY_TAG=main-<date>变量,统一控制所有组件。

4.2 现象二:docker pull 卡在 “TLS handshake timeout” 或 “dial tcp: i/o timeout”

现象:执行docker compose pull时,某个镜像一直重试,日志显示 TLS 握手超时,或连接被重置。

原因:你仍然在从 Docker Hub 直接拉取,或者你的加速器地址已经失效。Docker 的registry-mirrors配置只对 Docker Hub 的镜像生效,如果你把镜像换成了阿里云个人仓库地址,就不应该走加速器。还有一种原因是镜像仓库所在区域网络策略变化。

解决:先清掉registry-mirrors配置,直接拉取你自己的仓库地址。如果必须用 Docker Hub,建议先在能在国外网络环境执行的机器上docker pull,再docker save成 tar 包,传到目标机器docker load。这是最笨但最稳的办法。对于团队场景,我倾向于搭建一个registry:2镜像缓存,配置如下:

# registry-cache.yml services: registry: image: registry:2 ports: - "5000:5000" environment: REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR: inmemory volumes: - ./registry-data:/var/lib/registry

然后在每台机器的 Docker daemon 里配置registry-mirrors指向本机 5000 端口。这样团队内拉取 Dify 镜像时,只有第一次会穿透到 Docker Hub,后续都是内网速度。

4.3 现象三:dify-sandbox 容器启动后立刻退出,日志报 seccomp 权限错误

现象:sandbox容器状态是exited,docker logs看到类似operation not permitted或seccomp相关的错误。

原因:Dify 的沙箱依赖 Docker 的--privileged或特定cap_add配置。在docker-compose.yaml里,sandbox服务通常有cap_add: [SYS_PTRACE]或者security_opt: [seccomp:unconfined]。如果你用的是自己改过的镜像,可能基础镜像里缺少必要的动态链接库,导致沙箱初始化失败。

解决:不用换镜像,先检查docker-compose.yaml里的 sandbox 配置,确保和官方一致。如果你是从旧版本升级到 dify-main,注意sandbox的启动命令可能新增了--enable-session-clean之类的参数。另一点是,你的宿主机内核版本太旧,沙箱要求 Linux 内核 >= 5.15。可以使用uname -r检查。如果不想升级内核,就把 sandbox 服务先停掉,用dify-sandbox的替代方案——临时禁用 sandbox 相关功能,但这样工作流里的代码节点就用不了。

4.4 现象四:升级到 dify-main 后,数据库迁移报错或数据丢失

现象:用旧版本的数据卷直接启动新的dify-api:main,启动时日志出现alembic migration error,或者数据库中某些表缺少字段。

原因:Dify 的 main 分支经常修改数据库 schema,而镜像构建时可能没有把所有迁移脚本都打包进去,或者你跳过了中间版本直接升级。数据库迁移是黑匣子,一旦失败,最坏情况就是回滚旧镜像。

解决:升级前先备份 postgres 数据卷。用docker compose exec db pg_dump备份,不要直接复制数据文件。然后,不要跨多个版本跳跃升级。如果你当前是 0.6.x,想升到 main,建议先升到最近的 release 版本,再切到:main标签。如果迁移已经失败,把 API 容器停掉,换回旧镜像,再手动执行 alembic 修复。

5. 让 dify-main 镜像版本可维护:自定义镜像名与内网分发

5.1 给镜像重新打 tag 并推送到自建 registry

日常迭代中,我不会直接修改docker-compose.yaml里的官方镜像名,而是把拉下来的镜像重新打 tag,推送到内网仓库。这样既保留官方原始信息,又能统一版本。

# 在能访问 Docker Hub 的机器上执行 docker pull langgenius/dify-api:main docker tag langgenius/dify-api:main registry.internal:5000/dify-platform/dify-api:main-20250201 docker push registry.internal:5000/dify-platform/dify-api:main-20250201

这里用registry.internal:5000示意内网 registry 地址。tag 里带上日期,就是为了防止main滚动更新后你无法回溯。推完之后,在部署机器上拉取这个固定 tag,并更新.env:

DIFY_API_IMAGE=registry.internal:5000/dify-platform/dify-api:main-20250201

5.2 用 docker compose 的 .env 统一管理镜像版本

Dify 的docker-compose.yaml里,不同服务对镜像变量的引用方式不完全一致。常见做法是定义全局变量,但有些服务直接写死了镜像名。更好的方案是把 compose 文件拆成多个 override 文件。

# docker-compose.override.yml services: api: image: ${DIFY_API_IMAGE} web: image: ${DIFY_WEB_IMAGE} sandbox: image: ${DIFY_SANDBOX_IMAGE}

然后在.env里统一指定:

DIFY_API_IMAGE=registry.internal:5000/dify-platform/dify-api:main-20250201 DIFY_WEB_IMAGE=registry.internal:5000/dify-platform/dify-web:main-20250201 DIFY_SANDBOX_IMAGE=registry.internal:5000/dify-platform/dify-sandbox:main-20250201

这样每次升级,只需改变.env里的 tag 值。docker compose up -d会重新拉取新 tag 并重建容器。注意,如果.env里没有定义对应变量,compose 会回退到默认的镜像名,这容易造成“改了 override 但没生效”的错觉。所以我会在部署脚本里加一层校验:

if [ -z "$DIFY_API_IMAGE" ]; then echo "DIFY_API_IMAGE is not set, abort" exit 1 fi

5.3 定期同步 dify-main 更新的最小步骤

如果你希望自己的内网镜像版本一直跟随 dify-main,建议写一个同步脚本,在 cron 里每天跑一次。核心步骤只有三步。

#!/bin/bash # sync_dify_main.sh set -euxo pipefail REGISTRY=registry.internal:5000/dify-platform DATE_TAG=$(date +%Y%m%d) # 1. 从 Docker Hub 拉取 main 镜像 docker pull langgenius/dify-api:main docker pull langgenius/dify-web:main docker pull langgenius/dify-sandbox:main # 2. 重新打 tag 并推送 docker tag langgenius/dify-api:main $REGISTRY/dify-api:main-$DATE_TAG docker push $REGISTRY/dify-api:main-$DATE_TAG docker tag langgenius/dify-web:main $REGISTRY/dify-web:main-$DATE_TAG docker push $REGISTRY/dify-web:main-$DATE_TAG docker tag langgenius/dify-sandbox:main $REGISTRY/dify-sandbox:main-$DATE_TAG docker push $REGISTRY/dify-sandbox:main-$DATE_TAG # 3. 更新 .env 中的 tag sed -i "s/main-[0-9]*/main-$DATE_TAG/" .env

这个脚本看起来简单,实际上有两个坑:第一个是 Docker Hub 的 rate limit,无认证的匿名 pull 每小时只有百来次,如果团队里有人同时跑别的镜像,可能会限制。解决办法是在脚本里先docker login。第二个坑是只同步了 API、Web、Sandbox,漏了plugin_daemon。Dify main 分支已经拆分了插件系统,plugin_daemon镜像更新频率更高,需要一并拉取。我建议在脚本里把插件和 Nginx 镜像也加上,避免以后启动时拉不到对应版本。

6. 镜像版本是否可用:三个硬指标验证法

镜像换源只是第一步,真正可用的 dify-main 镜像要过三关。第一关是版本一致性。启动后,不要只看docker ps的Up状态,要检查dify-api和dify-web里记录的 commit 时间是否一致。进入 Web 容器:

docker exec docker-web-1 cat /usr/share/nginx/html/version.txt

如果文件不存在,就打开页面看页面底部的版本号。再看 API 容器的启动时间,两者应该在同一天内。如果 Web 是昨天构建的、API 是上个月的,即使 tag 都叫main,也会出现功能不一致。

第二关是核心链路功能测试。Dify 最依赖外部模型 API,但有少数能力不依赖外部模型也能测试。启动后进入工作区,创建一个空白应用,尝试添加一个“LLM 节点”但不填模型供应商,系统应该会提示设置模型,而不是报前端 500。然后,在“数据集”页面创建一个空数据集,上传一个小的 CSV 文件,看能不能正常索引。如果这两步都通,说明 API 和数据库、对象存储之间的接口是通的。接着再测试沙箱:在工作流里加一个“代码执行”节点,写一行print("hello"),运行后看沙箱是否返回结果。这一步能直接暴露 sandbox 镜像和 API 的版本匹配问题。

第三关是升级回滚路径。验证一个镜像版本是否可用,还要看它能不能干净地回滚到你当前使用的版本。我把当前生产环境的镜像 tag 写死在.env里,升级前把旧的 tag 记下来,升级失败时可以快速改回去。这里的后悔药就是前面说的固定 tag 方案。不要信任:latest,它只会让你在出问题时连回滚都不知道回滚到哪个版本。

最后讲一个我自己的教训:有段时间我为了省事,把所有镜像都改成:main,以为这样每天都是最新。结果某次 main 分支的 API 改动需要新的数据库迁移脚本,而我拉取镜像时刚好赶上官方构建的半个空窗期,导致容器起不来。后来我改成固定日期 tag,每次升级前先在测试环境跑一遍迁移脚本,再上生产。现在我的做法是:每个月初同步一次 main,并在当月用日期 tag 固定。这样既不会落后太多,又能保证版本可追溯。

希望这些方法能帮你少踩几个坑。如果你正在折腾 dify-main 的镜像版本,建议先理清自己的部署环境,再决定用加速器、个人仓库还是自建 registry。对大多数团队来说,固定日期 tag 加内网 registry 是投入产出比最高的方案。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询