📖 前言

在本地部署大模型应用(如 Dify + Ollama + Open WebUI)是掌握 AI 自主权的关键一步。然而,在 Windows 环境下,我们不仅要面对复杂的 docker-compose.yml 配置,还时常会遭遇 Docker Desktop 和 WSL 2 的“突发状况”。
本文基于一次真实的从无到有的部署经历,详细记录了环境搭建步骤、关键配置细节,以及遇到 WSL 磁盘文件锁死 时的完整排查与修复过程。希望这份实录能帮助大家少走弯路,顺利跑通自己的本地 AI 引擎。

🛠️ 第一阶段:环境准备与基础搭建

1.1 基础环境

  • 操作系统: Windows 10/11
  • 命令行工具: PowerShell (自带) 或 CMD,我用的PowerShell
  • 容器引擎: Docker Desktop (建议从微软商店或官网下载最新版,确保勾选 "Use WSL 2" 选

补充:

Git (下载项目用)

NVIDIA Container Toolkit (仅限有 N 卡用户)

1.2 创建项目目录

在 D 盘创建专属部署目录:

mkdir D:\AI_Local_Deploy
cd D:\AI_Local_Deploy

1.3 编写核心配置文件 docker-compose.yml

在项目目录下新建 docker-compose.yml 文件,填入以下配置。该配置包含三个核心部分:Ollama 模型引擎Open WebUI 交互界面Dify 应用编排平台

version: '3.8'

services:
  # API 服务
  api:
    image: langgenius/dify-api:latest
    # 【备选】如果拉取失败,取消下面注释使用阿里云镜像
    # image: registry.cn-hangzhou.aliyuncs.com/langgenius/dify-api:latest
    restart: always
    environment:
      MODE: api
      LOG_LEVEL: INFO
      SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
      CONSOLE_WEB_URL: ''
      INIT_PASSWORD: ''
      CONSOLE_API_URL: ''
      SERVICE_API_URL: ''
      APP_WEB_URL: ''
      FILES_URL: ''
      MIGRATION_ENABLED: 'true'
      DB_USERNAME: postgres
      DB_PASSWORD: difyai123456
      DB_HOST: db
      DB_PORT: 5432
      DB_DATABASE: dify
      REDIS_HOST: redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: difyai123456
      CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
      WEB_API_CORS_ALLOW_ORIGINS: '*'
      CONSOLE_CORS_ALLOW_ORIGINS: '*'
      STORAGE_TYPE: local
      STORAGE_LOCAL_PATH: /app/storage
      VECTOR_STORE: milvus
      MILVUS_URI: http://milvus:19530
      MILVUS_USER: root
      MILVUS_PASSWORD: Milvus
      MILVUS_SECURE: 'false'
    volumes:
      - ./volumes/app/storage:/app/storage
    depends_on:
      - db
      - redis
      - milvus
    networks:
      - dify-network

  # Worker 服务 (后台任务)
  worker:
    image: langgenius/dify-worker:latest
    # 【备选】如果拉取失败,取消下面注释使用阿里云镜像
    # image: registry.cn-hangzhou.aliyuncs.com/langgenius/dify-worker:latest
    restart: always
    environment:
      MODE: worker
      LOG_LEVEL: INFO
      SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
      DB_USERNAME: postgres
      DB_PASSWORD: difyai123456
      DB_HOST: db
      DB_PORT: 5432
      DB_DATABASE: dify
      REDIS_HOST: redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: difyai123456
      CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
      STORAGE_TYPE: local
      STORAGE_LOCAL_PATH: /app/storage
      VECTOR_STORE: milvus
      MILVUS_URI: http://milvus:19530
      MILVUS_USER: root
      MILVUS_PASSWORD: Milvus
      MILVUS_SECURE: 'false'
    volumes:
      - ./volumes/app/storage:/app/storage
    depends_on:
      - db
      - redis
      - milvus
    networks:
      - dify-network

  # Web 前端服务
  web:
    image: langgenius/dify-web:latest
    # 【备选】如果拉取失败,取消下面注释使用阿里云镜像
    # image: registry.cn-hangzhou.aliyuncs.com/langgenius/dify-web:latest
    restart: always
    environment:
      CONSOLE_API_URL: ''
      SERVICE_API_URL: ''
      APP_API_URL: ''
      SENTRY_DSN: ''
    ports:
      - "3000:3000"  # 暴露端口以便访问
    networks:
      - dify-network

  # 数据库 PostgreSQL
  db:
    image: postgres:15-alpine
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: difyai123456
      POSTGRES_DB: dify
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - ./volumes/db/data:/var/lib/postgresql/data
    networks:
      - dify-network

  # 缓存 Redis
  redis:
    image: redis:6-alpine
    restart: always
    command: redis-server --requirepass difyai123456
    volumes:
      - ./volumes/redis/data:/data
    networks:
      - dify-network

  # 向量数据库 Milvus (已修复:添加启动命令)
  milvus:
    image: milvusdb/milvus:v2.3.4
    restart: always
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
      # 可选:限制内存使用,防止 OOM (根据您的物理内存调整,单位 MB)
      # MEM_SIZE_LIMIT: 2048 
    depends_on:
      - etcd
      - minio
    volumes:
      - ./volumes/milvus/data:/var/lib/milvus
    # 【关键修复】显式指定启动命令为 standalone 模式
    command: ["milvus", "run", "standalone"]
    ports:
      - "19530:19530" # 暴露 Milvus 端口 (可选,方便调试)
      - "9091:9091"   # 暴露监控端口 (可选)
    networks:
      - dify-network

  # Etcd (Milvus 依赖)
  etcd:
    image: quay.io/coreos/etcd:v3.5.5
    restart: always
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
    volumes:
      - ./volumes/etcd:/etcd
    # 确保监听所有接口,允许容器内访问
    command: etcd -advertise-client-urls=http://0.0.0.0:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
    networks:
      - dify-network

  # MinIO (对象存储)
  minio:
    image: minio/minio:RELEASE.2023-03-20T20-16-18Z
    restart: always
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    command: server /data --console-address ":9001"
    volumes:
      - ./volumes/minio/data:/data
    ports:
      - "9000:9000" # 对象存储端口
      - "9001:9001" # 控制台端口
    networks:
      - dify-network

networks:
  dify-network:
    driver: bridge

1.4 执行安装

docker compose up -d  ,第一次一般执行的不顺利出各种问题,我通过ai费了好几个小时才弄好。

第二阶段:遇到的坑与关键处理技巧

2.1 镜像版本手动对齐 (Tag Trick)

由于 Dify 的 worker 镜像在某些仓库中可能缺失或与 api 版本不一致,导致拉取失败。我们可以通过手动打标签的方式,复用 api 镜像作为 worker 镜像(因为它们核心代码一致)。

# 1. 拉取最新 API 和 Web 镜像
docker pull langgenius/dify-api:latest
docker pull langgenius/dify-web:latest

# 2. 将 latest 标记为具体版本号 (例如 0.6.10),防止 compose 中写死版本导致不匹配
docker tag langgenius/dify-api:latest langgenius/dify-api:0.6.10
docker tag langgenius/dify-web:latest langgenius/dify-web:0.6.10

# 3. 【核心技巧】将 API 镜像复用作 Worker 镜像
docker tag langgenius/dify-api:latest langgenius/dify-worker:0.6.10
docker tag langgenius/dify-worker:0.6.10 langgenius/dify-worker:latest

# 验证镜像列表
docker images | findstr langgenius

此时你应该看到 dify-api, dify-web, dify-worker 都存在且 ID 对应正确。

2.2 WSL 磁盘文件锁死急救 (Critical Fix)

在启动过程中,如果 Docker Desktop 卡住或报错 The system cannot find the file specified,通常是因为 WSL 的虚拟磁盘文件 (ext4.vhdx) 被占用或损坏。

🚑 急救三步走:

Step 1: 强制杀死残留进程

清理所有可能占用 WSL 资源的进程:

Get-Process | Where-Object { $_.Name -like "*vmmem*" -or $_.Name -like "*docker*" -or $_.Name -eq "wsl" } | Stop-Process -Force -ErrorAction SilentlyContinue
wsl --shutdown
Start-Sleep -Seconds 3
Step 2: 删除损坏的虚拟磁盘文件

找到并删除 WSL 的主磁盘文件(路径可能因安装方式略有不同,常见于 AppData\Local\Docker\wsldist 或 AppData\Local\Docker\wsl\main):

# 示例路径,请根据实际情况调整
$badFile = "C:\Users\admin\AppData\Local\Docker\wsl\main\ext4.vhdx"

if (Test-Path $badFile) {
    Remove-Item -Path $badFile -Force
    Write-Host "🎉 文件锁已解除,损坏磁盘已删除。" -ForegroundColor Green
} else {
    Write-Host "ℹ️ 文件不存在或已被删除。" -ForegroundColor Cyan
}

⚠️ 警告:此操作会重置 Docker 的所有数据(镜像、容器、卷)。如果是生产环境请谨慎操作,开发环境这是最快的恢复手段。

Step 3: 重启 Docker 并重建
  1. 手动以管理员身份启动 Docker Desktop
  2. 等待左下角显示绿色 "Engine running" (此时 Docker 会在后台自动重建 ext4.vhdx)。
  3. 再次尝试部署。

🚀 第三阶段:正式启动与验证

一切准备就绪后,执行最终启动命令:

cd D:\AI_Local_Deploy
docker compose up -d

✅ 成功标志

终端应输出类似以下内容,且无红色报错:

[+] up 14/14
✔ Image minio/minio:... Pulled
✔ Image milvusdb/milvus:... Pulled
✔ Network ai_local_deploy_dify-network Created
✔ Container ai_local_deploy-db-1 Created
...
✔ Container ai_local_deploy-worker-1 Created

(注:如果您的配置中包含 Milvus 向量库,Dify 会自动拉取相关镜像,首次启动耗时约 5-10 分钟)

🔍 验证服务状态

  1. 查看容器运行状态

    docker ps

    确认 ollama-serveropen-webuidify-apidify-web 等状态均为 Up

  2. 访问应用界面

    • Open WebUI: 浏览器访问 http://localhost:3000
    • Dify: 浏览器访问 http://localhost:3001 (根据配置中的端口映射)
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐