当前位置: 首页 > news >正文

Dify部署全指南:Docker、Kubernetes与源码部署实战

1. 为什么Dify部署值得花一整天认真对待——不是装上就行,而是要稳、要快、要可维护

Dify 是我过去两年在客户现场落地最多的大模型应用平台之一。它不像单纯跑个 LLM 推理服务那样“启动即用”,而是一个典型的生产级 AI 应用中台:前端有 React 管理界面,后端有 FastAPI 提供 API,数据库要存知识库切片、会话历史、工作流定义,向量库要支撑 RAG 检索,还要对接外部 LLM(OpenAI / Ollama / DeepSeek / Qwen 等),甚至可能集成企业微信、飞书、钉钉等通知通道。这意味着——部署不是“复制粘贴 docker run 命令”,而是一次小型基础设施架构决策

我见过太多团队踩的坑:有人用 Docker Compose 在一台 8G 内存的笔记本上硬跑,结果知识库上传卡死、工作流执行超时;有人照着官网 Kubernetes 文档直接 apply,却忘了配置 PersistentVolume,重启后所有知识库全丢;还有人 clone 源码后 pip install -e .,发现本地 Python 环境里 PyTorch 和 Transformers 版本冲突,pip 重装十几次仍报错 ModuleNotFoundError: No module named 'torch._C'。这些都不是“不会”,而是对 Dify 的分层依赖结构缺乏系统性认知。

Dify 的核心价值在于“低代码构建 AI 应用”,但它的部署恰恰是高决策密度环节:你选 Docker,就默认接受单机轻量、快速验证,但要自己扛日志轮转、健康检查、配置热更新;你选 Kubernetes,就获得弹性伸缩、滚动升级、多租户隔离能力,但必须理解 StatefulSet 与 Headless Service 的配合逻辑、Ingress 路由规则如何匹配 /api/v1/ 和 /chat/ 前缀;你选源码部署,则完全掌控每个模块的启动顺序、环境变量注入方式、甚至能 patch 官方未合并的 PR,代价是每次升级都要手动 merge conflict。

所以这篇指南不叫“Dify 安装教程”,而叫“Dify 部署全指南”——它覆盖的不是“能不能跑起来”,而是“跑得稳不稳、扩得快不快、修得快不快、升得顺不顺”。我会用真实客户环境中的配置片段、kubectl describe pod 输出日志、docker logs -f 的实时反馈截图(文字还原)、以及 git diff 的关键行,告诉你每一步背后的真实意图。如果你正准备在测试环境搭一个 demo 给老板看,或要在生产环境承载 50+ 员工的智能客服知识库,又或者想基于 Dify 改造成内部 AI 工具平台——这篇文章里的每一个参数、每一处注释、每一次“我试过不行”的记录,都是从 17 个不同行业客户的部署现场抠出来的。

关键词不是堆砌,而是锚点:Dify是你要交付的平台实体,Docker是最小可行单元,Kubernetes是规模化底座,源码是终极控制权。三者不是并列选项,而是同一问题在不同成熟度阶段的解法光谱。接下来,我们按这个光谱展开——从最轻量的 Docker 开始,到最复杂的源码定制,全程不跳步、不省略、不假设你知道 kubectl get nodes 的输出含义。

2. Docker 部署:单机验证的黄金标准,但 90% 的失败源于环境预检缺失

2.1 为什么 Docker 是首选起点?——它把“环境一致性”从玄学变成可验证事实

Docker 的本质不是容器技术,而是环境契约封装。Dify 官方镜像(difyai/dify:latest)已将 Python 3.11、PostgreSQL 15、Redis 7、Elasticsearch 8、Weaviate 1.24 等全部依赖打包进一个 OCI 镜像。这意味着你在 Ubuntu 22.04、CentOS 7、macOS Sonoma 上运行 docker run,得到的是完全一致的二进制行为——这解决了传统“在我机器上能跑”的协作噩梦。

但前提是:你的 Docker 环境本身是干净的。我统计过近三个月客户部署失败案例,63% 的问题出在 Docker 引擎预检环节,而非 Dify 配置本身。比如:

  • docker info显示Storage Driver: overlay2是必须的,但某些旧版 CentOS 7 默认用 devicemapper,会导致 PostgreSQL 数据卷写入失败,现象是容器反复 restart,docker logs dify-db报错FATAL: could not write lock file "postmaster.pid": No space left on device(实际磁盘有 20G 剩余);
  • docker version中 Client 和 Server 版本差超过 2 个大版本(如 Client 24.0,Server 20.10),会导致 docker-compose.yml v3.8 语法解析异常,报错version is unsupported
  • 更隐蔽的是sysctl -w vm.max_map_count=262144未执行,导致 Elasticsearch 启动失败,日志里只有一行max virtual memory areas vm.max_map_count [65536] is too low, increase to at least [262144],新手往往忽略这条警告,以为是端口冲突。

所以我的 Docker 部署流程强制插入三道预检关卡:

  1. 内核与存储驱动校验

    # 必须返回 overlay2 docker info | grep "Storage Driver" # 必须返回 1(表示 cgroup v2 已启用,Kubernetes 兼容前提) stat -fc %T /sys/fs/cgroup # 检查内核版本(Ubuntu 22.04 要求 5.15+,否则 overlay2 性能劣化) uname -r
  2. 资源阈值硬性检查

    # 内存:Dify 最小推荐 8G,但实测 6G 可跑基础功能(无知识库) free -h | awk '/^Mem:/ {print $2}' # 磁盘:/var/lib/docker 至少预留 20G(PostgreSQL WAL 日志 + Weaviate 向量索引增长) df -h /var/lib/docker | awk 'NR==2 {print $4}' # 文件句柄:Dify 后端并发连接数默认 1000,需 ulimit -n >= 65536 ulimit -n
  3. Docker Desktop 特殊处理(仅 macOS/Windows)

    提示:Docker Desktop 默认分配 2GB 内存,这连 PostgreSQL 都起不来。必须进入 Settings → Resources → Memory,调至6GB 起步。且关闭 “Use the WSL 2 based engine”(Windows)或 “Use Rosetta for x86/amd64 emulation”(M1/M2 Mac)——Dify 镜像为 amd64 构建,强行模拟性能损失 40% 以上。

2.2 docker-compose.yml 的 7 处魔鬼细节——官方模板没说,但线上必填

Dify 官网提供的 docker-compose.yml 是极简版,适合演示,但离生产可用差 7 个关键补丁。我以客户真实环境(Ubuntu 22.04 + Docker 24.0.7)的最终版为例,逐行拆解:

version: '3.8' services: # --- 1. PostgreSQL:必须显式指定 initdb 参数,否则中文全文检索失效 --- db: image: postgres:15-alpine restart: always environment: POSTGRES_DB: dify POSTGRES_USER: dify POSTGRES_PASSWORD: dify # 关键:启用中文分词扩展 POSTGRES_INITDB_ARGS: "--auth-host=md5 --auth-local=trust --lc-collate=C.UTF-8 --lc-ctype=C.UTF-8" volumes: - ./volumes/db:/var/lib/postgresql/data # 关键:禁用 fsync 强制刷盘(开发/测试环境可接受,提升 3x 写入速度) command: > postgres -c fsync=off -c synchronous_commit=off -c full_page_writes=off healthcheck: test: ["CMD-SHELL", "pg_isready -U dify -d dify"] interval: 30s timeout: 10s retries: 5 # --- 2. Redis:必须设置 maxmemory-policy,否则内存溢出崩溃 --- redis: image: redis:7-alpine restart: always command: redis-server --save 60 1 --maxmemory 512mb --maxmemory-policy allkeys-lru volumes: - ./volumes/redis:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 30s timeout: 5s retries: 5 # --- 3. Web 服务:环境变量不是可选,而是强制覆盖项 --- web: image: difyai/dify:latest restart: always ports: - "3000:3000" # 前端 - "5001:5001" # API(官方文档写 5000,但 v1.0+ 已改为 5001) environment: # 关键:必须显式声明 SECRET_KEY,否则每次重启 session 失效 SECRET_KEY: "your-32-byte-secret-key-here" # 生成命令:openssl rand -base64 32 # 关键:DATABASE_URL 必须带 ?sslmode=disable,否则 PostgreSQL 连接拒绝 DATABASE_URL: "postgresql://dify:dify@db:5432/dify?sslmode=disable" # 关键:REDIS_URL 必须带 db=0,否则 Celery 任务队列无法识别 REDIS_URL: "redis://redis:6379/0" # 关键:LLM_PROVIDER 必须设为 "openai" 或 "ollama",空值导致启动报错 LLM_PROVIDER: "ollama" # 关键:OLLAMA_BASE_URL 必须指向宿主机 IP(非 localhost!) OLLAMA_BASE_URL: "http://host.docker.internal:11434" # macOS/Windows # OLLAMA_BASE_URL: "http://172.17.0.1:11434" # Linux(docker0 网桥 IP) # 关键:WEAVIATE_ENDPOINT 必须用 service 名,不能写 localhost WEAVIATE_ENDPOINT: "http://weaviate:8080" # 关键:CELERY_BROKER_URL 必须与 REDIS_URL 一致,否则异步任务不执行 CELERY_BROKER_URL: "redis://redis:6379/0" # 关键:ENABLE_WEB_SOCKET 必须设为 true,否则聊天界面无实时响应 ENABLE_WEB_SOCKET: "true" depends_on: db: condition: service_healthy redis: condition: service_healthy weaviate: condition: service_healthy volumes: - ./volumes/web:/app/storage # 知识库文件、日志、临时上传都存在这里 # 关键:添加资源限制,防止单个容器吃光内存 deploy: resources: limits: memory: 3G cpus: '1.5' # --- 4. Weaviate:必须禁用监控端口,否则与 Dify 冲突 --- weaviate: image: semitechnologies/weaviate:1.24.4 restart: always environment: QUERY_DEFAULTS_LIMIT: 25 AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true' PERSISTENCE_DATA_PATH: '/var/lib/weaviate' DEFAULT_VECTORIZER_MODULE: 'none' CLUSTER_HOSTNAME: 'node1' # 关键:关闭 Prometheus 监控端口(Dify 自带监控,双开导致端口占用) DISABLE_TELEMETRY: 'true' # 关键:必须显式设置 CORS,否则前端跨域请求失败 AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'weaviate-api-key' AUTHENTICATION_APIKEY_ADMIN_KEY: 'weaviate-admin-key' volumes: - ./volumes/weaviate:/var/lib/weaviate ports: - "8080:8080" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/v1/.well-known/ready"] interval: 30s timeout: 10s retries: 5

注意:host.docker.internal是 Docker Desktop 的特殊 DNS,Linux 下不存在。必须用ip route | awk '/default/ {print $3}'获取宿主机在 docker0 网桥上的 IP(通常是 172.17.0.1)。这是 Linux 用户 Docker 部署失败的头号原因——他们把 macOS 配置原样复制,结果 Ollama 服务根本连不上。

2.3 启动后的三分钟黄金检测清单——比看日志更快定位问题

docker-compose up -d后不要急着打开浏览器。执行以下 5 条命令,3 分钟内确认核心链路是否打通:

  1. 检查容器状态是否全绿

    docker-compose ps | awk '$4 !~ /Up/ {print $1, $4}' # 任何非 "Up" 状态都标红

    如果看到web Exit 1,立刻docker-compose logs web | tail -20,90% 是环境变量拼写错误(如DATA_BASE_URL少了个 S)。

  2. 验证 PostgreSQL 连通性(绕过 Dify)

    docker exec -it dify_db psql -U dify -d dify -c "SELECT version();"

    成功返回 PostgreSQL 版本即证明数据库层 OK。若报错psql: error: connection to server at "localhost" failed,说明db服务名在web容器内解析失败——检查depends_on是否漏写,或network_mode: "bridge"是否误加。

  3. 测试 Redis 键值存取(验证缓存层)

    docker exec -it dify_redis redis-cli SET test_key "hello" && \ docker exec -it dify_redis redis-cli GET test_key

    返回"hello"即通过。若超时,检查redis容器的command是否遗漏--save参数(持久化开关关闭会导致容器退出)。

  4. 直连 Weaviate API(跳过 Dify 中间层)

    curl -X GET http://localhost:8080/v1/meta

    应返回 JSON 包含version字段。若返回Connection refused,检查weaviate容器的ports是否映射正确,或healthcheck是否失败(常见于磁盘空间不足)。

  5. 触发一次 Dify 内部健康检查

    curl -X GET http://localhost:5001/health

    正常返回{"status":"ok","timestamp":...}。若返回 503,说明web容器虽运行,但未能连接 DB/Redis/Weaviate 中任一服务——此时docker-compose logs web的第一行错误就是根因。

这五步做完,Dify 基础服务链路就算通关。接下来才是真正的业务验证:上传 PDF 测试知识库切片、创建 LLM 模型配置、运行一个简单工作流。但请记住——Docker 部署的成败,80% 在启动前的预检和配置,20% 在启动后的验证。我见过太多人花 2 小时调web容器的环境变量,却忽略db容器的POSTGRES_INITDB_ARGS导致中文搜索永远返回空。

3. Kubernetes 部署:不是“把 docker-compose 翻译成 YAML”,而是重构运维范式

3.1 Kubernetes 部署的本质矛盾:Dify 的“有状态”与 K8s 的“无状态”哲学冲突

Kubernetes 的设计哲学是“一切皆可驱逐、一切皆可重建”。Pod 挂了?删掉,Controller 会新建一个。节点宕机?Pod 自动漂移到其他节点。但 Dify 的核心组件偏偏是强状态的:PostgreSQL 的 WAL 日志、Weaviate 的向量索引文件、Redis 的内存数据、Web 服务的/app/storage目录(存用户上传的 PDF/PPT)——这些都不能随 Pod 重建而丢失。

所以 Kubernetes 部署 Dify 的第一课,不是写 Deployment,而是重新定义“状态”的归属

  • 数据库状态:必须绑定 PersistentVolumeClaim(PVC),且 PVC 的volumeMode: Filesystem+accessModes: [ReadWriteOnce]是底线。我曾见某团队用ReadWriteMany挂载 NFS,结果 PostgreSQL 启动时报错could not open file "global/pg_filenode.map": Permission denied——因为 NFS 的 POSIX 权限模型与 PostgreSQL 的文件锁机制不兼容。
  • 向量库状态:Weaviate 官方明确要求使用hostPathlocal类型 PV(非网络存储),否则向量索引写入性能下降 10 倍。这意味着你必须在每个计划运行 Weaviate 的节点上,预先创建/var/lib/weaviate目录并chown 1001:1001(Weaviate 容器 UID)。
  • 应用状态/app/storage目录必须挂载独立 PVC,且该 PVC 的storageClassName必须支持Retain回收策略(而非默认的Delete)。否则kubectl delete -f dify.yaml后,所有知识库文件永久消失。

因此,Kubernetes 部署 Dify 不是“翻译”,而是状态分层治理:把 PostgreSQL、Weaviate、Redis 的状态分别托管给不同类型的存储后端,再用 StatefulSet 确保它们有稳定的网络标识(如dify-db-0.dify-db-headless),最后用 Deployment 管理无状态的 Web 层。

3.2 生产级 K8s 清单的 5 个不可妥协字段——比 Helm Chart 更可靠

Dify 官方 Helm Chart(chart.dify.ai)虽方便,但隐藏了太多魔改空间。我为客户定制的生产环境清单,全部手写 YAML,核心在于 5 个字段的精确控制:

3.2.1 PostgreSQL StatefulSet:initContainer 是救命稻草
apiVersion: apps/v1 kind: StatefulSet metadata: name: dify-db spec: serviceName: "dify-db-headless" replicas: 1 template: spec: initContainers: - name: init-chmod image: busybox:1.35 command: ['sh', '-c'] args: - | echo "Fixing permissions for PostgreSQL data dir..." chown -R 70:70 /var/lib/postgresql/data chmod -R 0700 /var/lib/postgresql/data volumeMounts: - name: pgdata mountPath: /var/lib/postgresql/data containers: - name: postgres image: postgres:15-alpine env: - name: POSTGRES_DB value: "dify" - name: POSTGRES_USER value: "dify" - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: dify-secrets key: db-password # 关键:必须显式设置 securityContext,否则 OpenShift 等加固环境启动失败 securityContext: runAsUser: 70 runAsGroup: 70 fsGroup: 70 volumeMounts: - name: pgdata mountPath: /var/lib/postgresql/data # 关键:livenessProbe 必须用 pg_isready,不能用 tcpSocket(端口通不代表 DB 可用) livenessProbe: exec: command: ["pg_isready", "-U", "dify", "-d", "dify"] initialDelaySeconds: 60 periodSeconds: 30 volumeClaimTemplates: - metadata: name: pgdata spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 20Gi # 关键:storageClassName 必须指定,否则用 default class,可能不满足性能要求 storageClassName: "ssd-sc" # 需提前创建 StorageClass

实操心得:initContainerchown是 PostgreSQL 在 K8s 中存活的关键。Alpine 镜像的默认 UID 70 对应postgres用户,但 PVC 挂载后目录属主常为 root,导致 PostgreSQL 进程无权写入。这个 3 行脚本,救活了我 8 个集群。

3.2.2 Weaviate StatefulSet:容忍度与亲和性必须双管齐下
apiVersion: apps/v1 kind: StatefulSet metadata: name: dify-weaviate spec: serviceName: "dify-weaviate-headless" replicas: 1 template: spec: # 关键:tolerations 让 Weaviate 只调度到 SSD 节点 tolerations: - key: "disktype" operator: "Equal" value: "ssd" effect: "NoSchedule" # 关键:nodeAffinity 确保与 PostgreSQL 同节点(降低向量检索延迟) affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - "node-01" # 与 dify-db 同节点 containers: - name: weaviate image: semitechnologies/weaviate:1.24.4 env: - name: QUERY_DEFAULTS_LIMIT value: "25" - name: AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED value: "true" - name: PERSISTENCE_DATA_PATH value: "/var/lib/weaviate" - name: DEFAULT_VECTORIZER_MODULE value: "none" - name: CLUSTER_HOSTNAME value: "node1" # 关键:resources limits 必须设,否则 OOMKilled 频发(Weaviate 内存泄漏已知问题) resources: limits: memory: "4Gi" cpu: "2" requests: memory: "2Gi" cpu: "1" volumeMounts: - name: weaviate-data mountPath: /var/lib/weaviate # 关键:livenessProbe 用 curl 检查 /v1/.well-known/ready,不能用 /v1/meta(后者不校验存储) livenessProbe: httpGet: path: /v1/.well-known/ready port: 8080 initialDelaySeconds: 120 periodSeconds: 60 volumeClaimTemplates: - metadata: name: weaviate-data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 50Gi # 关键:Weaviate 必须用 local PV,不能用 network storage storageClassName: "local-ssd"

注意:local-ssdStorageClass 需提前在每个目标节点创建:

# 在 node-01 上执行 mkdir -p /mnt/local-ssd # 格式化为 ext4 并挂载 mkfs.ext4 /dev/nvme0n1 && mount /dev/nvme0n1 /mnt/local-ssd # 创建 PV kubectl apply -f - <<EOF apiVersion: v1 kind: PersistentVolume metadata: name: weaviate-pv-node01 spec: capacity: storage: 50Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: local-ssd local: path: /mnt/local-ssd nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - node-01 EOF
3.2.3 Web Deployment:ConfigMap + Secret 的分离艺术

Dify 的环境变量多达 30+ 个,全塞进 Deployment 的env字段既难维护又易泄露。我的方案是:敏感信息进 Secret,配置参数进 ConfigMap,启动脚本做胶水

# dify-config.yaml apiVersion: v1 kind: ConfigMap metadata: name: dify-config data: # 非敏感配置放这里 APP_ENV: "production" LOG_LEVEL: "INFO" # 数据库连接字符串(不含密码)——注意:DATABASE_URL 里密码用占位符 DATABASE_URL: "postgresql://dify:@dify-db:5432/dify?sslmode=disable" # Redis 连接(不含密码) REDIS_URL: "redis://:@dify-redis:6379/0" # Weaviate 地址 WEAVIATE_ENDPOINT: "http://dify-weaviate:8080" # LLM 配置 LLM_PROVIDER: "ollama" OLLAMA_BASE_URL: "http://dify-ollama:11434" --- # dify-secrets.yaml apiVersion: v1 kind: Secret metadata: name: dify-secrets type: Opaque data: # base64 编码的敏感值 db-password: "ZGlm (base64 of 'dify')" redis-password: "" # Redis 无密码,留空 secret-key: "eW91ci0zMi1ieXRlLXNlY3JldC1rZXktaGVyZQo= (base64 of 32-byte key)" --- # web-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: dify-web spec: replicas: 2 template: spec: containers: - name: web image: difyai/dify:latest # 关键:envFrom 同时加载 ConfigMap 和 Secret,自动替换占位符 envFrom: - configMapRef: name: dify-config - secretRef: name: dify-secrets # 关键:启动前执行脚本,拼接完整 DATABASE_URL command: ["/bin/sh", "-c"] args: - | # 用 Secret 中的密码替换 DATABASE_URL 占位符 export DATABASE_URL=\${DATABASE_URL/@dify:/dify:\${db-password}@} export REDIS_URL=\${REDIS_URL/@:/\${redis-password}@} # 启动 Dify exec gunicorn --bind 0.0.0.0:5001 --workers 4 --worker-class sync --timeout 120 app:app volumeMounts: - name: storage mountPath: /app/storage volumes: - name: storage persistentVolumeClaim: claimName: dify-storage-pvc

实操心得:envFrom+command脚本的组合,让敏感信息零明文出现在 YAML 中,且避免了 Helm 的tpl函数复杂度。exec gunicorn ...中的exec是关键——它让容器 PID 1 是 gunicorn 进程,而非 shell,确保kubectl exec和信号传递正常。

3.2.4 Ingress:路径重写与 WebSocket 的生死线

Dify 前端(React)和后端(FastAPI)共用一个域名,但路由前缀不同:/走前端,/api/v1//chat/走后端。Kubernetes Ingress 必须精准重写,否则出现“白屏”或“连接已关闭”。

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: dify-ingress annotations: # 关键:nginx.ingress.kubernetes.io/rewrite-target 必须用 v1 注解 nginx.ingress.kubernetes.io/rewrite-target: /$2 # 关键:WebSocket 必须开启,否则聊天界面断连 nginx.ingress.kubernetes.io/upstream-hash-by: "$connection_upgrade" nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-origin: "*" spec: ingressClassName: nginx rules: - host: dify.example.com http: paths: - path: /api/v1/(.*) pathType: Prefix backend: service: name: dify-web port: number: 5001 - path: /chat/(.*) pathType: Prefix backend: service: name: dify-web port: number: 5001 - path: /(.*) pathType: Prefix backend: service: name: dify-web port: number: 3000

注意:path: /api/v1/(.*)中的(.*)是正则捕获组,$2表示第二个捕获组(即(.*)匹配的内容)。这样/api/v1/chat-messages会被重写为/chat-messages发送给dify-web:5001。如果写成$1,则重写为/api/v1/chat-messages,后端路由不匹配。

3.2.5 监控与日志:用 Prometheus Operator 替代 Grafana Cloud

Dify 自带/metrics端点,但默认只暴露基础指标。生产环境必须注入自定义 exporter:

# prometheus-dify-exporter.yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: dify-metrics spec: selector: matchLabels: app: dify-web endpoints: - port: http-metrics interval: 30s path: /metrics # 关键:添加 bearer token 认证,防未授权访问 scheme: https tlsConfig: insecureSkipVerify: true --- # dify-web-service.yaml 中添加 metrics 端口 ports: - name: http-metrics port: 9000 targetPort: 9000

然后在 Dify Web 容器中启动prometheus-flask-exporter

# Dockerfile.patch FROM difyai/dify:latest RUN pip install prometheus-flask-exporter COPY entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]
# entrypoint.sh #!/bin/sh # 启动 Prometheus exporter export PROMETHEUS_MULTIPROC_DIR=/tmp/prometheus_metrics gunicorn --bind 0.0.0.0:9000 --workers 1 --daemon prometheus_flask_exporter:app & # 启动 Dify exec gunicorn --bind 0.0.0.0:5001 --workers 4 app:app

这样,Prometheus 就能采集到dify_api_request_duration_seconds_bucket等业务指标,而不仅是process_cpu_seconds_total这类通用指标。

4. 源码部署:当标准化方案无法满足业务深度定制时的终极武器

4.1 源码部署不是“高级玩家炫技”,而是解决三个不可绕过的问题

我坚持源码部署 Dify 的客户,几乎都卡在同一个十字路口:

  • 问题一:需要修改知识库切片逻辑。某金融客户要求 PDF 表格识别必须保留原始行列结构,而 Dify 默认的unstructured切片器会把表格打散成纯文本。这必须修改core/rag/extractor/pdf.py中的extract_pdf函数,注入pdfplumber的表格提取逻辑。
  • 问题二:需要对接私有认证体系。某政务云客户要求 Dify 登录必须走统一身份认证(UAA),而非内置的邮箱密码。这需要重写api/controllers/console/auth/login.py中的login方法,并新增 UAA OAuth2 Provider。
  • 问题三:需要定制工作流节点。某电商客户希望工作流中增加“调用内部 ERP 接口”节点,而 Dify 官方只提供 HTTP、SQL、LLM 三类节点。这必须在core/workflow/nodes下新增erp_node.py,并注册到NODES列表。

这些问题,用 Docker/K8s 部署无法解决——镜像里代码是冻结的。源码部署的价值,不在于“能改”,而在于“改完还能一键升级”。

4.2 源码部署的黄金三角:Python 环境、依赖管理、Git 分支策略

4.2.1 Python 环境:为什么必须用 pyenv + virtualenv,而非系统 Python

Dify 依赖PyTorch 2.1+transformers 4.35+langchain 0.1.10+,这些包对 Python 版本极其敏感。Ubuntu 22.04 自带 Python 3.10,但 Dify v1.0+ 要

http://www.jsqmd.com/news/1157443/

相关文章:

  • 猫抓插件:浏览器资源嗅探与视频下载的终极解决方案
  • Windows 11文件资源管理器启动提速:从预加载到内核优化的体验革新
  • 接口文档智能解析Agent Skill推荐
  • 2026定制应用提效工具:5分钟生成定制系统、零代码AI搭建平台盘点
  • 2026年无锡企业AI服务商综合能力选型观察 - IT超人老张
  • 望谟黄金变现防坑手册:摸清四种常见套路,选对三十年老店安心出手 - 福金阁黄金回收
  • 季节面料备货智能分配程序,根据气温预测调整轻薄厚款面料采购比例。
  • 2026年靠谱的芝麻黑路沿石制造厂实用选购指南 - 热点品牌推荐
  • 金价高位震荡回落,普安黄金回收热潮暗藏多重陷阱,3 家 30 年合规老店安全变现指南 - 福金阁黄金回收
  • 终极原神FPS解锁器完整指南:轻松突破60帧限制
  • 广州GEO公司有哪些?2026头部服务商盘点:技术、资质与选型全攻略 - GEO优化
  • 虚拟文化体验翻译:虚拟角色对话的叙事性语言与多语种适配
  • Kimi Code实战:2小时搭建Java考试系统原型
  • SEOGEO优化公司哪家好?2026年L3级综合实力测评报告 - GEO优化
  • Codex智能体核心Skills安装配置实战:从零构建AI开发助手
  • 蚂蚁商铺定位赛全国第五名技术实现:SQL特征构建、XGBoost建模、Java指纹匹配与三模型融合
  • 别乱充会员!全学段论文 AI 写作工具大盘点,一篇分清谁值得买
  • 直流有刷电机驱动方案:TC78H653FTG与MKV46F256VLH16应用
  • BQ25887与STM32F411RE实现锂电池平衡充电方案
  • OpenGL 二维几何变换实战:glPushMatrix/glPopMatrix 堆栈操作 3 种典型错误分析
  • 每日 AI 研究简报 · 2026-07-09
  • 极简事件总线:用 Go Channel 实现进程内发布订阅的工程化封装
  • 黄金变现避坑指南:虚高报价背后的“偷金”套路,你中招了吗? - 福金阁黄金回收
  • JMeter混合场景压测实战:从设计到分析的全链路指南
  • 深度解析:2026年7月广州GEO公司TOP5核心技术与资质盘点 - GEO优化
  • Kimi Work Beta:操作系统级AI Agent工作流切片实践
  • VLAConf:面向视觉-语言-动作模型的单次前向置信度评估框架
  • Hive 倾斜 Join 实战:大表关联小表为什么也会慢
  • Fast-GitHub深度解析:如何通过浏览器插件架构重塑国内GitHub访问体验
  • 深入解析pytest fixture:从依赖注入到测试环境管理