gitlab与禅道数据备份策略
我需要备份 gitlab、禅道 数据,到一个新的机器上,新的机器主要用于存储上述服务的数据,请问改用 ftp、nfs、nas、minio,或是其他?是否有更好的选择?请给我一些较好的方案策略
Gitlab、禅道备份存储方案选型与策略
场景说明:现有业务机器运行GitLab、禅道;新增一台独立机器专门存放备份数据,不运行业务,只做备份归档,需要对比 FTP / NFS / NAS / MinIO,给出多套可落地方案,包含优缺点、适用场景、完整备份策略。
核心数据构成(先明确要备份什么)
GitLab
- PostgreSQL数据库
- Git仓库裸库(repositories)
- 上传附件、CI产物、LFS对象
- Redis数据、配置文件
GitLab官方备份支持两种:
gitlab-backup全量备份包 + 单独备份/etc/gitlab配置
禅道
- MySQL/MariaDB数据库
- 附件、截图、文档、上传文件(
zentaopms/www/data) - 程序配置文件
两类业务都包含:数据库(逻辑备份) + 大量小文件(附件、代码仓库)。备份特点:既有数据库dump,又有海量小文件;需要可靠存储、支持版本留存、防误删。
各存储介质对比(目标:独立备份服务器)
| 方案 | 实现方式 | 优点 | 缺点 | 是否适合本场景 |
|---|---|---|---|---|
| FTP | 备份服务器搭建vsftpd,业务机ftp上传备份包 | 部署简单;跨网络可用 | 无锁、无版本;小文件性能差;无校验;容易断传;没有快照,不推荐生产备份 | ❌不建议作为主备份,仅可做临时中转 |
| NFS | 备份机器开启NFS服务,业务机挂载远程目录到本地,备份直接写挂载点 | Linux原生,配置简单;读写性能好;直接本地路径写入,脚本好写;适合大量小文件 | 网络故障会导致业务机挂载卡死风险;本身不提供版本、快照、防误删,需要额外做快照;无Web管理;仅内网使用 | ✅适合内网,作为基础存储层,需要叠加备份轮转脚本 |
| NAS设备 | 成品NAS(群晖/威联通),支持NFS/SMB/S3 | 自带快照、RAID、硬盘故障容错、WebUI;权限管理;开箱即用 | 硬件成本高;自定义脚本灵活性弱;如果是x86 NAS也可以跑额外服务 | ✅企业首选,硬件一体化备份存储 |
| MinIO(S3兼容对象存储) | 在新备份机器部署MinIO服务,提供S3 API | 支持对象版本、对象锁、生命周期(自动清理旧备份);GitLab原生直接支持S3备份;支持校验、断点续传;支持内网/外网访问;可配套rsync做本地副本;方便对接velero等工具 | 需要维护MinIO服务;小文件会有少量开销;需要做磁盘RAID保证底层磁盘可靠性 | ⭐⭐⭐强烈推荐,软件方案最优 |
补充备选:
- Rsync + SSH(SCP):不单独部署存储服务,业务机通过rsync over ssh推送到备份机器目录。简单可靠,适合文件同步,但缺少版本管理。
- Restic / BorgBackup:备份工具,后端可以对接:本地目录/NFS/S3‑MinIO,支持去重、加密、快照版本,非常适合这两个系统。
三套落地实施方案(按推荐优先级排序)
方案A:MinIO(S3对象存储)【软件最优,推荐】
架构
新备份机器部署MinIO,底层磁盘建议配置RAID1/RAID5(防止单盘损坏丢失备份)。
- GitLab:原生支持直接备份输出到S3(MinIO),不需要中转本地磁盘。
- 禅道:本地生成mysqldump、打包附件,通过
mc(minio客户端)上传到MinIO桶。
优势
- GitLab官方原生支持S3备份,无需中转磁盘,简化脚本。
- 开启对象版本、对象锁:防止备份被误删、覆盖,具备防勒索能力。
- 生命周期规则:自动清理N天前旧备份,自动管理备份轮转,不用自己写复杂删除脚本。
- 备份文件自带md5校验,可校验备份完整性。
- 后续可扩展:以后Velero、其他业务备份也可以复用这套MinIO。
关键配置策略
- MinIO底层磁盘必须做RAID,MinIO本身不做磁盘冗余!
- 建立两个bucket:
gitlab‑backup、zentao‑backup;开启版本、对象锁。 - GitLab修改
gitlab.rb开启S3备份,直接把备份写入minio。 - 禅道脚本流程:
- mysqldump导出数据库
- tar打包禅道data附件目录
- mc cp上传备份包到minio桶
- 保留策略:每日全量备份,保留30天;月度备份永久留存。
- 额外要求:定期执行备份恢复演练,验证备份包可用。
缺点:需要维护MinIO服务;海量KB级小文件会消耗元数据,可适当打包再上传。
方案B:NFS挂载 + Restic备份(轻量内网方案)
架构
备份服务器配置NFS服务,业务机器挂载NFS目录;使用restic备份工具把GitLab、禅道数据备份到NFS存储。
不建议直接裸写文件到NFS,搭配restic实现:快照、去重、加密、版本管理。
流程
- 业务机挂载备份机NFS共享目录。
- GitLab:执行gitlab‑backup,输出到本地,restic推送至NFS。
- 禅道:mysqldump + tar打包附件,restic做快照存入NFS。
优点
部署简单,没有额外对象存储组件;restic自动去重,节省磁盘空间;支持加密。
风险规避
- NFS增加软挂载参数
soft,retry=2,避免备份服务器宕机导致业务机进程卡死。 - 禁止业务程序读写NFS,NFS只做备份写入,业务全部跑本地磁盘。
- NFS本身没有快照,快照由restic提供。
适用场景:机器配置比较弱,不想维护MinIO,纯内网环境。
方案C:成品NAS硬件方案(运维最简单,企业优选)
架构
采购一台NAS(群晖/威联通),开启NFS + S3兼容接口。
- GitLab:直接S3写入NAS的S3接口。
- 禅道:NFS挂载,存放备份包。
NAS自带RAID、硬盘预警、快照、Web管理界面。
优点:不用维护应用服务,磁盘故障告警,快照一键配置。
缺点:硬件成本高。
❌不推荐主备份使用FTP
FTP只适合临时中转。没有完整性校验,传输中断容易产生损坏备份,没有版本保护。
GitLab + 禅道通用备份最佳实践策略(无论选哪个存储都要遵守)
- 数据库优先逻辑备份
- GitLab:使用官方
gitlab‑backup‑create,不要直接拷贝数据库文件。 - 禅道:使用
mysqldump导出,不要直接拷贝data目录。
- GitLab:使用官方
- 两份备份原则
条件允许,重要数据建议:一份存本方案独立备份机;另外一份异地离线备份。
- 备份后必须校验
- GitLab:定期测试
gitlab‑backup‑restore恢复。 - 禅道:定期把备份包拉到测试机器,完整恢复,验证页面、附件正常。
- GitLab:定期测试
- 备份轮转策略参考
- 每日全量备份,保留30天;
- 每个月1号做月度备份,永久保存;
- 旧备份由存储层生命周期自动清理,不要手动乱删。
- 禁止备份和业务同一台机器(你现在架构已经做到,新机器专门存备份)
- 权限:备份存储账号最小权限,只允许写入备份,禁止删除权限(对象锁)。
- 监控告警:备份脚本执行失败,发送邮件/告警通知,不能只靠脚本默默跑。
选型快速决策
- 如果你的服务器是x86 Linux,希望软件方案,兼顾GitLab原生S3、以后还要给Velero等其他业务做备份 → 选MinIO(方案A)
- 机器配置低,不想维护对象存储,纯内网环境 → NFS + restic(方案B)
- 预算充足,不想维护软件服务,想要硬件开箱运维 → NAS硬件(方案C)
禅道+GitLab对接MinIO的shell备份脚本模板
禅道 + GitLab 对接 MinIO 的 shell 备份脚本模板 参考如下:
环境说明
- 备份机器部署 MinIO,业务机器安装
mcminio客户端,业务机可以访问 MinIO服务- GitLab 使用官方 omnibus 安装;禅道使用 MySQL,部署在同一台业务主机
- 预先在MinIO创建2个桶:
gitlab-backup、zentao-backup,建议开启对象版本、对象锁防止误删- mc 已经完成配置:
mc alias set minio http://minio-ip:9000 ACCESS_KEY SECRET_KEY- 脚本执行用户具备 gitlab、mysql、tar 相关权限;建议放入crontab定时执行
- 脚本会生成本地临时备份,上传MinIO之后自动清理本地临时文件;增加简单日志、错误告警预留位
#!/bin/bash
set -euo pipefail
##############################################################################
# 配置项,请根据实际环境修改
##############################################################################
# MinIO mc别名
MINIO_ALIAS="minio"
GITLAB_BUCKET="gitlab-backup"
ZENTAO_BUCKET="zentao-backup"
# GitLab配置 omnibus版本
GITLAB_BACKUP_DIR="/var/opt/gitlab/backups"
GITLAB_CONFIG_DIR="/etc/gitlab"
GITLAB_BACKUP_RETENTION_LOCAL=0 # 本地不保留gitlab备份,上传minio后删除
# 禅道配置
ZENTAO_PATH="/opt/zentaopms" # 禅道程序根目录
ZENTAO_MYSQL_HOST="127.0.0.1"
ZENTAO_MYSQL_PORT="3306"
ZENTAO_MYSQL_USER="root"
ZENTAO_MYSQL_PASS="YourMysqlPasswd"
ZENTAO_MYSQL_DB="zentao"
# 本地临时目录
TMP_BACKUP_DIR="/data/tmp_backup"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/gitlab_zentao_backup.log"
# 告警通知(这里预留,可替换为钉钉/企业微信webhook)
ALERT_WEBHOOK=""
##############################################################################
# 日志函数
##############################################################################
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
alert_fail() {
local msg="$1"
log "ERROR: ${msg}"
if [[ -n "${ALERT_WEBHOOK}" ]];then
curl -s -X POST "${ALERT_WEBHOOK}" -d "{\"msg\":\"备份失败:${msg}\"}" >/dev/null 2>&1
fi
}
##############################################################################
# 初始化临时目录
##############################################################################
mkdir -p "${TMP_BACKUP_DIR}"
clean_tmp(){
log "清理临时目录 ${TMP_BACKUP_DIR}"
rm -rf "${TMP_BACKUP_DIR:?}"/*
}
##############################################################################
# 1.GitLab备份:官方备份 + 配置文件,上传MinIO
##############################################################################
backup_gitlab(){
log "===== 开始执行 GitLab 备份 ====="
clean_tmp
# 1.执行gitlab官方备份 omnibus
gitlab-backup create BACKUP="${DATE}" CRON=1
if [ $? -ne 0 ];then
alert_fail "GitLab gitlab-backup create执行失败"
exit 1
fi
# 2.备份gitlab配置文件 gitlab-secrets.json gitlab.rb
GITLAB_CONFIG_TMP="${TMP_BACKUP_DIR}/gitlab-config-${DATE}.tar.gz"
tar -czf "${GITLAB_CONFIG_TMP}" \
"${GITLAB_CONFIG_DIR}/gitlab.rb" \
"${GITLAB_CONFIG_DIR}/gitlab-secrets.json"
# 3.获取生成的备份包
GITLAB_BACKUP_FILE=$(ls -1 ${GITLAB_BACKUP_DIR}/${DATE}_gitlab_backup.tar)
# 4.上传备份包到minio
log "上传GitLab业务备份包 ${GITLAB_BACKUP_FILE} 到 ${MINIO_ALIAS}/${GITLAB_BUCKET}"
mc cp "${GITLAB_BACKUP_FILE}" "${MINIO_ALIAS}/${GITLAB_BUCKET}/gitlab-backup/"
log "上传GitLab配置文件 ${GITLAB_CONFIG_TMP}"
mc cp "${GITLAB_CONFIG_TMP}" "${MINIO_ALIAS}/${GITLAB_BUCKET}/gitlab-config/"
# 清理本地gitlab备份
rm -f "${GITLAB_BACKUP_FILE}"
log "===== GitLab备份完成 ====="
}
##############################################################################
# 2.禅道备份:mysql dump + 附件data目录打包,上传MinIO
##############################################################################
backup_zentao(){
log "===== 开始执行禅道备份 ====="
clean_tmp
ZENTAO_DUMP="${TMP_BACKUP_DIR}/zentao_db_${DATE}.sql"
ZENTAO_ARCHIVE="${TMP_BACKUP_DIR}/zentao_full_${DATE}.tar.gz"
# 1.mysql逻辑备份
log "导出禅道MySQL数据库"
mysqldump -h${ZENTAO_MYSQL_HOST} -P${ZENTAO_MYSQL_PORT} -u${ZENTAO_MYSQL_USER} -p${ZENTAO_MYSQL_PASS} \
--single-transaction --routines --triggers ${ZENTAO_MYSQL_DB} > "${ZENTAO_DUMP}"
if [ $? -ne 0 ];then
alert_fail "禅道mysqldump数据库导出失败"
exit 1
fi
# 2.打包数据库+禅道data附件目录(www/data是附件、截图、上传文件)
log "打包禅道数据库与附件目录"
tar -czf "${ZENTAO_ARCHIVE}" \
-C "${TMP_BACKUP_DIR}" "$(basename ${ZENTAO_DUMP})" \
-C "${ZENTAO_PATH}" www/data
# 3.上传到minio
log "上传禅道完整备份包 ${ZENTAO_ARCHIVE} 到 ${MINIO_ALIAS}/${ZENTAO_BUCKET}"
mc cp "${ZENTAO_ARCHIVE}" "${MINIO_ALIAS}/${ZENTAO_BUCKET}/"
log "===== 禅道备份完成 ====="
}
##############################################################################
# 主流程
##############################################################################
main(){
log ">>>>>>>>>> 启动GitLab+禅道联合备份任务 <<<<<<<<<<"
backup_gitlab
backup_zentao
clean_tmp
log ">>>>>>>>>> 全部备份任务执行完成 <<<<<<<<<<"
}
# 捕获异常
trap 'alert_fail "脚本异常中断";exit 1' ERR
main
使用部署步骤
- 将脚本保存为
gitlab_zentao_backup.sh - 修改脚本顶部配置项:minio别名、禅道mysql账号密码、路径
- 赋予执行权限:
chmod +x gitlab_zentao_backup.sh
- 测试手动运行:
./gitlab_zentao_backup.sh
- crontab定时示例,每天凌晨2点执行备份
0 2 * * * /opt/scripts/gitlab_zentao_backup.sh >> /var/log/gitlab_zentao_backup_cron.log 2>&1
MinIO生命周期配置(重要,自动清理旧备份,无需脚本删除)
不要写shell脚本删除旧备份,使用MinIO桶生命周期策略,更安全。
- gitlab‑backup桶:
- 普通每日备份:30天后自动删除
- 每月1号的月度备份打上标签,设置永久保留
- zentao‑backup桶:
- 日常备份保留30天,月度标记永久留存
mc命令示例设置生命周期,你可以替换时间:
# 示例:30天过期删除,根据实际业务调整
mc ilm rule add minio/gitlab-backup --expire-days 30
mc ilm rule add minio/zentao-backup --expire-days 30
恢复简要提示(备忘,非脚本)
GitLab恢复
- 将minio上备份包下载到
/var/opt/gitlab/backups gitlab-backup restore BACKUP=时间戳- 恢复gitlab.rb、gitlab-secrets.json配置文件
禅道恢复
- 下载minio中zentao_full_xxx.tar.gz解压
- mysql导入sql文件
- 覆盖还原 www/data 附件目录
重要注意事项
- MinIO底层磁盘务必做RAID,MinIO本身不提供磁盘冗余,磁盘损坏会丢失备份。
- 开启桶的对象锁(legal hold),防止备份被误删除、勒索病毒篡改。
- 定期做恢复演练,只备份不恢复演练等于没有备份。
- mysql密码写脚本有安全风险,生产环境可以改用
.my.cnf免密配置,避免明文密码。 - 如果gitlab备份时间很长,注意crontab错开业务高峰。
- 脚本中
set -euo pipefail遇到错误直接退出,防止生成损坏备份上传MinIO。
MinIO桶完整生命周期mc配置命令
补充一份免明文mysql密码的优化版本,以及MinIO桶完整生命周期mc配置命令。
MinIO mc 桶生命周期完整配置命令
业务场景:
gitlab‑backup、zentao‑backup两个备份桶- 日常自动备份:保留30天自动删除
- 每月1号月度归档备份:永久保存,不会被生命周期删除(通过标签过滤)
- 同时包含:版本删除、过期清理、非当前版本过期(开启对象版本场景)
前提:已经配置好mc别名,别名叫minio;桶预先开启 版本控制 + 对象锁。
第一步:预先开启桶版本控制 + 对象锁(备份桶必开)
# 开启版本控制
mc version enable minio/gitlab-backup
mc version enable minio/zentao-backup
# 开启对象锁(合规锁,防止误删备份),开启后桶无法关闭
mc retention set minio/gitlab-backup --mode COMPLIANCE --default 0d
mc retention set minio/zentao-backup --mode COMPLIANCE --default 0d
对象锁COMPLIANCE模式:被打上保留的对象,任何账号(包括admin)都不能删除覆盖,适合备份防勒索。
第二步:给月度备份打标签(关键!区分普通备份和永久归档)
当你每月1号执行备份之后,给该批备份打上标签
backup_type=monthly,生命周期会跳过带此标签的对象,不会自动删除。
#示例,给月度gitlab备份打标签
mc tag set minio/gitlab-backup/gitlab-backup/20260801_020000_gitlab_backup.tar "backup_type=monthly"
mc tag set minio/gitlab-backup/gitlab-config/gitlab-config-20260801_020000.tar.gz "backup_type=monthly"
#禅道月度备份打标签示例
mc tag set minio/zentao-backup/zentao_full_20260801_020000.tar.gz "backup_type=monthly"
脚本改造提示:每月1号备份完成,自动执行上面打标签命令,其余日期不打标签。
第三步:生命周期规则
规则逻辑:
- 不带标签 backup_type=monthly 的对象,30天后自动过期删除(日常每日备份)
- 带 backup_type=monthly 的对象,跳过本条规则,永久留存
- 如果开启版本,旧版本对象30天清理;删除标记清理。
gitlab‑backup 桶生命周期完整配置
# 删除已存在全部旧生命周期规则
mc ilm rule rm --all minio/gitlab-backup
# 规则1:非月度标记对象,30天自动过期删除
mc ilm rule add minio/gitlab-backup \
--tag "backup_type!=monthly" \
--expire-days 30
# 规则2:旧版本对象30天后删除(版本控制场景)
mc ilm rule add minio/gitlab-backup \
--noncurrent-expire-days 30
# 规则3:清理残留的删除标记
mc ilm rule add minio/gitlab-backup \
--expire-delete-marker true
zentao‑backup 桶生命周期完整配置
mc ilm rule rm --all minio/zentao-backup
mc ilm rule add minio/zentao-backup \
--tag "backup_type!=monthly" \
--expire-days 30
mc ilm rule add minio/zentao-backup \
--noncurrent-expire-days 30
mc ilm rule add minio/zentao-backup \
--expire-delete-marker true
查看、验证生命周期配置
#查看桶全部生命周期规则
mc ilm list minio/gitlab-backup
mc ilm list minio/zentao-backup
#查看桶版本、锁状态
mc version info minio/gitlab-backup
mc retention info minio/gitlab-backup
常用辅助命令
手动删除桶内全部对象(谨慎!测试环境用)
# 仅测试环境执行,生产不要执行
mc rm --recursive --dangerous minio/gitlab-backup/
查看桶标签
mc tag list minio/gitlab-backup/gitlab-backup/xxx.tar
集成到备份脚本的片段(每月1号自动打标签)
把下面片段追加到备份脚本末尾,实现每月1号自动给备份打monthly标签
# 判断如果是每月1号,打上永久归档标签
DAY_OF_MONTH=$(date +%d)
if [ "${DAY_OF_MONTH}" = "01" ];then
log "本月1号,该备份标记为月度归档永久保存"
mc tag set "${MINIO_ALIAS}/${GITLAB_BUCKET}/gitlab-backup/${DATE}_gitlab_backup.tar" "backup_type=monthly"
mc tag set "${MINIO_ALIAS}/${GITLAB_BUCKET}/gitlab-config/gitlab-config-${DATE}.tar.gz" "backup_type=monthly"
mc tag set "${MINIO_ALIAS}/${ZENTAO_BUCKET}/zentao_full_${DATE}.tar.gz" "backup_type=monthly"
fi
重要注意事项
--tag "backup_type!=monthly"条件:只有不包含该标签的对象才会30天过期;打上monthly标签的对象完全不受这条规则约束,永久保留。- 对象锁开启后,月度归档备份想要手动删除,必须先解除合规保留,才能删除。
- 生命周期是MinIO服务端异步执行,不是到点立刻删除,一般会有0‑24小时延迟,属于正常现象。
- 不要使用shell脚本遍历删除MinIO备份,优先使用ilm生命周期,避免脚本漏删、误删。
- 如果你的业务不需要永久月度归档,可以去掉tag条件,直接简单设置
--expire‑days 30全部30天过期。
极简版本(不需要月度永久归档,全部备份保留30天)
如果不需要月度归档,直接执行这个,不需要打标签
mc ilm rule rm --all minio/gitlab-backup
mc ilm rule add minio/gitlab-backup --expire-days 30 --noncurrent-expire-days 30 --expire-delete-marker true
mc ilm rule rm --all minio/zentao-backup
mc ilm rule add minio/zentao-backup --expire-days 30 --noncurrent-expire-days 30 --expire-delete-marker true
赠人玫瑰
手留余香
我们曾如此渴望命运的波澜,到最后才发现:人生最曼妙的风景,竟是内心的淡定与从容……我们曾如此期盼外界的认可,到最后才知道:世界是自己的,与他人毫无关系!-杨绛先生
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的【关注我】。

浙公网安备 33010602011771号