本文目录导读:

“回滚脚本”的写法取决于你具体使用的技术栈和场景(数据库、应用部署、Kubernetes 等),下面分最常见的数据库回滚和应用版本回滚两种情况说明。
数据库回滚脚本(最常用)
通常采用“版本化迁移”工具(如 Flyway、Liquibase、MyBatis Migrations),但纯 SQL 脚本也常用。
单次变更的回滚(纯 SQL 示例)
假设你执行了一个 V1.1__add_user_email.sql 的升级脚本:
-- 升级(正向) ALTER TABLE users ADD COLUMN email VARCHAR(255) NOT NULL DEFAULT ''; CREATE INDEX idx_user_email ON users(email);
对应的回滚脚本(通常命名为 V1.1__add_user_email__rollback.sql):
-- 回滚(逆向) DROP INDEX IF EXISTS idx_user_email; ALTER TABLE users DROP COLUMN IF EXISTS email;
Flyway / Liquibase 自动化回滚
- Flyway:
flyway undo命令,需要 Flyway Teams 版(付费),或手动执行回滚 SQL。 - Liquibase: 支持
rollback标签,在 changelog 中定义回滚语句:<changeSet id="1" author="me"> <createTable tableName="test"> <column name="id" type="int"/> </createTable> <rollback> DROP TABLE test; </rollback> </changeSet>
手动版本控制(推荐方式)
建立一个 migrations 目录,每个变更包含正向和回滚两个文件:
migrations/
├── V1.0__init.sql
├── V1.0__init__rollback.sql
├── V1.1__add_email.sql
├── V1.1__add_email__rollback.sql
执行时记录当前版本,回滚时找到对应版本的文件执行。
应用代码回滚脚本(部署回滚)
基于 Git 的回滚脚本(shell)
适用于代码级别回滚:
#!/bin/bash
# rollback.sh - 回滚到上一个版本
set -e
APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/deploys/backups"
# 1. 停止当前服务
systemctl stop myapp.service
# 2. 备份当前版本(可选)
cp -r "$APP_DIR" "${BACKUP_DIR}/$(date +%Y%m%d_%H%M%S)_before_rollback"
# 3. Git 回滚
cd "$APP_DIR"
git checkout --force HEAD~1 # 回退到上一个提交
# 或者指定 tag: git checkout v1.0.5
# 4. 重新构建(如果需要)
npm install && npm run build
# 或 mvn clean package
# 5. 重启服务
systemctl start myapp.service
echo "回滚完成,当前版本: $(git log --oneline -1)"
Docker 镜像版本回滚脚本
假设使用 myapp:2.0.1 回滚到 myapp:2.0.0:
#!/bin/bash
# docker_rollback.sh
OLD_TAG="$1" # 2.0.0
CONTAINER_NAME="myapp"
# 拉取旧镜像
docker pull myapp:${OLD_TAG}
# 停止并删除当前容器
docker stop ${CONTAINER_NAME}
docker rm ${CONTAINER_NAME}
# 使用旧镜像启动
docker run -d --name ${CONTAINER_NAME} \
-p 8080:8080 \
-v /opt/config:/config \
myapp:${OLD_TAG}
echo "应用已回滚至版本: ${OLD_TAG}"
Kubernetes 回滚脚本
使用 kubectl rollout undo(最简单)
#!/bin/bash
# k8s_rollback.sh
DEPLOYMENT_NAME="myapp-deployment"
NAMESPACE="default"
# 回滚到上一个版本
kubectl rollout undo deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE}
# 或回滚到指定版本
# kubectl rollout undo deployment/${DEPLOYMENT_NAME} --to-revision=3
# 查看回滚状态
kubectl rollout status deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE}
Helm 回滚
#!/bin/bash helm rollback myapp 1 # 回滚到 revision 1 # 或回滚到上一个版本 # helm rollback myapp
通用回滚脚本框架(推荐结构化)
将升级和回滚做成可逆操作对:
#!/bin/bash
# migrate.sh - 通用迁移脚本
ACTION=${1:-upgrade} # upgrade / rollback
case $ACTION in
upgrade)
echo "=== 执行升级 ==="
# 步骤1: 备份
cp config.yml config.yml.bak
# 步骤2: 修改
sed -i 's/version: 1/version: 2/' config.yml
# 步骤3: 执行DB变更
mysql -e "ALTER TABLE ..."
;;
rollback)
echo "=== 执行回滚 ==="
# 步骤1: 还原备份
cp config.yml.bak config.yml
# 步骤2: 逆向DB变更
mysql -e "ALTER TABLE ... DROP COLUMN ..."
# 步骤3: 清理备份
rm config.yml.bak
;;
esac
关键原则
| 原则 | 说明 |
|---|---|
| 幂等性 | 回滚脚本可多次执行而不出错(使用 IF EXISTS / DROP IF EXISTS) |
| 版本追踪 | 记录当前版本号,避免重复回滚 |
| 备份优先 | 任何变更前先备份数据或配置 |
| 原子性 | 脚本失败时要能回退到一致状态(考虑事务) |
| 测试 | 在预发环境验证回滚脚本再上生产 |
一个具体的建议:不用自己造轮子,直接用成熟的工具:
- 数据库:Flyway / Liquibase
- 应用部署:Ci/CD 工具(Jenkins/GitLab CI)配合 Git tag 回滚
- 容器/K8s:Helm / ArgoCD(支持自动回滚)
这样回滚脚本(或命令)通常就只有一行,由工具管理版本。