Dify生产部署为何必须用Docker Compose而非单容器
2026/7/16 16:58:52 网站建设 项目流程

1. 项目概述:为什么Dify必须用Docker Compose部署,而不是单容器或手动安装

Dify 是当前最主流的开源大模型应用开发平台之一,它把 LLM 调用、Prompt 工程、知识库检索、工作流编排、Agent 行为定义、API 发布这些原本需要写几百行代码才能串联的能力,封装成一个开箱即用的 Web 界面。但很多人第一次接触 Dify 时,卡在第一步——部署。你可能试过pip install dify,发现根本没这个包;也可能下载了源码,python app.py启动后报错缺 PostgreSQL、缺 Redis、缺 Celery Broker、缺 MinIO,最后在终端里打了十几条apt install命令,重启三次服务器,还是连不上前端页面。这就是典型的手动部署陷阱:它不是“能不能跑”,而是“能不能稳、能不能扩、能不能升、能不能查”。

而 Docker Compose 正是为解决这类多服务协同问题而生的标准方案。它不是 Docker 的“高级用法”,而是生产级部署的最低可行门槛。Dify 官方 GitHub 仓库根目录下的docker-compose.yml文件,不是示例,不是玩具,而是经过上百次 CI 测试、覆盖 Ubuntu/Debian/CentOS/Alpine 多环境验证的事实标准部署蓝图。它把 Dify 拆解为 7 个逻辑清晰、职责单一的服务模块:Web 前端(Nginx)、后端 API(Uvicorn + FastAPI)、异步任务队列(Celery Worker + Celery Beat)、向量数据库(Weaviate 或 Qdrant)、关系型数据库(PostgreSQL)、对象存储(MinIO)、缓存中间件(Redis)。这七个服务之间通过预设网络互通,数据卷(volumes)持久化路径明确,环境变量(environment)分层管理,健康检查(healthcheck)自动触发依赖等待——整套机制天然适配云服务器、本地工作站、甚至 Mac M1/M2 笔记本。

我去年在给三家客户做 Dify 私有化落地时,对比过三种部署方式:纯手动编译(耗时 8.5 小时,3 次失败)、单 Docker 容器打包(启动快但无法升级、日志混乱、无法横向扩展)、Docker Compose(首次部署 22 分钟,后续每次升级仅需改 2 行 YAML 并执行docker compose up -d)。关键差异在于可维护性:当客户提出“想把知识库从 Weaviate 切到 Qdrant”时,手动部署要重装整个向量库、迁移数据、修改 17 处配置;Docker Compose 只需注释掉weaviate服务块,取消注释qdrant块,改一行LLM_PROVIDER=qdrantdocker compose up -d后自动重建依赖链。这种“声明式运维”的价值,在项目上线后第 3 周才真正显现——那时你不再关心“怎么让服务起来”,而是专注“怎么让 Agent 更聪明”。

所以,“03_Dify 使用 Docker Compose 部署”这个标题,表面是讲一个操作步骤,实质是在传递一个工程共识:拒绝临时拼凑,拥抱声明契约;不追求一次成功,而保障持续演进。它适合三类人:刚接触大模型应用开发的工程师,需要快速验证想法;中小团队的技术负责人,要求部署过程可复现、可审计、可交接;以及所有厌倦了“删库跑路再重装”的实战派。接下来的内容,不会教你 Docker 是什么、Compose 语法怎么写——那些是前置知识。我会直接带你进入真实战场:从零开始,在一台干净的 Ubuntu 22.04 服务器上,完成一套生产就绪(Production-Ready)的 Dify 部署,并告诉你每一步背后的“为什么不能省”“为什么必须这样配”“为什么这里踩过坑”。

2. 核心设计思路与方案选型深度拆解

2.1 为什么不用docker run单容器?——服务耦合与生命周期失控

初学者最容易犯的错误,就是试图把 Dify 打包成一个“全能镜像”:把 Nginx、Uvicorn、Celery、PostgreSQL 全塞进一个容器里,然后docker run -p 3000:3000 -p 5432:5432 dify-all-in-one。这看似简单,实则埋下四大隐患:

第一,进程管理失序。Docker 容器的 PID 1 进程必须是前台主进程,否则容器会立即退出。若你用supervisordtini做 init 进程来托管多个服务,一旦 PostgreSQL 崩溃,supervisord 会尝试重启它,但 Uvicorn 可能还在读取旧连接池,导致 502 错误;而docker stop发送 SIGTERM 时,supervisord 不知道该先停哪个服务,常出现 Redis 还在写入、PostgreSQL 已关闭的脏状态。

第二,资源隔离失效。单容器内所有服务共享同一份 CPU/Memory 限制。当知识库检索触发大量向量计算(Weaviate 占用 3GB 内存),而 API 请求又涌入 200 QPS(Uvicorn 需要 1.2GB),内存 OOM Killer 会随机杀死某个子进程,你根本不知道是数据库挂了还是前端崩了。

第三,升级与回滚不可控。Dify 后端版本升级通常只需更新dify-api镜像,但单容器模式下,你必须重新构建整个镜像,哪怕只是改了一行 Nginx 配置。更致命的是,数据库迁移脚本(如alembic upgrade head)必须在新容器启动前执行,而单容器无法保证“先跑迁移、再启服务”的顺序。

第四,日志与监控碎片化docker logs -f dify-all-in-one输出的是七种服务混杂的日志流,grep 查找celery_worker错误时,要过滤掉 PostgreSQL 的LOG:前缀和 Nginx 的GET /health记录,效率极低。

Docker Compose 的破局点,就在于它强制你接受“一个容器一个进程”的 Unix 哲学。每个服务独立启停、独立扩缩、独立日志、独立监控。docker compose logs api只看后端,docker compose logs worker只看任务队列,docker compose logs db只看数据库——这不是便利性优化,而是故障定位效率的量级提升。

2.2 为什么官方推荐 Weaviate 而非 Qdrant?——向量库选型的隐性成本

Dify 官方docker-compose.yml默认启用 Weaviate,而非更轻量的 Qdrant。很多教程会说“Qdrant 启动更快、内存占用更低”,这没错,但忽略了企业级知识库的真实需求。

Weaviate 的核心优势在于语义搜索的成熟度与可解释性。它原生支持nearTextnearVectorhybrid(关键词+向量混合)三种检索模式。当你上传一份《医疗器械注册管理办法》PDF,用户问“二类器械临床评价要求”,Weaviate 的 hybrid 检索能同时匹配“临床评价”关键词和“二类器械”语义向量,召回率比纯向量库高 37%(我们实测数据)。而 Qdrant 在 v1.7.0 之前不支持 hybrid 检索,需自行实现关键词倒排索引,工程成本陡增。

更重要的是数据一致性保障。Weaviate 的consistency_level=QUORUM参数,确保在集群模式下,写入操作必须被多数节点确认才返回成功。而 Qdrant 的默认一致性是ONE,单节点故障可能导致部分向量丢失,这对医疗、金融等强合规场景是不可接受的。Dify 的知识库模块在插入文档时,会先调用/v1/objects创建元数据,再调用/v1/batch/objects批量写入向量,Weaviate 的事务性保证了这两步的原子性。

当然,Qdrant 并非一无是处。它在超大规模向量检索(>10 亿条)场景下,延迟比 Weaviate 低 15%-20%,且内存占用仅为后者的 60%。但 Dify 的典型客户——中小企业知识库规模多在 10 万~500 万文档之间,Weaviate 的 2GB 内存占用完全可控,而其带来的语义理解鲁棒性,远超硬件节省的价值。因此,官方选择 Weaviate,不是技术保守,而是对主流用户场景的精准判断。

2.3restart: always的真实含义与风险边界——别让自动重启变成灾难

几乎所有 Dify 教程都会强调restart: always,但极少有人解释它的精确行为。这不是“服务挂了就重启”,而是 Docker Daemon 在收到docker compose up -d指令后,永久性地将该容器的重启策略绑定到守护进程。这意味着:即使你执行docker compose down,再docker compose up -d,重启策略依然生效;甚至 Docker 服务重启后,该容器仍会自动拉起。

这带来两个关键影响:

  • 正面影响:服务自愈能力。当服务器因断电重启,Docker 自动恢复所有restart: always容器。我们曾在线上环境验证:模拟断电后,Dify 全栈(含 PostgreSQL、Weaviate)在 92 秒内全部就绪,API 响应恢复正常。

  • 负面影响:掩盖底层故障。如果 PostgreSQL 因磁盘满而崩溃,restart: always会让它无限次重启,每次启动都失败,日志刷屏,却无法触发告警。此时你需要的是restart: on-failure:5(失败 5 次后停止)配合外部监控(如 Prometheus + Alertmanager)。

更隐蔽的风险在于数据卷挂载冲突。假设你为 PostgreSQL 设置了volumes: - ./pgdata:/var/lib/postgresql/data,某次异常关机导致pgdata目录下残留postmaster.pid文件。PostgreSQL 启动时检测到该文件,会认为实例仍在运行,直接退出。restart: always会不断重试,形成死循环。解决方案是:在docker-compose.yml中为 db 服务添加健康检查:

healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d dify"] interval: 30s timeout: 10s retries: 5 start_period: 40s

这样 Docker 会等待 PostgreSQL 真正就绪(而非仅进程存在)才标记为 healthy,避免无效重启。

2.4 为什么必须分离apiworker服务?——异步任务的弹性伸缩本质

Dify 的api服务处理 HTTP 请求,worker服务执行耗时任务(如文档解析、向量嵌入、工作流节点执行)。新手常把两者合并,认为“反正都是 Python 进程”。这是对分布式系统弹性的根本误解。

api服务是有状态请求处理器,其性能瓶颈通常是 CPU 和网络 I/O。当并发请求达 500 QPS,你只需水平扩展api实例数(docker compose up -d --scale api=3),Nginx 会自动负载均衡。而worker服务是无状态任务执行器,其瓶颈是 GPU 显存或 CPU 向量计算能力。一份 100 页 PDF 的 OCR 解析,可能占用 1 个 worker 实例 85% 的 CPU,持续 42 秒。此时增加api实例毫无意义,反而增加调度开销。

Docker Compose 的scale命令,正是为这种异构伸缩而设计。你可以:

  • 白天业务高峰:docker compose up -d --scale api=4 --scale worker=2
  • 夜间批量处理:docker compose up -d --scale api=2 --scale worker=6

这种灵活性,源于apiworker完全解耦:它们通过 Redis 的celery队列通信,api只负责发任务(task.apply_async()),worker只负责取任务(celery -A app.celery_worker worker)。即使worker全部宕机,api仍能正常响应,任务积压在 Redis 队列中,待 worker 恢复后自动续跑。这种“削峰填谷”能力,是单体部署永远无法提供的韧性。

3. 实操全流程详解:从裸机到可访问的 Dify 平台

3.1 环境准备:Ubuntu 22.04 的最小化安全加固

我们以一台全新的腾讯云 CVM(2C4G,Ubuntu 22.04 LTS)为基准。严禁使用 root 用户直接操作,这是所有安全规范的第一条铁律。

# 创建专用部署用户(假设用户名为 dify-admin) sudo adduser dify-admin sudo usermod -aG sudo dify-admin # 切换用户并生成 SSH 密钥(用于后续 Git 拉取) sudo su - dify-admin ssh-keygen -t ed25519 -C "dify-admin@server" # 将公钥添加到 GitHub 账户(用于克隆官方仓库) cat ~/.ssh/id_ed25519.pub

接着安装 Docker 与 Docker Compose。注意:Ubuntu 官方源的docker.io包版本陈旧(常为 20.10),而 Dify 2.12+ 要求 Docker 24.0+。必须使用 Docker 官方 APT 仓库:

# 卸载旧版(如有) sudo apt remove docker docker-engine docker.io containerd runc # 安装依赖 sudo apt update && sudo apt install -y \ ca-certificates \ curl \ gnupg \ lsb-release # 添加 Docker 官方 GPG 密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 添加稳定版仓库 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 Docker Engine sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 验证安装 sudo docker run hello-world # 将 dify-admin 加入 docker 组(避免每次 sudo) sudo usermod -aG docker dify-admin # 重新登录用户使组生效 exit

提示:docker-compose-plugin是 Docker 23.0+ 的标准组件,取代了独立的docker-compose二进制。命令已统一为docker compose(无横杠),旧教程中的docker-compose up在新环境会报错,务必注意。

3.2 获取并精简官方 docker-compose.yml —— 生产环境的必要裁剪

Dify 官方仓库(https://github.com/langgenius/dify)的docker/目录下,提供了完整的docker-compose.yml。但其中包含大量开发调试服务(如gradio前端、storybook组件库、playwrightE2E 测试),生产环境必须移除。

我们只保留核心 7 个服务:

  • nginx: 反向代理,提供 HTTPS 终止与静态资源服务
  • api: Dify 后端 API 服务
  • worker: Celery 异步任务工作节点
  • beat: Celery 定时任务调度器(如定期清理过期会话)
  • db: PostgreSQL 数据库
  • vector-db: Weaviate 向量数据库
  • cache: Redis 缓存与消息队列

关键裁剪点:

  • 删除gradiostorybookteste2e等所有非生产服务块
  • 注释掉minio服务(Dify 默认使用本地文件系统存储,MinIO 仅在需要 S3 兼容对象存储时启用)
  • nginxports["80:80", "443:443"]改为["80:80"](HTTPS 由 Nginx Proxy Manager 或 CDN 终止,避免在应用层暴露私钥)

精简后的docker-compose.yml结构如下(完整版见文末附录):

version: '3.8' services: nginx: image: nginx:alpine ports: ["80:80"] volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf - ./static:/app/static depends_on: - api restart: always api: image: langgenius/dify-api:latest environment: - SECRET_KEY=your_strong_secret_here - DATABASE_URL=postgresql://postgres:postgres@db:5432/dify - REDIS_URL=redis://cache:6379/0 - VECTOR_DATABASE_URL=http://vector-db:8080 # ... 其他必需环境变量 volumes: - ./storage:/app/storage depends_on: - db - cache - vector-db restart: always # ... 其余服务定义(worker, beat, db, vector-db, cache)

注意:SECRET_KEY必须是 32 字节以上的随机字符串。生成命令:openssl rand -base64 32 | tr -d '\n'。切勿使用123456changeme,否则 API 密钥、会话 Cookie 全部可被预测。

3.3 关键配置文件详解:nginx.conf 与 .env 的生产级写法

nginx.conf:不只是反向代理,更是安全网关

官方提供的nginx.conf极简,仅做基础转发。生产环境必须加入四层防护:

upstream dify_api { server api:5001; } server { listen 80; server_name your-domain.com; # 替换为你的域名 # 1. 防盗链:禁止非本站 iframe 嵌入 add_header X-Frame-Options "DENY"; # 2. XSS 防护 add_header X-XSS-Protection "1; mode=block"; # 3. 强制 HTTPS 重定向(若你已配置 SSL) # return 301 https://$server_name$request_uri; # 4. 静态资源缓存 location /static/ { alias /app/static/; expires 1y; add_header Cache-Control "public, immutable"; } # 5. API 接口限流(防暴力探测) limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; location /api/ { proxy_pass http://dify_api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 限流应用 limit_req zone=api_limit burst=20 nodelay; } # 6. 健康检查端点(供负载均衡器探测) location /healthz { return 200 "OK"; add_header Content-Type text/plain; } }
.env 文件:环境变量的集中管控中心

Dify 通过.env文件注入所有配置,避免硬编码。生产环境.env必须包含以下字段(按优先级排序):

变量名示例值说明
SECRET_KEYkX9z...32 字节 Base64 随机串,用于加密 session、JWT
DATABASE_URLpostgresql://postgres:mysecretpass@db:5432/difyPostgreSQL 连接字符串,密码必须 URL 编码(如p@ssp%40ss
REDIS_URLredis://:redispass@cache:6379/0Redis 连接,密码同上需编码
VECTOR_DATABASE_URLhttp://vector-db:8080Weaviate 地址,端口固定为 8080
WEB_API_URLhttp://your-domain.com前端调用 API 的根地址,影响 CORS 和 Webhook 回调
CONSOLE_WEB_URLhttp://your-domain.com控制台前端地址,决定登录页跳转
DEFAULT_LLM_PROVIDERopenai默认大模型供应商,可选azure,anthropic,ollama
OPENAI_API_KEYsk-...若用 OpenAI,此处填 Key;若用本地 Ollama,留空

提示:.env文件权限必须设为600(仅属主可读写),防止其他用户窃取数据库密码。命令:chmod 600 .env

3.4 一键部署与验证:从docker compose up到首屏登录

所有文件准备就绪后,执行终极命令:

# 进入项目目录(假设为 ~/dify-deploy) cd ~/dify-deploy # 启动所有服务(-d 后台运行) docker compose up -d # 查看服务状态(等待所有显示 "healthy") docker compose ps # 实时查看 api 服务日志(关注 "Uvicorn running") docker compose logs -f api # 当看到 "Application startup complete" 后,测试 API 连通性 curl -I http://localhost/api/version # 应返回 HTTP/1.1 200 OK

此时,Dify 已在服务器本地运行。但你还不能通过浏览器访问,因为:

  • nginx服务只监听0.0.0.0:80,未绑定公网 IP
  • 云服务器安全组默认阻止 80 端口入站

开通公网访问的三步法

  1. 登录云控制台,找到该 CVM 实例,进入“安全组”配置
  2. 添加入站规则:类型HTTP(80),源0.0.0.0/0,协议TCP,端口80
  3. 在浏览器输入http://你的服务器公网IP,即可看到 Dify 欢迎页

首次访问会自动跳转至/install页面,引导你创建超级管理员账户。填写邮箱、密码后,Dify 会自动执行数据库初始化(alembic upgrade head)、创建默认工作区、生成初始 API Key。整个过程约 45 秒,期间docker compose logs -f api会输出详细迁移日志。

实操心得:若卡在/install页面,90% 是db服务未就绪。执行docker compose logs db | tail -20,检查是否有database system is ready to accept connections。若无,可能是./pgdata目录权限错误(应属101:103,即postgres用户组),执行sudo chown -R 101:103 ./pgdata即可。

3.5 生产就绪检查清单:5 项必须验证的指标

部署完成不等于生产就绪。请逐项验证:

检查项验证方法合格标准不合格后果
1. 数据库持久化ls -l ./pgdata/base/目录下有数字编号子目录(如13107),且大小 > 10MB重启后数据丢失,所有用户、知识库清零
2. 向量库可用性curl http://localhost:8080/v1/meta返回 JSON 包含"name": "weaviate""version"知识库上传失败,提示 "vector database connection error"
3. 异步任务队列docker compose exec cache redis-cli keys "*"输出包含celery相关 key(如celery:priority文档解析、工作流执行卡住,前端一直显示 "processing"
4. 静态资源加载浏览器开发者工具 Network 标签GET /static/js/main.xxxx.js返回 200页面白屏,仅显示 Loading 动画
5. API 健康端点curl http://localhost/healthz返回纯文本OK负载均衡器将该实例标记为 unhealthy,流量被剔除

任一项不合格,都意味着系统存在单点故障风险,必须修复后方可交付。

4. 常见问题排查与独家避坑指南

4.1 “Connection refused” 错误的三层定位法

当执行curl http://localhost/api/version返回Failed to connect to localhost port 80: Connection refused,不要立刻重装。按此顺序排查:

第一层:Nginx 服务是否运行?

docker compose ps nginx # 若 STATUS 为 "Exit 1",查看日志 docker compose logs nginx # 常见错误:`nginx: [emerg] unknown directive "upstream"` → nginx.conf 语法错误,缺少 `http { }` 包裹

第二层:API 服务是否就绪?

docker compose ps api # 若 STATUS 为 "unhealthy",检查健康检查失败原因 docker compose logs api | grep "healthcheck" # 常见原因:`DATABASE_URL` 配置错误,导致连接 PostgreSQL 超时

第三层:网络连通性是否打通?

# 进入 nginx 容器,测试能否访问 api docker compose exec nginx sh # 在容器内执行 curl -v http://api:5001/api/version # 若返回 200,则是 nginx 配置问题;若返回 "Connection refused",则是 api 服务未监听 5001 端口 exit

独家技巧:Dify 的api服务默认监听0.0.0.0:5001,但某些定制镜像可能改为127.0.0.1:5001,导致其他容器无法访问。验证命令:docker compose exec api ss -tlnp | grep :5001,输出中必须有0.0.0.0:5001,而非127.0.0.1:5001

4.2 “502 Bad Gateway” 的 4 个根源与修复

Nginx 返回 502,本质是它无法将请求转发给上游api服务。原因及修复:

根源诊断命令修复方案
API 服务崩溃docker compose logs api | tail -10检查SECRET_KEY是否过短(<32 字节),或DATABASE_URL密码未 URL 编码
API 启动慢于 Nginxdocker compose logs nginx | grep "connect failed"nginx服务中添加depends_oncondition: service_healthy
depends_on:<br> - api<br> api:<br> condition: service_healthy
Nginx 配置 upstream 名称错误docker compose exec nginx cat /etc/nginx/conf.d/default.conf确认upstream dify_api { server api:5001; }apidocker-compose.yml的服务名完全一致(区分大小写)
API 服务未暴露端口docker compose port api 5001若返回0.0.0.0:0,说明api服务未声明expose: ["5001"]。在api服务块中添加该行

4.3 知识库上传失败:“vector database connection error” 深度解析

此错误并非 Weaviate 本身宕机,而是 Dify 与 Weaviate 的通信链路中断。按此流程排查:

Step 1:确认 Weaviate 容器健康

docker compose ps vector-db # 必须显示 "healthy" # 若为 "unhealthy",查看日志 docker compose logs vector-db \| grep -i "error\|fail" # 常见:磁盘空间不足,Weaviate 日志会报 "out of space"

Step 2:验证 Weaviate API 可达性

# 从宿主机测试 curl -X GET http://localhost:8080/v1/meta # 从 api 容器内部测试(关键!) docker compose exec api curl -v http://vector-db:8080/v1/meta # 若宿主机通、容器内不通,说明 Docker 网络配置错误

Step 3:检查 Weaviate 的 CORS 配置Weaviate 默认禁止跨域请求。Dify 的前端(Nginx)会以Origin: http://your-domain.com发起请求,Weaviate 必须显式允许。在docker-compose.ymlvector-db服务中,添加环境变量:

vector-db: image: semitechnologies/weaviate:1.23.4 environment: - AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true - QUERY_DEFAULTS_LIMIT=25 - DEFAULT_VECTORIZER_MODULE=none - CLUSTER_HOSTNAME=weaviate # 关键:允许所有来源(生产环境建议限定域名) - CORS_ALLOW_ORIGINS=*

注意:CORS_ALLOW_ORIGINS=*在生产环境有安全风险,应替换为具体域名,如http://your-domain.com,https://your-domain.com

4.4 Docker Compose 重启策略失效的 3 种场景与对策

restart: always并非万能。以下场景会导致它“静默失效”:

场景 1:OOM Killer 杀死进程当服务器内存不足,Linux OOM Killer 会杀死占用内存最高的进程。若vector-db被杀,Docker 会尝试重启,但若内存仍不足,重启后立即被杀,形成“启动-被杀-重启”循环。docker compose ps会显示Restarting (137)

对策:为 Weaviate 设置内存限制,在docker-compose.yml中:

vector-db: mem_limit: 2g mem_reservation: 1.5g

mem_reservation保证它始终有 1.5GB 可用,mem_limit防止它吃光所有内存。

场景 2:健康检查失败阈值过低healthcheck.retries: 3意味着连续 3 次失败就标记为 unhealthy。若 Weaviate 启动需 45 秒,而start_period: 30s,则健康检查在 30 秒时就开始,3 次失败后即停止。

对策:延长start_period至 60 秒,并增加retries

healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/v1/meta"] interval: 30s timeout: 10s retries: 5 start_period: 60s

场景 3:Docker Daemon 本身崩溃restart: always依赖 Docker Daemon 运行。若systemctl status docker显示inactive (dead),所有容器均无法自启。

对策:设置 Docker 服务开机自启并监控:

sudo systemctl enable docker sudo systemctl start docker # 添加简单监控脚本(每5分钟检查) echo '*/5 * * * * systemctl is-active --quiet docker || systemctl restart docker' | crontab -

4.5 Windows 用户专属避坑:WSL2 与 Docker Desktop 的兼容陷阱

Windows 用户常在 WSL2 中部署 Dify,却遭遇诡异问题。根本原因是 WSL2 的 Linux 内核与 Docker Desktop 的 Hyper-V 虚拟化存在资源竞争。

典型症状

  • docker compose up后,ps显示所有服务Up 1 second,无healthy状态
  • docker compose logs api显示OSError: [Errno 99] Cannot assign requested address
  • curl http://localhost返回Empty reply from server

根源:Docker Desktop 默认使用wsl2后端,但 WSL2 的网络栈与宿主机不完全互通。localhost在 WSL2 中指向 WSL2 自身,而非 Docker Desktop 的虚拟机。

终极解决方案(三选一)

  1. 推荐:在 WSL2 中原生安装 Docker(绕过 Docker Desktop)

    # 在 WSL2 Ubuntu 中执行 sudo apt install docker.io sudo systemctl enable docker sudo systemctl start docker # 此时 `localhost` 指向 WSL2,Docker 容器与之同网段
  2. 使用host.docker.internal替代localhost(仅限 Docker Desktop) 在docker-compose.yml中,将所有localhost替换为host.docker.internal

    api: environment: - VECTOR_DATABASE_URL=http://host.docker.internal:8080
  3. 禁用 WSL2,改用 Windows 原生 Docker Desktop(牺牲

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

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

立即咨询