gitlab与禅道数据备份策略

我需要备份 gitlab、禅道 数据,到一个新的机器上,新的机器主要用于存储上述服务的数据,请问改用 ftp、nfs、nas、minio,或是其他?是否有更好的选择?请给我一些较好的方案策略

Gitlab、禅道备份存储方案选型与策略

场景说明:现有业务机器运行GitLab、禅道;新增一台独立机器专门存放备份数据,不运行业务,只做备份归档,需要对比 FTP / NFS / NAS / MinIO,给出多套可落地方案,包含优缺点、适用场景、完整备份策略。

核心数据构成(先明确要备份什么)

GitLab

  1. PostgreSQL数据库
  2. Git仓库裸库(repositories)
  3. 上传附件、CI产物、LFS对象
  4. Redis数据、配置文件

GitLab官方备份支持两种:gitlab-backup全量备份包 + 单独备份 /etc/gitlab配置

禅道

  1. MySQL/MariaDB数据库
  2. 附件、截图、文档、上传文件(zentaopms/www/data
  3. 程序配置文件

两类业务都包含:数据库(逻辑备份) + 大量小文件(附件、代码仓库)。备份特点:既有数据库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保证底层磁盘可靠性 ⭐⭐⭐强烈推荐,软件方案最优

补充备选:

  1. Rsync + SSH(SCP):不单独部署存储服务,业务机通过rsync over ssh推送到备份机器目录。简单可靠,适合文件同步,但缺少版本管理。
  2. Restic / BorgBackup:备份工具,后端可以对接:本地目录/NFS/S3‑MinIO,支持去重、加密、快照版本,非常适合这两个系统。

三套落地实施方案(按推荐优先级排序)

方案A:MinIO(S3对象存储)【软件最优,推荐】

架构

新备份机器部署MinIO,底层磁盘建议配置RAID1/RAID5(防止单盘损坏丢失备份)。

  • GitLab:原生支持直接备份输出到S3(MinIO),不需要中转本地磁盘。
  • 禅道:本地生成mysqldump、打包附件,通过mc(minio客户端)上传到MinIO桶。

优势

  1. GitLab官方原生支持S3备份,无需中转磁盘,简化脚本。
  2. 开启对象版本、对象锁:防止备份被误删、覆盖,具备防勒索能力。
  3. 生命周期规则:自动清理N天前旧备份,自动管理备份轮转,不用自己写复杂删除脚本。
  4. 备份文件自带md5校验,可校验备份完整性。
  5. 后续可扩展:以后Velero、其他业务备份也可以复用这套MinIO。

关键配置策略

  1. MinIO底层磁盘必须做RAID,MinIO本身不做磁盘冗余!
  2. 建立两个bucket:gitlab‑backupzentao‑backup;开启版本、对象锁。
  3. GitLab修改gitlab.rb开启S3备份,直接把备份写入minio。
  4. 禅道脚本流程:
    1. mysqldump导出数据库
    2. tar打包禅道data附件目录
    3. mc cp上传备份包到minio桶
  5. 保留策略:每日全量备份,保留30天;月度备份永久留存。
  6. 额外要求:定期执行备份恢复演练,验证备份包可用。

缺点:需要维护MinIO服务;海量KB级小文件会消耗元数据,可适当打包再上传。

方案B:NFS挂载 + Restic备份(轻量内网方案)

架构

备份服务器配置NFS服务,业务机器挂载NFS目录;使用restic备份工具把GitLab、禅道数据备份到NFS存储。

不建议直接裸写文件到NFS,搭配restic实现:快照、去重、加密、版本管理。

流程

  1. 业务机挂载备份机NFS共享目录。
  2. GitLab:执行gitlab‑backup,输出到本地,restic推送至NFS。
  3. 禅道:mysqldump + tar打包附件,restic做快照存入NFS。

优点

部署简单,没有额外对象存储组件;restic自动去重,节省磁盘空间;支持加密。

风险规避

  1. NFS增加软挂载参数 soft,retry=2,避免备份服务器宕机导致业务机进程卡死。
  2. 禁止业务程序读写NFS,NFS只做备份写入,业务全部跑本地磁盘。
  3. NFS本身没有快照,快照由restic提供。

适用场景:机器配置比较弱,不想维护MinIO,纯内网环境。

方案C:成品NAS硬件方案(运维最简单,企业优选)

架构

采购一台NAS(群晖/威联通),开启NFS + S3兼容接口。

  • GitLab:直接S3写入NAS的S3接口。
  • 禅道:NFS挂载,存放备份包。
    NAS自带RAID、硬盘预警、快照、Web管理界面。

优点:不用维护应用服务,磁盘故障告警,快照一键配置。
缺点:硬件成本高。

❌不推荐主备份使用FTP

FTP只适合临时中转。没有完整性校验,传输中断容易产生损坏备份,没有版本保护。


GitLab + 禅道通用备份最佳实践策略(无论选哪个存储都要遵守)

  1. 数据库优先逻辑备份
    • GitLab:使用官方gitlab‑backup‑create,不要直接拷贝数据库文件。
    • 禅道:使用mysqldump导出,不要直接拷贝data目录。
  2. 两份备份原则

    条件允许,重要数据建议:一份存本方案独立备份机;另外一份异地离线备份。

  3. 备份后必须校验
    • GitLab:定期测试 gitlab‑backup‑restore 恢复。
    • 禅道:定期把备份包拉到测试机器,完整恢复,验证页面、附件正常。
  4. 备份轮转策略参考
    • 每日全量备份,保留30天;
    • 每个月1号做月度备份,永久保存;
    • 旧备份由存储层生命周期自动清理,不要手动乱删。
  5. 禁止备份和业务同一台机器(你现在架构已经做到,新机器专门存备份)
  6. 权限:备份存储账号最小权限,只允许写入备份,禁止删除权限(对象锁)。
  7. 监控告警:备份脚本执行失败,发送邮件/告警通知,不能只靠脚本默默跑。

选型快速决策

  1. 如果你的服务器是x86 Linux,希望软件方案,兼顾GitLab原生S3、以后还要给Velero等其他业务做备份 → 选MinIO(方案A)
  2. 机器配置低,不想维护对象存储,纯内网环境 → NFS + restic(方案B)
  3. 预算充足,不想维护软件服务,想要硬件开箱运维 → NAS硬件(方案C)

禅道+GitLab对接MinIO的shell备份脚本模板

禅道 + GitLab 对接 MinIO 的 shell 备份脚本模板 参考如下:

环境说明

  1. 备份机器部署 MinIO,业务机器安装 mc minio客户端,业务机可以访问 MinIO服务
  2. GitLab 使用官方 omnibus 安装;禅道使用 MySQL,部署在同一台业务主机
  3. 预先在MinIO创建2个桶:gitlab-backupzentao-backup,建议开启对象版本、对象锁防止误删
  4. mc 已经完成配置:mc alias set minio http://minio-ip:9000 ACCESS_KEY SECRET_KEY
  5. 脚本执行用户具备 gitlab、mysql、tar 相关权限;建议放入crontab定时执行
  6. 脚本会生成本地临时备份,上传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

使用部署步骤

  1. 将脚本保存为 gitlab_zentao_backup.sh
  2. 修改脚本顶部配置项:minio别名、禅道mysql账号密码、路径
  3. 赋予执行权限:
chmod +x gitlab_zentao_backup.sh
  1. 测试手动运行:
./gitlab_zentao_backup.sh
  1. 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恢复

  1. 将minio上备份包下载到 /var/opt/gitlab/backups
  2. gitlab-backup restore BACKUP=时间戳
  3. 恢复gitlab.rb、gitlab-secrets.json配置文件

禅道恢复

  1. 下载minio中zentao_full_xxx.tar.gz解压
  2. mysql导入sql文件
  3. 覆盖还原 www/data 附件目录

重要注意事项

  1. MinIO底层磁盘务必做RAID,MinIO本身不提供磁盘冗余,磁盘损坏会丢失备份。
  2. 开启桶的对象锁(legal hold),防止备份被误删除、勒索病毒篡改。
  3. 定期做恢复演练,只备份不恢复演练等于没有备份。
  4. mysql密码写脚本有安全风险,生产环境可以改用 .my.cnf 免密配置,避免明文密码。
  5. 如果gitlab备份时间很长,注意crontab错开业务高峰。
  6. 脚本中set -euo pipefail遇到错误直接退出,防止生成损坏备份上传MinIO。

MinIO桶完整生命周期mc配置命令

补充一份免明文mysql密码的优化版本,以及MinIO桶完整生命周期mc配置命令。

MinIO mc 桶生命周期完整配置命令

业务场景:

  1. gitlab‑backupzentao‑backup两个备份桶
  2. 日常自动备份:保留30天自动删除
  3. 每月1号月度归档备份:永久保存,不会被生命周期删除(通过标签过滤)
  4. 同时包含:版本删除、过期清理、非当前版本过期(开启对象版本场景)
    前提:已经配置好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号备份完成,自动执行上面打标签命令,其余日期不打标签。

第三步:生命周期规则

规则逻辑:

  1. 不带标签 backup_type=monthly 的对象,30天后自动过期删除(日常每日备份)
  2. 带 backup_type=monthly 的对象,跳过本条规则,永久留存
  3. 如果开启版本,旧版本对象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

重要注意事项

  1. --tag "backup_type!=monthly" 条件:只有不包含该标签的对象才会30天过期;打上monthly标签的对象完全不受这条规则约束,永久保留
  2. 对象锁开启后,月度归档备份想要手动删除,必须先解除合规保留,才能删除。
  3. 生命周期是MinIO服务端异步执行,不是到点立刻删除,一般会有0‑24小时延迟,属于正常现象。
  4. 不要使用shell脚本遍历删除MinIO备份,优先使用ilm生命周期,避免脚本漏删、误删。
  5. 如果你的业务不需要永久月度归档,可以去掉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
posted @ 2026-08-31 16:09  念槐聚  阅读(3)  评论(0)    收藏  举报