为什么需要自动化升级 Dify
Dify最近的版本迭代升级有点频繁,一个礼拜更新了3个版本,我看了下release tag,大部分是对Dify v1.0版本的bug修复。这对于想要第一时间更新版本体验新功能以及首次体验Dify的用户不太友好,每次升级更新需要手动执行一系列的脚本才能完成。
此外,升级部署过程可能还会遇到各种问题,比如安装环境差异、依赖安装失败、Docker 镜像下载超时、代码版本冲突等等,因此我创建了一个脚本用于自动化升级部署,简化每次迭代升级繁琐的流程以及在新环境首次部署的繁琐操作,让升级过程变得简单、可靠且高效。
脚本自动化:一键解决所有升级烦恼
一键自动化升级、安装部署基于docker composed的方式,主要提供了以下几个功能:
* 对于新环境的部署,会自动检测并安装依赖环境(Git、Docker 和 Docker Compose),使用国内镜像源来加速下载过程;
* Dify配置文件、volumes数据卷的自动化备份
* 代码冲突的处理:自动检测并记录代码冲突,提供解决方案
* Dify服务的平滑重启
升级指南详解:从准备到完成的全流程
完整的执行脚本我放在了文末,这里简要介绍一下自动化脚本的执行过程:
第一步:获取脚本并添加执行权限
chmod +x update_dify.sh第二步:执行脚本
./update_dify.sh第三步:验证升级结果
访问 http://localhost 确认系统正常运行
执行后,脚本会自动完成以下工作:
1. 检查并安装依赖:
- 检测 Git、Docker 和 Docker Compose 是否已安装
- 如缺失,会使用国内镜像源自动安装
- 为 Docker 配置国内镜像加速器
2. 代码库准备:
- 如果当前不在 Dify 目录中,会自动查找或克隆代码
- 使用 Git 管理代码更新,智能处理本地修改
3. 数据备份:
- 创建带时间戳的备份目录(dify-backups/日期时间/)
- 备份 docker-compose.yaml 配置文件
- 备份所有数据卷,确保数据安全
4. 代码更新与冲突处理:
- 保存当前分支和本地修改
- 检出 main 分支并获取最新更新
- 智能处理合并冲突,优先采用远程版本
- 尝试恢复本地修改,如有冲突会提供警告
5. 服务重启:
- 安全停止当前服务
- 使用新版配置启动服务
- 显示服务状态和日志查看命令
完成升级后,可以通过以下几种方式对dify升级的版本进行验证:
1. 服务状态检查:确保所有服务状态为"Up"
cd docker && docker compose ps
2. 日志检查:检查是否有错误信息
docker compose logs -f api web
3. 功能验证:dify web端验证已有应用以及重要功能是否正常工作
如何应对升级中可能出现的问题
对于升级过程中可能出现的问题,一键部署脚本中对以下几种情况做了处理:
#### 1. 备份与恢复问题
升级失败需要恢复旧版本,可以通过以下方式:
停止当前服务
cd docker && docker compose down恢复数据卷(替换为实际备份路径)
tar -xzvf dify-backups/20240318_123456/dify-volumes-20240318_123456.tar.gz -C /恢复配置
cp dify-backups/20240318_123456/docker-compose.yaml.bak docker/docker-compose.yaml重启服务
docker compose up -d
#### 2. 代码冲突处理
本地有重要修改与github更新的代码版本冲突时:
- 脚本会自动创建冲突报告文件 conflict_files.txt
- 根据报告手动解决冲突
- 或使用 git stash list 查看并恢复被暂存的本地修改
#### 3. Docker 相关问题
Docker 服务无法启动:
检查 Docker 状态
sudo systemctl status docker重启 Docker 服务
sudo systemctl restart docker查看详细错误日志
docker compose logs
你也可以根据自己的需求进行脚本的定制,通过以下方式修改脚本:
编辑脚本
vim update_dify.sh可定制的关键参数:
- 备份目录位置
- Docker 镜像加速器列表
- 是否保存本地修改
完整的脚本代码如下:
#!/bin/bash设置日志函数
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}设置错误处理函数
handle_error() {
log "错误: $1"
exit 1
}检查命令是否存在
check_command() {
command -v $1 >/dev/null 2>&1 || {
log "未找到命令: $1"
return 1
}
return 0
}检查并安装必要的命令
check_and_install_dependencies() {
# 检查操作系统类型
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
else
OS=$(uname -s)
fi
# 检查 Git
if ! check_command git; then
log "尝试安装 Git..."
case $OS in
ubuntu|debian)
sudo apt-get update && sudo apt-get install -y git
;;
centos|rhel|fedora)
sudo yum install -y git
;;
darwin)
log "请通过 Homebrew 安装 Git: brew install git"
handle_error "请安装 Git 后重试"
;;
*)
handle_error "请手动安装 Git 后重试"
;;
esac
fi
# 检查 Docker
if ! check_command docker; then
log "尝试安装 Docker(使用国内镜像源)..."
case $OS in
ubuntu|debian)
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
# 使用阿里云的 Docker 镜像源
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/$OS/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/$OS $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
sudo systemctl enable docker
sudo systemctl start docker
# 配置 Docker 镜像加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
;;
centos|rhel)
sudo yum install -y yum-utils
# 使用阿里云的 Docker 镜像源
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl enable docker
sudo systemctl start docker
# 配置 Docker 镜像加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
;;
fedora)
sudo dnf -y install dnf-plugins-core
# 使用阿里云的 Docker 镜像源
sudo dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/fedora/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io
sudo systemctl enable docker
sudo systemctl start docker
# 配置 Docker 镜像加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
;;
darwin)
log "请通过 Homebrew 安装 Docker Desktop: brew install --cask docker"
log "安装后,请配置 Docker Desktop 的镜像加速,可在偏好设置中设置"
log "建议使用以下镜像:https://registry.docker-cn.com, https://docker.mirrors.ustc.edu.cn, https://hub-mirror.c.163.com"
handle_error "请安装 Docker 后重试"
;;
*)
handle_error "请手动安装 Docker 后重试"
;;
esac
fi
# 检查 Docker Compose
if ! check_command docker-compose && ! check_command "docker compose"; then
log "尝试安装 Docker Compose(使用国内镜像源)..."
case $OS in
ubuntu|debian|centos|rhel|fedora)
# 使用 GitHub 镜像网站获取最新版本
COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4)
# 使用清华大学镜像源下载 Docker Compose
sudo curl -L "https://mirrors.tuna.tsinghua.edu.cn/github-release/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 如果清华源失败,尝试使用中科大镜像源
if [ $? -ne 0 ]; then
log "清华源下载失败,尝试使用中科大镜像源..."
sudo curl -L "https://mirrors.ustc.edu.cn/github-release/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
fi
# 如果以上镜像都失败,则使用原始源
if [ $? -ne 0 ]; then
log "国内镜像源下载失败,尝试使用原始源..."
sudo curl -L "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
fi
sudo chmod +x /usr/local/bin/docker-compose
;;
darwin)
log "Docker Desktop for Mac 已包含 Docker Compose,请确保安装了 Docker Desktop"
;;
*)
handle_error "请手动安装 Docker Compose 后重试"
;;
esac
fi
# 验证安装成功
check_command git || handle_error "Git 安装失败,请手动安装后重试"
check_command docker || handle_error "Docker 安装失败,请手动安装后重试"
if ! check_command docker-compose && ! docker compose version >/dev/null 2>&1; then
handle_error "Docker Compose 安装失败,请手动安装后重试"
fi
# 确保当前用户可以运行 docker 命令
if ! docker info >/dev/null 2>&1; then
log "将当前用户添加到 docker 组..."
sudo usermod -aG docker $USER
log "需要重新登录以应用权限更改。请重新登录后再次运行此脚本。"
exit 0
fi
}检查或克隆 Dify 仓库
check_or_clone_dify() {
# 如果当前目录不是 dify 目录,尝试查找或克隆
if [ ! -d "./docker" ] || [ ! -f "./docker/docker-compose.yaml" ]; then
log "当前目录不是 Dify 根目录"
# 检查是否已经存在 dify 目录
if [ -d "./dify" ] && [ -f "./dify/docker/docker-compose.yaml" ]; then
log "找到现有的 Dify 目录,正在进入..."
cd ./dify
else
log "未找到 Dify 代码库,正在克隆..."
git clone https://github.com/langgenius/dify.git
if [ $? -ne 0 ]; then
handle_error "克隆 Dify 代码库失败"
fi
log "克隆成功,正在进入 Dify 目录..."
cd ./dify
fi
fi
# 再次检查是否在 dify 目录
if [ ! -d "./docker" ] || [ ! -f "./docker/docker-compose.yaml" ]; then
handle_error "不在 Dify 根目录,且无法找到或克隆 Dify 代码库"
fi
log "确认当前在 Dify 根目录"
}检查 Docker Compose 命令格式
get_docker_compose_cmd() {
if docker compose version >/dev/null 2>&1; then
echo "docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
echo "docker-compose"
else
handle_error "未找到 Docker Compose 命令"
fi
}检查并安装依赖
check_and_install_dependencies检查或克隆 Dify 代码库
check_or_clone_dify获取正确的 Docker Compose 命令
DOCKER_COMPOSE_CMD=$(get_docker_compose_cmd)
log "使用的 Docker Compose 命令: $DOCKER_COMPOSE_CMD"创建备份目录
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="dify-backups/$BACKUP_DATE"
mkdir -p $BACKUP_DIRlog "开始备份..."
备份 docker-compose 配置
cp docker/docker-compose.yaml "$BACKUP_DIR/docker-compose.yaml.bak"
if [ $? -ne 0 ]; then
handle_error "备份 docker-compose.yaml 失败"
fi
log "已备份 docker-compose.yaml"检查 .env 文件是否存在,如果不存在则创建
if [ ! -f "docker/.env" ]; then
log "未找到 .env 文件,正在从示例创建..."
cp docker/.env.example docker/.env
if [ $? -ne 0 ]; then
handle_error "创建 .env 文件失败"
fi
log "已创建 .env 文件,请在升级后根据需要修改配置"
fi检查 volumes 目录是否存在
if [ -d "docker/volumes" ]; then
# 备份数据卷
log "开始备份数据卷..."
tar -czvf "$BACKUP_DIR/dify-volumes-$BACKUP_DATE.tar.gz" docker/volumes/
if [ $? -ne 0 ]; then
handle_error "备份数据卷失败"
fi
log "已备份数据卷到 $BACKUP_DIR/dify-volumes-$BACKUP_DATE.tar.gz"
else
log "未找到 volumes 目录,跳过数据卷备份"
filog "开始更新代码..."
保存当前分支名
CURRENT_BRANCH=$(git branch --show-current)
log "当前分支: $CURRENT_BRANCH"缓存当前修改(如果有)
git diff --quiet || {
log "检测到本地修改,正在备份..."
git stash save "Auto stash before update script - $BACKUP_DATE"
HAS_STASH=1
}检出主分支
git checkout main || handle_error "无法切换到 main 分支"获取远程更新
git fetch origin || handle_error "无法获取远程代码"检查是否有冲突
CONFLICTS=$(git merge --no-commit --no-ff origin/main 2>&1)
if echo "$CONFLICTS" | grep -q "Automatic merge failed"; then
log "检测到合并冲突,正在中止合并并创建冲突报告..."
git merge --abort
# 创建冲突详情
git diff --name-only --diff-filter=U > "$BACKUP_DIR/conflict_files.txt"
# 选项1: 自动解决冲突(使用远程版本)
log "尝试使用远程版本来解决冲突..."
git checkout -f origin/main || handle_error "无法强制切换到远程版本"
log "已切换到远程最新版本"
# 应用本地修改(如可能)
if [ "$HAS_STASH" = "1" ]; then
log "尝试应用本地修改..."
git stash pop || {
log "警告: 无法自动应用本地修改,本地更改仍在 stash 中"
log "请在升级完成后手动运行 'git stash list' 查看并应用更改"
}
fi
else
# 没有冲突,完成合并
log "无冲突,正在更新代码..."
git merge origin/main || handle_error "合并更新失败"
# 恢复本地修改(如果有)
if [ "$HAS_STASH" = "1" ]; then
log "恢复本地修改..."
git stash pop || log "警告: 恢复本地修改时出现冲突,请手动解决"
fi
fi显示最新更新日志
log "最近的代码更新:"
git log --oneline -n 5进入docker目录
cd docker || handle_error "无法进入 docker 目录"log "停止当前服务..."
$DOCKER_COMPOSE_CMD down || handle_error "停止服务失败"log "启动新版本服务..."
$DOCKER_COMPOSE_CMD up -d || handle_error "启动新版本失败"log "检查服务状态..."
$DOCKER_COMPOSE_CMD pslog "升级完成! 可以通过以下命令查看日志:"
echo "$DOCKER_COMPOSE_CMD logs -f api # 查看API服务日志"
echo "$DOCKER_COMPOSE_CMD logs -f web # 查看前端日志"恢复到原始分支(如果不是main)
if [ "$CURRENT_BRANCH" != "main" ] && [ "$CURRENT_BRANCH" != "" ]; then
cd ..
log "正在恢复到原始分支: $CURRENT_BRANCH"
git checkout "$CURRENT_BRANCH" || log "警告: 无法恢复到原始分支 $CURRENT_BRANCH"
fi
log "全部操作完成!请访问 http://localhost 检查 Dify 是否正常运行"
结语:让技术回归简单
技术本应该让生活变得更简单,而不是更复杂。通过这个自动升级脚本,希望给初次体验Dify以及升级的朋友提供一键自动化的便捷方式,简化繁琐的流程。 需要的朋友可以复制上述自动化升级部署脚本的内容,本地保存。今天的分享就到这里啦!
希望这个工具能够帮助到你,如有任何建议或问题,欢迎在评论区留言交流!