ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Dify main 镜像国内拉取:docker compose 换源与版本锁定实践

Dify main 镜像国内拉取:docker compose 换源与版本锁定实践 简介面向国内网络环境开发的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 镜像的国内可用方案大致有三种Docker Hub 官方加速器。这类加速器通常由云厂商提供用法是在/etc/docker/daemon.json里配置registry-mirrors。优点是不改 compose 文件缺点是加速器只对 Docker Hub 官方仓库生效而且高峰期不稳定。另外很多加速器地址已经失效需要先测试连通性。把镜像推到自己的阿里云/腾讯云容器镜像服务个人版。你在能访问 Docker Hub 的机器上docker pull再docker tag然后docker push到个人仓库部署机器从个人仓库拉取。这个方案在国内最稳但需要手动同步且个人版有命名空间限制。自建 Docker Registry 缓存。适合团队内部多台机器重复拉取用registry:2配合pull-through cache模式。这个对 dify-main 的场景有点重但如果你要频繁升级 main 分支值得考虑。我一般会用第二种。因为“国内可以的镜像版本”本质上是“可获取的镜像版本”而不是“最快的加速器”。把镜像推到自己的仓库等于把版本控制权握在手里还能顺便解决 docker pull 的 rate limit 问题。3. 用国内可用的镜像版本跑通 dify-maindocker 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_IMAGEregistry.cn-shanghai.aliyuncs.com/myteam/dify-api:main DIFY_WEB_IMAGEregistry.cn-shanghai.aliyuncs.com/myteam/dify-web:main DIFY_SANDBOX_IMAGEregistry.cn-shanghai.aliyuncs.com/myteam/dify-sandbox:main DIFY_PLUGIN_DAEMON_IMAGEregistry.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 21 | grep -i versionDify 启动日志里通常会打印后端服务版本号、提交时间等信息。更直接的办法是调用 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_TAGmain-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容器状态是exiteddocker 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并更新.envDIFY_API_IMAGEregistry.internal:5000/dify-platform/dify-api:main-202502015.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_IMAGEregistry.internal:5000/dify-platform/dify-api:main-20250201 DIFY_WEB_IMAGEregistry.internal:5000/dify-platform/dify-web:main-20250201 DIFY_SANDBOX_IMAGEregistry.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 fi5.3 定期同步 dify-main 更新的最小步骤如果你希望自己的内网镜像版本一直跟随 dify-main建议写一个同步脚本在 cron 里每天跑一次。核心步骤只有三步。#!/bin/bash # sync_dify_main.sh set -euxo pipefail REGISTRYregistry.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 是投入产出比最高的方案。本文还有配套的精品资源点击获取
返回列表