Dify:自建AI工作流平台
Module:
Categories:
Dify 是一个生成式 AI 应用创新引擎,开源的 LLM 应用开发平台。 提供从 Agent 构建到 AI workflow 编排、RAG 检索、模型管理等能力,帮助用户轻松构建和运营生成式 AI 原生应用。
Pigsty 提供对自建 Dify 的支持,您可以一键拉起 Dify ,并将关键状态保存于外部由 Pigsty 管理的 PostgreSQL, 并使用同一个 PG 中的 pgvector 作为向量数据库,进一步简化版部署。
快速上手
curl -fsSL https://repo.pigsty.cc/get | bash; cd ~/pigsty
./bootstrap # 安装 Pigsty 依赖
./configure -c app/dify # 使用 Dify 配置模板
vi pigsty.yml # 修改密码,域名,密钥等参数
./install.yml # 安装 Pigsty
./docker.yml # 安装 Docker 模块
./app.yml # 拉起 Dify
Dify 默认监听于 5001
端口,你可以通过浏览器访问 http://<ip>:5001
,并设置初始用户与密码后登陆。
Dify 是什么?
为什么要自建Dify?
自建 Dify 的原因有很多,但主要是出于数据安全的考虑。 Dify 提供的 DockerCompose 模板使用的是简陋的默认数据库镜像,缺少企业级应用所需的高可用性,容灾能力,监控,IaC,PITR 等能力。
Pigsty 可以优雅地为 Dify 解决这些问题,根据配置文件一键拉起所有组件,并使用镜像解决国内翻墙难题。让 Dify 的部署与交付无比丝滑。 一次性解决 PostgreSQL 主数据库与 PGVector 向量数据库,MinIO 对象存储,Redis,Prometheus 监控与 Grafana 可视化,以及 Nginx 反向代理,免费 HTTPS 证书。
Pigsty 可以确保 Dify 所有的状态都存储在外部托管服务中,包括 PostgreSQL 中的元数据,与文件系统中的其他数据。 因此,使用 Docker Compose 拉起的 Dify 是无状态的简单应用,可以随时销毁与重建。
单节点安装
让我们先从单节点 Dify 部署开始,我们会在后面进一步介绍生产环境高可用部署的方法。
首先,使用 Pigsty 标准安装流程 安装 Dify 所需的 MinIO 与 PostgreSQL 实例;
您可以使用 在 app/dify
配置模板快速进行单机 Dify 部署。
当你使用 ./configure -c app/dify
命令时,Pigsty 会自动根据 conf/app/dify.yml
配置模板,以及您当前的环境生成 Pigsty 配置文件。
您应该根据自己的实际需求,在生成的配置文件 pigsty.yml
中,修改密码,域名等相关参数,然后使用 ./install.yml
执行标准安装流程即可。
然后额外运行 docker.yml
与 app.yml
完成剩余的工作,
拉起无状态部分的 Dify 容器,就可以使用了(默认端口 5001
)。
curl -fsSL https://repo.pigsty.cc/get | bash; && cd ~/pigsty
./bootstrap # 准备 Pigsty 依赖
./configure -c app/supa # 使用 Supabase 应用模板
vi pigsty.yml # 编辑配置文件,修改域名与密码
./install.yml # 安装 Pigsty,以及各种数据库
./docker.yml # 安装 Docker 与 Docker Compose
./app.yml # 使用 Docker 拉起 Supabase 无状态部分
如果您的配置没有问题,那么大约在 10 分钟后,您就可以在本地网络通过 http://<your_ip_address>:5001
访问到 Dify Web 管理界面了。
默认的用户名,邮箱,密码会在首次登陆时提醒您设置。
你也可以使用本地解析的占位域名 dify.pigsty
,或者参考下面的配置,使用真正的域名与 HTTPS 证书。
检查清单
以下是您需要关注的配置项检查清单:
- 硬件/软件:准备所需的机器资源:Linux
x86_64/arm64
服务器一台,全新安装主流 Linux 操作系统 - 网络/权限:有 ssh 免密登陆权限,所用用户有免密 sudo 权限
- 确保机器有内网静态IPv4网络地址,并可以访问互联网。
- 在
configure
过程中,请输入节点的内网首要 IP 地址,或直接通过-i <primary_ip>
命令行参数指定
- 在
-
- 如果您的网络环境无法访问 DockerHub,请通过
docker_registry_mirrors
使用镜像站 或proxy_env
绕过防火墙。
- 如果您的网络环境无法访问 DockerHub,请通过
- 确保使用了
app/dify
配置模板,并按需修改了参数- 您是否修改了所有与密码有关的配置参数?【可选】
-
grafana_admin_password
:pigsty
,Grafana管理员密码 -
pg_admin_password
:DBUser.DBA
,PG超级用户密码 -
pg_monitor_password
:DBUser.Monitor
,PG监控用户密码 -
pg_replication_password
:DBUser.Replicator
,PG复制用户密码 -
patroni_password
:Patroni.API
,Patroni 高可用组件密码 -
haproxy_admin_password
:pigsty
,负载均衡器管控密码 -
minio_access_key
:minioadmin
,MinIO 根用户名 -
minio_secret_key
:minioadmin
,MinIO 根用户密钥
-
- 您是否修改了 PostgreSQL 集群业务用户的密码,以及使用此密码的 App 配置?
- 您是否修改了 Dify 默认使用的加密密钥?
- 您是否修改了所有与密码有关的配置参数?【可选】
那么也同样要修改 all.children.odoo.vars.apps.<dify>.conf.PG_PASSWORD
参数,以确保 Odoo 与 PostgreSQL 数据库的连接正常。
这里需要特别注意的是,请务必使用 openssl rand -base64 42
生成一个你自己的随机密钥,替换 SECRET_KEY
,并相应更改其他密码类参数。
第二个需要注意的地方是域名,如果你想要使用真正的域名,你需要将配置中的 dify.pigsty
占位假域名替换为你自己的域名。
例如,假设你使用的域名是:
dify.my.com
,那么可以sed -ie 's/dify.pigsty/dify.my.com/g' pigsty.yml
all:
children:
# the dify application (default username & password: admin/admin)
dify:
hosts: { 10.10.10.10: {} }
vars:
app: dify # specify app name to be installed (in the apps)
apps: # define all applications
dify: # app name, should have corresponding ~/app/dify folder
file: # data directory to be created
- { path: /data/dify ,state: directory ,mode: 0755 }
conf: # override /opt/dify/.env config file
# change domain, mirror, proxy, secret key
NGINX_SERVER_NAME: dify.pigsty
# A secret key for signing and encryption, gen with `openssl rand -base64 42` (CHANGE PASSWORD!)
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
# expose DIFY nginx service with port 5001 by default
DIFY_PORT: 5001
# where to store dify files? the default is ./volume, we'll use another volume created above
DIFY_DATA: /data/dify
# proxy and mirror settings
#PIP_MIRROR_URL: https://pypi.tuna.tsinghua.edu.cn/simple
#SANDBOX_HTTP_PROXY: http://10.10.10.10:12345
#SANDBOX_HTTPS_PROXY: http://10.10.10.10:12345
# database credentials
DB_USERNAME: dify
DB_PASSWORD: difyai123456
DB_HOST: 10.10.10.10
DB_PORT: 5432
DB_DATABASE: dify
VECTOR_STORE: pgvector
PGVECTOR_HOST: 10.10.10.10
PGVECTOR_PORT: 5432
PGVECTOR_USER: dify
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
PGVECTOR_MIN_CONNECTION: 2
PGVECTOR_MAX_CONNECTION: 10
pg-meta:
hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
vars:
pg_cluster: pg-meta
pg_users:
- { name: dify ,password: difyai123456 ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: dify superuser }
pg_databases:
- { name: dify ,owner: dify ,revokeconn: true ,comment: dify main database }
- { name: dify_fs ,owner: dify ,revokeconn: true ,comment: dify fs database }
pg_hba_rules:
- { user: dify ,db: all ,addr: 172.17.0.0/16 ,auth: pwd ,title: 'allow dify access from local docker network' }
node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am
infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }
etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }
#minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }
vars: # global variables
version: v3.4.0 # pigsty version string
admin_ip: 10.10.10.10 # admin node ip address
region: default # upstream mirror region: default|china|europe
node_tune: oltp # node tuning specs: oltp,olap,tiny,crit
pg_conf: oltp.yml # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
docker_enabled: true # enable docker on app group
#docker_registry_mirrors: ["https://docker.1ms.run"] # use mirror in mainland china
proxy_env: # global proxy env when downloading packages & pull docker images
no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
#http_proxy: 127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
#https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:pass@proxy.xxx.com
#all_proxy: 127.0.0.1:12345
infra_portal: # domain names and upstream servers
home : { domain: h.pigsty }
grafana : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
prometheus : { domain: p.pigsty ,endpoint: "${admin_ip}:9090" }
alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9093" }
blackbox : { endpoint: "${admin_ip}:9115" }
loki : { endpoint: "${admin_ip}:3100" }
#minio : { domain: m.pigsty ,endpoint: "${admin_ip}:9001" ,scheme: https ,websocket: true }
dify: # nginx server config for dify
domain: dify.pigsty # REPLACE WITH YOUR OWN DOMAIN!
endpoint: "10.10.10.10:5001" # dify service endpoint: IP:PORT
websocket: true # add websocket support
certbot: dify.pigsty # certbot cert name, apply with `make cert`
#----------------------------------#
# Credential: CHANGE THESE PASSWORDS
#----------------------------------#
#grafana_admin_username: admin
grafana_admin_password: pigsty
#pg_admin_username: dbuser_dba
pg_admin_password: DBUser.DBA
#pg_monitor_username: dbuser_monitor
pg_monitor_password: DBUser.Monitor
#pg_replication_username: replicator
pg_replication_password: DBUser.Replicator
#patroni_username: postgres
patroni_password: Patroni.API
#haproxy_admin_username: admin
haproxy_admin_password: pigsty
#minio_access_key: minioadmin
minio_secret_key: minioadmin # minio root secret key, `minioadmin` by default
# use minio as default backup repo for PostgreSQL
repo_extra_packages: [ pg17-main ]
pg_version: 17
Pigsty的准备工作
我们用 单机安装 的 Pigsty 为例,假设你有一台 IP 地址为 10.10.10.10
的机器,已经 安装好了单机 Pigsty。
当然,我们需要在 Pigsty 配置文件 pigsty.yml
中定义一下我们所需的数据库集群。
这里定义了一个名为 pg-meta
的集群,其中有一个名为 dify
的超级业务用户,
一个安装了 pgvector
扩展插件的数据库 dify
,以及一条特定的防火墙规则,允
许用户通过密码从任何地方访问数据库(你也可以将其限制为docker的网段 172.0.0.0/8
之类更精确的范围)。
pg-meta:
hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
vars:
pg_cluster: pg-meta
pg_users:
- { name: dify ,password: difyai123456 ,pgbouncer: true ,roles: [ dbrole_admin ] ,superuser: true ,comment: dify superuser }
pg_databases:
- { name: dify ,owner: dify ,revokeconn: true ,comment: dify main database }
pg_hba_rules:
- { user: dify ,db: all ,addr: 172.17.0.0/16 ,auth: pwd ,title: 'allow dify access from local docker network' }
- { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am
这里出于演示目的,我们全部使用单实例配置,你可以参考 Pigsty 文档部署 高可用 的 PG 集群。
bin/pgsql-add pg-meta # create the dify database cluster
当然,您也可以在现有的 PostgreSQL 集群,例如 pg-meta
上新定义 业务用户 与 业务数据库,并通过以下命令创建:
bin/pgsql-user pg-meta dify # create dify biz user
bin/pgsql-db pg-meta dify # create dify biz database
您应该可以通过以下的连接串,访问 到 PostgreSQL,当然连接信息请根据实际情况进行修改。
psql postgres://dify:difyai123456@10.10.10.10:5432/dify -c 'SELECT 1'
当你确认这个连接串可用后,大功告成,你可以开始部署 Dify 了。
这里出于演示方便的原因,使用IP直连的土办法,如果是多节点的高可用 PG 集群,请参考 接入 一节。
当然,上面的部分是假设你已经是 Pigsty 用户,了解如何部署 PostgreSQL 与 Redis 集群。你可以直接跳过下一节,查看 Dify 如何配置。
从零开始的一些说明
如果您已经了解如何配置使用 Pigsty,可以略过本节。
从零安装 Pigsty 需要 准备 一台符合要求的机器节点: Linux / x86_64,静态 IP,使用带有免密 sudo
权限的用户,执行以下命令:
curl -fsSL https://repo.pigsty.cc/get | bash
然后依次完成以下步骤:
cd ~/pigsty # 下载源码包解压后进入 Pigsty 源码目录,完成后续 准备、配置、安装 三个步骤
./bootstrap # 【可选项】用于确保 Ansible 正常安装,如果 /tmp/pkg.tgz 离线包则使用它
./configure # 【可选项】执行环境检测,并生成相应的推荐配置文件,如果知道如何配置可以跳过
# …… 这里请修改自动生成的配置 pigsty.yml ,将上面的集群定义填入 all.children 部分内
./install.yml # 根据生成的配置文件开始在当前节点上执行安装,使用离线安装包大概需要10分钟完成
您应当将上面的 PostgreSQL 集群与 Redis 集群定义填入 pigsty.yml
文件中,然后执行 install.yml
完成安装。
Redis安装问题
Pigsty 默认不会安装 Redis,所以您需要使用 redis.yml
剧本显式完成 Redis 安装:
./redis.yml
Docker安装问题
Pigsty 默认不会在当前节点安装 Docker,所以您需要使用 docker.yml
剧本安装 Docker。
./docker.yml
Docker Hub 被墙问题
请注意,对于中国大陆用户来说,Docker Hub 与各镜像站点目前出于封锁状态,需要 “科学上网” 才能拉取 Dify 所需的镜像,您可以考虑 docker save|load
,或者为 Docker Daemon 配置代理。
要为 Docker Daemon 配置代理,您需要在 proxy_env
中指定 http_proxy
与 https_proxy
环境变量,该参数会在 docker_config
任务中被写入 /etc/docker/daemon.json
中:
{
"proxies": {
"http-proxy": "http://192.168.x.x:8118",
"https-proxy": "http://192.168.x.x:8118",
"no-proxy": "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.myqcloud.com,*.tsinghua.edu.cn"
}
}
当然您也可以直接在配置文件中填入您的 HTTP/HTTPS 代理地址,并使用 systemctl restart docker
重启生效。
$ docker compose pull
[+] Pulling 5/5
✔ worker Skipped - Image is already being pulled by api
✔ web Pulled
✔ api Pulled
✔ ssrf_proxy Pulled
✔ nginx Pulled
配置代理后,镜像都可以成功拉取了。当然您也可以使用其他可用的镜像站点,例如 quay.io 等。
Dify的配置工作
Dify 的配置参数一如往常地放在 .env
文件中,内容如下所示:
所有参数都顾名思义,已经填入了在 Pigsty默认沙箱环境 中可以直接工作的默认值。
数据库连接信息请根据您的真实配置,与上面 PG / Redis 集群配置保持一致即可。
我们建议你随便改一下这个 SECRET_KEY
字段,可以使用 openssl rand -base64 42
生成一个强密钥。
# meta parameter
DIFY_PORT=8001 # expose dify nginx service with port 8001 by default
LOG_LEVEL=INFO # The log level for the application. Supported values are `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U # A secret key for signing and encryption, gen with `openssl rand -base64 42`
# postgres credential
PG_USERNAME=dbuser_dify
PG_PASSWORD=DBUser.Dify
PG_HOST=10.10.10.10
PG_PORT=5432
PG_DATABASE=dify
# redis credential
REDIS_HOST=10.10.10.10
REDIS_PORT=6379
REDIS_USERNAME=''
REDIS_PASSWORD=redis.dify
# minio/s3 [OPTIONAL] when STORAGE_TYPE=s3
STORAGE_TYPE=local
S3_ENDPOINT='https://sss.pigsty'
S3_BUCKET_NAME='infra'
S3_ACCESS_KEY='dba'
S3_SECRET_KEY='S3User.DBA'
S3_REGION='us-east-1'
填好连接信息后,我们就可以使用 Docker Compose 拉起 Dify 服务了:
cd pigsty/app/dify && make up
使用真实域名与HTTPS
如果你希望使用真实的域名与 HTTPS 证书,你需要在 pigsty.yml
配置文件中,修改:
infra_portal
参数中的dify
域名。- Dify
.env
文件中的NGINX_SERVER_NAME
参数, - 最好指定一个用于接受证书过期通知的邮箱地址
certbot_email
。
从实际操作上,你可以通过简单的 sed
或文本编辑器替换实现:
将 pigsty.
all:
children: # 集群定义
dify: # Dify 分组
vars: # Dify 分组变量
apps: # 应用配置
dify: # Dify 应用定义
conf: # Dify 应用配置
NGINX_SERVER_NAME: dify.pigsty
vars: # 全局参数
#certbot_sign: true # 使用 Certbot 申请免费 HTTPS 证书
certbot_email: your@email.com # 申请证书使用的邮箱,用于接受过期通知,可选
infra_portal: # 配置 Nginx 服务器
dify: # Dify 服务器定义
domain: dify.pigsty # 请在这里替换为你自己的域名!
endpoint: "10.10.10.10:5001" # 请在这里指定 Dify 的 IP 与端口(默认自动配置)
websocket: true # Dify 需要启用 websocket
certbot: dify.pigsty # 指定 Certbot 证书名称
使用以下命令申请 Nginx 证书:
make cert # 申请证书,也可以手动执行 /etc/nginx/sign-cert 脚本
同时,在 Dify Docker .env
配置中,也需要使用新的域名:
all:
执行 app.yml
剧本,重新拉起 Dify 服务即可生效。
./app.yml
当然如果要通过域名访问,你要把自己的域名 dify.pigsty
添加到域名服务器,或者简单地写入:/etc/hosts
或 C:\Windows\System32\drivers\etc\hosts
之类的静态域名解析文件。
然后,你就可以从浏览器中,通过 http://dify.pigsty 访问 Dify IDE 了。
所以,Pigsty 提供的模板中,DIFY_PORT
默认使用了 5001
,并通过宿主机上 Pigsty 部署的 Nginx 转发至此端口。
当然我们也提供选项B,你也可以直接在 /etc/nginx/conf.d/dify.conf
里使用样例配置,直接指向 Dify 的 web
与 api
端口。
文件系统备份
你可以使用 restic
对 Dify 文件系统进行备份,Dify 的数据文件在 /data/dify
目录下,你可以使用以下命令对其进行备份:
export RESTIC_REPOSITORY=/data/backups/dify # 指定 dify 备份目录
export RESTIC_PASSWORD=some-strong-password # 指定备份加密密码
mkdir -p ${RESTIC_REPOSITORY} # 创建 dify 备份目录
restic init
创建 Restic 备份库后,你可以使用以下命令对 Dify 进行备份:
export RESTIC_REPOSITORY=/data/backups/dify # 指定 dify 备份目录
export RESTIC_PASSWORD=some-strong-password # 指定备份加密密码
restic backup /data/dify # 将 /dify 数据目录备份到仓库
restic snapshots # 查看备份快照列表
restic restore -t /data/dify 0b11f778 # 将快照 xxxxxx 恢复到 /data/dify
restic check # 定期检查仓库完整性
另一种更可靠的方式是使用 JuiceFS 将 MinIO 对象存储挂载到 /data/dify
目录下,这样你就可以使用 MinIO/S3 盛放文件状态了。
如果你希望将所有的数据都保存在 PostgreSQL 中,可以考虑使用 JuiceFS 将文件系统数据保存到 PostgreSQL 中:
```bash
METAURL=postgres://dify:difyai123456@:5432/dify_fs
OPTIONS=(
--storage postgres
--bucket :5432/dify_fs
--access-key dify
--secret-key difyai123456
${METAURL}
jfs
)
juicefs format "${OPTIONS[@]}" # 创建一个 PG 文件系统
juicefs mount ${METAURL} /data2 -d # 后台挂载到 /data2 目录
juicefs bench /data2 # 测试性能
juicefs umount /data2 # 停止挂载
参考阅读
update