一、概述
二、准备工作
前提条件
硬件
软件
镜像推送
下载镜像
docker pull postgres:15-alpine docker pull redis:6-alpine docker pull semitechnologies/weaviate:1.19.0 docker pull nginx:latest docker pull langgenius/dify-plugin-daemon:0.0.6-local docker pull langgenius/dify-sandbox:0.2.11 docker pull ubuntu/squid:latest docker pull langgenius/dify-api:1.1.3 docker pull langgenius/dify-web:1.1.3
推送镜像
这里使用shell脚本完成
#!/bin/bash images="postgres:15-alpine redis:6-alpine semitechnologies/weaviate:1.19.0 nginx:latest langgenius/dify-plugin-daemon:0.0.6-local langgenius/dify-sandbox:0.2.11 ubuntu/squid:latest langgenius/dify-api:1.1.3 langgenius/dify-web:1.1.3" # 遍历镜像列表,并推送到harbor for line in $images; do #echo "$line" docker tag $line harbor.qq.com:8083/dify/$line docker push harbor.qq.com:8083/dify/$line done
注意修改harbor的的地址为实际访问地址
登录到harbor,查看镜像
创建命名空间以及密钥
kubectl create namespace dify
kubectl create secret docker-registry harbor-key --docker-server=harbor.qq.com:8083 --docker-username=devops --docker-password=1sB5r9UShgK5 --namespace=dify
注意:修改harbor地址,用户名,密码。
下载部署yaml
yaml已经写好了,推送到我个人的github,地址:https://github.com/987334176/dify-k8s
下载项目后,进入文件夹1.1.3
目录结构
env --> 全局环境变量 pvc --> 所有组件,统一使用一个pvc来进行持久化存储 databases --> 数据库相关:postgresql,redis,weaviate middleware --> 中间件相关:plugin-daemon,sandox,ssf-proxy,nginx services --> 服务相关:api,web,worker
三、创建全局环境变量
这里有500个多个变量,直接一键运行
kubectl apply -f env/env.yaml
四、创建pv和pvc
创建storageClass,因为pv和pvc必须是同一个storageClass才能绑定成功
kubectl apply -f pvc/storageClass.yaml
注意:修改NFS 服务端的共享路径,provisioner必须指定为nfs-client
nfs-client是一个外部的动态存储供给器(Provisioner),用于在 Kubernetes 集群中动态创建和管理基于 NFS(Network File System)的 PersistentVolumes(PV)。它是 Kubernetes 社区提供的一个解决方案,用于支持 NFS 存储的动态供给。
创建pv,pvc。注意:这里的pv是自建的NFS,请根据实际情况修改
kubectl apply -f pvc/pv.yaml
kubectl apply -f pvc/pvc.yaml
查看pvc状态,注意:请确保pvc状态为Bound
# kubectl -n dify get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
dify-pvc Bound dify 10Gi RWX nfs-storage <unset> 12m
服务器已经挂载好了NFS,进入到NFS根目录
cd /mnt/nfs_share
创建dify相关持久化文件,并设置权限
mkdir -p dify/volumes/db/data mkdir -p dify/volumes/redis/data mkdir -p dify/volumes/weaviate mkdir -p dify/volumes/plugin_daemon mkdir -p dify/volumes/app/storage chmod 777 -R dify
五、数据库相关
postgresql
PostgreSQL 是一个功能强大的开源关系型数据库管理系统(RDBMS),以其稳定性、扩展性和对 SQL 标准的严格遵循而闻名。它支持复杂查询、事务、触发器、视图、存储过程等功能,适用于各种规模的应用程序。
自从MySQL被Oracle收购以后,PostgreSQL逐渐成为开源关系型数据库的首选。
修改文件postgres-StatefulSet.yaml
vi databases/postgresql/postgres-StatefulSet.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key terminationGracePeriodSeconds: 10 containers: - name: postgres image: harbor.qq.com:8083/dify/postgres:15-alpine
发布应用
kubectl apply -f databases/postgresql/postgres-StatefulSet.yaml
kubectl apply -f databases/postgresql/postgres-Service.yaml
查看postgresql日志
# kubectl -n dify logs -f postgres-0 ... UTC [72] WARNING: no usable system locales were found performing post-bootstrap initialization ...
第一次会出现,pod到这里就终止了,不用管
再次查看日志。
# kubectl -n dify logs -f postgres-0 2025-04-05 16:29:11.415 UTC [1] LOG: database system is ready to accept connections 2025-04-05 16:29:13.707 UTC [46] FATAL: database "postgres" does not exist 2025-04-05 16:29:18.721 UTC [53] FATAL: database "postgres" does not exist ...
提示数据库postgres不存在,因为在全局configMap里面,POSTGRES_DB的值为dify,所以默认的postgres不会创建。
这个是不影响dify运行的,但是postgres的健康检查命令,必须要这个数据库存在,否则会一直发日志。
手动创建postgres数据库
kubectl -n dify exec -it postgres-0 -- createdb postgres
再次查看日志,就不会再出现了。
进入容器,查看数据库列表
# kubectl -n dify exec -it postgres-0 -- /bin/bash postgres-0:/# psql -U postgres psql (15.12) Type "help" for help. postgres=# \list List of databases Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges -----------+----------+----------+------------+------------+------------+-----------------+------------------- postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | (2 rows)
postgres-# \q
说明:
psql -U postgres,这里 -U postgres 表示以 postgres 用户登录
\list,查看数据库列表
\q,退出
发现少了1个数据库dify,手动创建一下
postgres-0:/# createdb dify
注意:这里必须手动创建,否则api组件启动会出现报错:
psycopg2.OperationalError: FATAL: database "dify" does not exist
提示找不到数据库dify
进入postgres容器,添加一条白名单
vi /var/lib/postgresql/data/pgdata/pg_hba.conf
最后一行增加
host all all 0.0.0.0/0 md5
参数解释:
all 表示允许所有数据库和所有用户。
0.0.0.0/0 表示允许所有 IP 地址的连接。
md5 表示使用密码验证(推荐),注意生产环境,必须配置md5
重启PostgreSQL,直接删除pod即可,它会自动启动的
kubectl -n dify delete pods postgres-0
这里估计有很多小伙伴有疑问,为什么docker-compose运行dify都没问题,偏偏k8s运行,还需要给PostgreSQL添加白名单?有这个必要吗?
答案是有必要的!
首先来解释一下docker-compose是单机运行的,每个容器会暴露端口。所以容器之间,是可以通过127.0.0.1+端口,就可以访问对应的服务了。
而且pg_hba.conf的默认规则,就有127.0.0.1
# TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all trust # IPv4 local connections: host all all 127.0.0.1/32 trust # IPv6 local connections: host all all ::1/128 trust # Allow replication connections from localhost, by a user with the # replication privilege. local replication all trust host replication all 127.0.0.1/32 trust host replication all ::1/128 trust host all all 0.0.0.0/0 md5
但是k8s运行的pod,ip地址是动态的,网络地址是由k8s来分配的。
对于这种不确定ip的请求,我们就需要添加一条白名单,否则PostgreSQL会拒绝连接。
在下面的步骤中,还需要部署plugin-daemon组件,它需要连接到PostgreSQL,创建数据库dify_plugin。如果不加白名单,启动pod会失败,日志会出现以下提示:
2025/04/06 01:40:49 /app/internal/db/init.go:17 [error] failed to initialize database, got error failed to connect to `host=postgres user=postgres database=dify_plugin`: server error (FATAL: no pg_hba.conf entry for host "10.42.0.45", user "postgres", database "dify_plugin", no encryption (SQLSTATE 28000)) 2025/04/06 01:40:49 /app/internal/db/init.go:21 [error] failed to initialize database, got error failed to connect to `host=postgres user=postgres database=postgres`: server error (FATAL: no pg_hba.conf entry for host "10.42.0.45", user "postgres", database "postgres", no encryption (SQLSTATE 28000)) 2025/04/06 01:40:49 init.go:144: [PANIC]failed to init dify plugin db: failed to connect to `host=postgres user=postgres database=postgres`: server error (FATAL: no pg_hba.conf entry for host "10.42.0.45", user "postgres", database "postgres", no encryption (SQLSTATE 28000))
redis
Redis是一个开源的高性能键值存储数据库,它提供了多种数据结构来存储数据,如字符串、哈希、列表、集合、有序集合等。Redis将数据存储在内存中,以提供快速的读写访问速度,并且能够通过异步的方式将数据持久化到磁盘上。它支持复制、Lua脚本、事务处理、不同级别的持久化选项以及多种客户端语言的接口。Redis广泛用于缓存、消息队列、短时数据存储和高性能的应用场景中。
修改文件redis-StatefulSet.yaml
vi databases/redis/redis-StatefulSet.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key terminationGracePeriodSeconds: 10 containers: - name: redis image: harbor.qq.com:8083/dify/redis:6-alpine
发布应用
kubectl apply -f databases/redis/redis-StatefulSet.yaml
kubectl apply -f databases/redis/redis-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep redis redis-0 1/1 Running 0 31s
weaviate
Weaviate 是一个开源的向量搜索引擎,它采用了最新的机器学习模型来优化向量搜索和存储。Weaviate 使用图数据结构来组织数据,支持高效的向量索引和近似最近邻(ANN)搜索。
修改文件weaviate-StatefulSet.yaml
vi databases/weaviate/weaviate-StatefulSet.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key terminationGracePeriodSeconds: 10 containers: - name: weaviate image: harbor.qq.com:8083/dify/semitechnologies/weaviate:1.19.0
发布应用
kubectl apply -f databases/weaviate/weaviate-StatefulSet.yaml
kubectl apply -f databases/weaviate/weaviate-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep weaviate weaviate-0 1/1 Running 0 5m42s
六、中间件相关
注意:这里的Nginx,最后一个运行。因为它是用来转发各个组件api接口的。
plugin-daemon
Dify 组件 plugin-daemon 是一个用于管理插件生命周期的服务。它的主要功能包括以下几个方面:
1.插件运行时管理;2.与 Dify API 服务器通信;3.插件状态管理;4.支持插件开发;
修改文件plugin-daemon-Deployment.yaml
vi middleware/plugin-daemon/plugin-daemon-Deployment.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key automountServiceAccountToken: false containers: - name: plugin-daemon image: harbor.qq.com:8083/dify/langgenius/dify-plugin-daemon:0.0.6-local imagePullPolicy: IfNotPresent
发布应用
kubectl apply -f middleware/plugin-daemon/plugin-daemon-Deployment.yaml
kubectl apply -f middleware/plugin-daemon/plugin-daemon-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep plugin-daemon plugin-daemon-5dd85d6958-4ld29 1/1 Running 0 26m
如果是非Running状态,查看pod日志。如果出现连接PostgreSQL失败问题,请确保PostgreSQL的pg_hba.conf添加了白名单策略。
很多小伙伴就卡在这里了,一直运行失败,连接失败。为什么?因为没加白名单。
sandbox
功能
-
多语言支持:基于Seccomp,支持多种编程语言,如Python、Nodejs等。
-
系统安全:采用白名单策略,只允许运行特定的系统调用,防止意外绕过。
-
文件系统隔离:用户代码运行在一个独立的隔离文件系统中。
-
网络隔离:在DockerCompose中,创建独立网络Sandbox网络,并使用代理容器进行网络访问,确保内网系统的安全;在K8s中,直接使用Exgress配置网络隔离策略。
简单来说,我们在dify工作流中,执行代码这个步骤,就是由sandbox组件来执行的。
修改文件sandbox-Deployment.yaml
vi middleware/sandbox/sandbox-Deployment.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key automountServiceAccountToken: false containers: - name: sandbox image: harbor.qq.com:8083/dify/langgenius/dify-sandbox:0.2.11 imagePullPolicy: IfNotPresent
发布应用,注意执行顺序,先执行configMap,再执行下面的。
kubectl apply -f middleware/sandbox/sandbox-cm0.yaml kubectl apply -f middleware/sandbox/sandbox-cm1.yaml kubectl apply -f middleware/sandbox/sandbox-Deployment.yaml kubectl apply -f middleware/sandbox/sandbox-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep sandbox sandbox-5dbbdf68c8-dpbz7 1/1 Running 0 29s
ssrf-proxy
功能
-
拦截和控制网络请求:所有来自Dify系统中其他服务的网络请求都必须通过ssrf-proxy,从而可以对这些请求进行拦截和控制,防止恶意或不安全的请求直接访问外部网络。
-
限制访问特定资源:通过配置ssrf-proxy,可以限制Dify系统中的服务只能访问特定的外部资源,从而减少潜在的安全风险。
-
记录和监控网络活动:ssrf-proxy可以记录和监控所有通过它的网络请求,这有助于进行安全审计和故障排查。
-
支持上游代理配置:ssrf-proxy可以配置上游代理,以便在需要时将请求转发到其他代理服务器,从而实现更灵活的网络访问控制 。
修改文件sandbox-Deployment.yaml
vi middleware/ssrf-proxy/ssrf-proxy-Deployment.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key containers: - name: ssrf image: harbor.qq.com:8083/dify/ubuntu/squid:latest imagePullPolicy: IfNotPresent
发布应用,注意执行顺序,先执行configMap,再执行下面的。
kubectl apply -f middleware/ssrf-proxy/ssrf-proxy-cm0.yaml kubectl apply -f middleware/ssrf-proxy/ssrf-proxy-cm1.yaml kubectl apply -f middleware/ssrf-proxy/ssrf-proxy-Deployment.yaml kubectl apply -f middleware/ssrf-proxy/ssrf-proxy-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep ssrf ssrf-57998f8494-jgkhs 1/1 Running 0 41s
七、服务相关
api
功能
-
对话型应用支持:
-
提供
chat-messages
接口,支持会话持久化,适用于聊天和客服 AI 等场景 。 -
每次对话会生成一个唯一的
conversation_id
,用于保持会话的连续性。
-
-
文本生成型应用支持:
-
提供
completion-messages
接口,用于生成高质量文本,如文章、摘要和翻译等 。
-
-
工作流支持:
-
提供
workflows/run
接口,用于执行复杂的工作流任务,支持阻塞和流式响应 。
-
-
文件上传与处理:
-
支持图片等特定格式文件的上传,文件仅供当前终端用户使用 。
-
-
反馈与信息获取:
-
提供接口用于获取应用参数、配置信息和日志,方便优化输出和故障排查 。
-
修改文件api-StatefulSet.yaml
vi services/api/api-StatefulSet.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key containers: - name: api image: harbor.qq.com:8083/dify/langgenius/dify-api:1.1.3 imagePullPolicy: IfNotPresent
发布应用
kubectl apply -f services/api/api-StatefulSet.yaml
kubectl apply -f services/api/api-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep api api-0 1/1 Running 0 37s
查看日志,是否有报错
# kubectl -n dify logs -f api-0 ... Database migration successful! [2025-04-07 02:49:40 +0000] [1] [INFO] Starting gunicorn 23.0.0 [2025-04-07 02:49:40 +0000] [1] [INFO] Listening at: http://0.0.0.0:5001 (1) [2025-04-07 02:49:40 +0000] [1] [INFO] Using worker: gevent [2025-04-07 02:49:40 +0000] [13] [INFO] Booting worker with pid: 13
注意:api首次运行,会自动创建相关表结构,从日志中,就可以看到创建表结果过程。
web
功能
-
用户界面展示:为用户提供更多样化的界面模板,支持快速创建和部署 Web 应用,涵盖对话式和文本生成两类应用,分别适用于不同场景 。
-
自定义和扩展能力:支持多种部署方式和定制开发,开发者可以根据需求进行轻量级或重量级开发,增强应用功能或构建独立的前端应用 。
-
多设备适配:已适配不同尺寸的设备,包括 PC、平板和手机,确保用户在各种设备上都能获得良好的使用体验。
修改文件web-Deployment.yaml
vi services/web/web-Deployment.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key automountServiceAccountToken: false restartPolicy: Always containers: - name: web image: harbor.qq.com:8083/dify/langgenius/dify-web:1.1.3 imagePullPolicy: IfNotPresent
发布应用
kubectl apply -f services/web/web-Deployment.yaml
kubectl apply -f services/web/web-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep web web-5d96685865-lts4s 1/1 Running 0 38s
worker
功能
-
异步任务处理:处理异步任务,如数据处理、文件转换或批量操作 。
-
任务调度:支持任务调度,类似于 xxl-job,可以挂起和重启任务
修改文件worker-StatefulSet.yaml
vi services/worker/worker-StatefulSet.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key restartPolicy: Always containers: - name: worker image: harbor.qq.com:8083/dify/langgenius/dify-api:1.1.3 imagePullPolicy: IfNotPresent
发布应用
kubectl apply -f services/worker/worker-StatefulSet.yaml
kubectl apply -f services/worker/worker-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep worker worker-0 1/1 Running 0 59s
等待上面所有组件运行正常之后,部署Nginx组件
修改文件nginx-Deployment.yaml
vi middleware/nginx/nginx-Deployment.yaml
修改红色部分,增加了密钥,改了镜像地址
spec: imagePullSecrets: - name: harbor-key automountServiceAccountToken: false containers: - name: nginx image: harbor.qq.com:8083/dify/nginx:latest imagePullPolicy: IfNotPresent
发布应用,注意执行顺序,先执行configMap,再执行下面的。
kubectl apply -f middleware/nginx/nginx-cm0.yaml kubectl apply -f middleware/nginx/nginx-cm1.yaml kubectl apply -f middleware/nginx/nginx-cm2.yaml kubectl apply -f middleware/nginx/nginx-cm3.yaml kubectl apply -f middleware/nginx/nginx-cm4.yaml kubectl apply -f middleware/nginx/nginx-cm5.yaml kubectl apply -f middleware/nginx/nginx-Deployment.yaml kubectl apply -f middleware/nginx/nginx-Service.yaml
查看pod,确保是Running状态
# kubectl -n dify get pods|grep nginx nginx-9b564959c-pg4hk 1/1 Running 0 2m59s
八、访问dify
如果是生产环境,最好是域名访问,则需要添加一条ingress规则,指向到nginx的svc,并做DNS解析,指向到ingress的公网ip。
这里直接使用nginx的nodeport端口访问
查看nginx的svc
# kubectl -n dify get svc|grep nginx nginx NodePort 10.43.122.247 <none> 80:31540/TCP 8m33s
可以看到nodeport对应的端口是31540
查看node节点
# kubectl get node -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME ubuntu-1 Ready control-plane,master 17h v1.32.3+k3s1 10.0.2.15 <none> Ubuntu 22.04 LTS 5.15.0-136-generic docker://28.0.4
可以看到node节点ip是,10.0.2.15
访问页面:
http://10.0.2.15:31540
如果页面加载一半,注册页面显示异常,一直在转圈,查看页面console:
http://10.0.2.15:31540/console/api/setup出现500错误,那么有可能是api组件出现故障了,需要查看pod日志。
输入管理员邮箱,用户名,密码
登录之后,首页效果如下:
点击右上角的用户,可以看到版本为1.1.3
九、测试dify
插件
点击右上角账号-->设置
添加模型供应商,安装通义千问
安装过程中,右上角会报错:
Reached maximum retries (3) for URL https://marketplace.dify.ai/api/v1/plugins/download?unique_identifier=langgenius/tongyi:0.0.15@76
注意:出现这个提示,表示自己的公网ip已经被 marketplace.dify.ai加入黑名单了,之后无论重试多少次就没有用的。
怎么解决?
既然在线安装的路被堵了,那就换一条道路,本地安装插件。
首先访问插件官网:https://marketplace.dify.ai/
点击模型,搜索tongyi
点击进去,点击下载
会提到文件langgenius-tongyi_0.0.15.difypkg
登录dify,进入首页,点击右边的插件
点击本地安装
选择本地下载的文件,安装
等待一会,提示安装成功
安装成功后,插件不会立即显示,刷新一次页面,就可以看到了。
再次回到模型供应商设置,可以看到通义千问了。点击设置api-key
输入api密钥,验证通过后
设置系统模型
应用测试
返回首页,创建空白应用
选择模型,发布,运行
输入问题
在企业生产环境中,有很多人在用。api组件的连接池是30个,通过api调用就可以查看。
进入到api组件的pod
kubectl -n dify exec -it api-0 -- /bin/bash
查看连接池信息
# curl http://127.0.0.1:5001/db-pool-stat {"checked_in_connections":7,"checked_out_connections":0,"connection_timeout":30.0,"overflow_connections":-23,"pid":27,"pool_size":30,"recycle_time":3600}
如果超过连接池,请求会被拒绝。 社区版限制的连接池是30个,你改参数是没有意义的,最终还是30个。
针对上百人以上的企业,那么就直接扩容api组件的数量即可,比如运行3个以上的副本即可。
具体副本数量,请根据实际情况调整即可。
搭建过程就到这里结束了,感谢大家耐心的观看。
在这个过程中,遇到了不少的坑,总算是解决了。
原创作者: xiao987334176 转载于: https://www.cnblogs.com/xiao987334176/p/18810257