#!/bin/bash

# GitLab 配置每日备份脚本 (目录模式)
set -e

CONTAINER_NAME="gitlab"
# 获取日期作为文件夹名称 (格式: 2026-04-20)
DATE=$(date +%Y-%m-%d)

# 基础备份目录
BASE_BACKUP_DIR="/mnt/nas/gitlab_backup/gitlab_22/config_backups"
# 目标备份目录
CURRENT_BACKUP_DIR="$BASE_BACKUP_DIR/$DATE"
LOG_FILE="/var/log/gitlab-config-backup.log"

echo "[$DATE] 开始执行每日配置备份..."

# 1. 检查容器状态
if ! docker ps | grep -q "$CONTAINER_NAME"; then
    echo "❌ 错误: GitLab 容器 $CONTAINER_NAME 未运行,无法备份!" | tee -a "$LOG_FILE"
    exit 1
fi

# 2. 如果当天的文件夹已存在,则追加时间戳防止冲突
if [ -d "$CURRENT_BACKUP_DIR" ]; then
    CURRENT_BACKUP_DIR="${CURRENT_BACKUP_DIR}_$(date +%H%M%S)"
fi

mkdir -p "$CURRENT_BACKUP_DIR"

# 3. 使用临时目录中转
TEMP_DIR=$(mktemp -d)
trap 'rm -rf "$TEMP_DIR"' EXIT

# 4. 提取配置
echo "正在从容器中复制 /etc/gitlab ..."
docker cp "$CONTAINER_NAME:/etc/gitlab" "$TEMP_DIR/config_etc"

# 5. 核心文件校验 (secrets 文件不可为空)
if [ ! -s "$TEMP_DIR/config_etc/gitlab-secrets.json" ]; then
    echo "❌ 致命错误: gitlab-secrets.json 校验失败,可能是容器内部路径变更!" | tee -a "$LOG_FILE"
    exit 1
fi

# 6. 记录元数据
docker exec "$CONTAINER_NAME" gitlab-ctl version > "$TEMP_DIR/version.txt" 2>/dev/null || true

# 7. 最终同步
cp -a "$TEMP_DIR/." "$CURRENT_BACKUP_DIR/"

# 8. 校验结果
if [ -d "$CURRENT_BACKUP_DIR/config_etc" ]; then
    SIZE=$(du -sh "$CURRENT_BACKUP_DIR" | cut -f1)
    echo "✅ 备份成功: $CURRENT_BACKUP_DIR (大小: $SIZE)" | tee -a "$LOG_FILE"
else
    echo "❌ 错误: 备份目录同步失败!" | tee -a "$LOG_FILE"
    exit 1
fi

# 9. 自动删除 30 天前的旧备份
# -maxdepth 1: 只在根目录下找
# -type d: 只找目录
# -mtime +30: 超过 30 天
echo "正在清理 15 天前的旧备份..."
find "$BASE_BACKUP_DIR" -maxdepth 1 -type d -name "20*" -mtime +7 -exec rm -rf {} + 2>/dev/null || true

echo "[$DATE] 备份任务结束。"

数据全量备份

#!/bin/bash
# GitLab 数据全量备份脚本 (Database + Repositories)
set -e

CONTAINER_NAME="gitlab"
DATE=$(date +%Y-%m-%d)
NAS_DATA_DIR="/mnt/nas/gitlab_backup/gitlab_22/data_backups/$DATE"
LOG_FILE="/var/log/gitlab-data-backup.log"

echo "[$DATE] 开始执行 GitLab 官方数据备份..."
mkdir -p "$NAS_DATA_DIR"

# 1. 触发官方备份程序 (包含 DB, Repos, Uploads)
# 注意:这会产生一个巨大的 .tar 文件
docker exec "$CONTAINER_NAME" gitlab-backup create

# 2. 找到刚刚生成的备份文件并移动到 NAS
# 官方备份路径通常对应宿主机的某个目录,或者直接用 docker cp
echo "正在将备份包转移至 NAS..."
# 技巧:获取最新生成的一个 .tar 文件
LATEST_BACKUP=$(docker exec "$CONTAINER_NAME" ls -t /var/opt/gitlab/backups/ | grep .tar | head -n 1)

if [ -n "$LATEST_BACKUP" ]; then
    docker cp "$CONTAINER_NAME:/var/opt/gitlab/backups/$LATEST_BACKUP" "$NAS_DATA_DIR/"
    # 转移后建议删除容器内的备份文件,节省空间
    docker exec "$CONTAINER_NAME" rm "/var/opt/gitlab/backups/$LATEST_BACKUP"
    echo "✅ 数据备份成功: $LATEST_BACKUP" | tee -a "$LOG_FILE"
else
    echo "❌ 错误: 未能找到生成的备份文件!" | tee -a "$LOG_FILE"
    exit 1
fi

# 3. 清理 7 天前的数据备份 (数据包很大,建议保留时间比配置短)
find /mnt/nas/gitlab_backup/gitlab_22/data_backups/ -maxdepth 1 -mtime +7 -exec rm -rf {} + 2>/dev/null || true

如何恢复

既然你已经拥有了配置备份(钥匙)和应用数据备份(内容),恢复流程可以分为四个清晰的步骤。

假设你的新服务器目录结构依然保持一致:

  • 配置路径/soft/gitlab/config

  • 数据路径/soft/gitlab/data


第 0 步:准备环境(版本对齐)

这是最关键的一步。从你提供的图片看,你的 GitLab 版本是 17.3.3

在新服务器上启动容器时,镜像标签必须指定为 17.3.3-ce.0。如果版本不一致,数据库迁移会报错,导致恢复失败。


第 1 步:还原配置文件(放置“钥匙”)

在启动 GitLab 之前,先将备份的配置物理放置到宿主机目录。

  1. 将备份的 gitlab.rbgitlab-secrets.json 以及 ssl 文件夹(如果有)拷贝到新服务器的 /soft/gitlab/config/ 目录下。

  2. 特别注意:确保 gitlab-secrets.json 权限正确(通常只有 root 可读写)。


第 2 步:启动全新的 GitLab 容器

使用你之前的 Docker 命令启动容器。由于你已经放好了配置文件,GitLab 会按照这些配置运行,但此时里面是空的。

Bash

# 启动命令示例 (确保版本号 17.3.3)
docker run --detach \
  --name gitlab \
  --restart always \
  --volume /soft/gitlab/config:/etc/gitlab \
  --volume /soft/gitlab/logs:/var/log/gitlab \
  --volume /soft/gitlab/data:/var/opt/gitlab \
  gitlab/gitlab-ce:17.3.3-ce.0

第 3 步:还原应用数据(搬入“家具”)

这是处理你图片中那些 dbrepositories 数据的阶段。GitLab 官方恢复命令需要一个 .tar 格式的压缩包。

  1. 准备备份文件

    如果你图片中是一个文件夹,请确保它已被打包成官方格式的 .tar 文件(通常备份完就是一个 tar 包)。

    将该文件拷贝到宿主机的 /soft/gitlab/data/backups/ 目录下。

  2. 设置权限

    给备份文件赋予 git 用户权限,否则容器内无法读取:

    Bash

    chown 998:998 /soft/gitlab/data/backups/1776670786_2026_04_20_17.3.3_gitlab_backup.tar
  3. 执行恢复命令

    进入容器内部执行以下操作:

    Bash

    # 1. 停止影响数据库的服务
    docker exec -it gitlab gitlab-ctl stop puma
    docker exec -it gitlab gitlab-ctl stop sidekiq
    
    # 2. 执行恢复 (注意:BACKUP 参数只需要写文件名的前缀,即时间戳和版本部分)
    # 例如文件名是 1776670786_2026_04_20_17.3.3_gitlab_backup.tar
    # 则命令如下:
    docker exec -it gitlab gitlab-backup restore BACKUP=1776670786_2026_04_20_17.3.3

    过程中会询问你两次是否确定,输入 yes 即可。


第 4 步:重启并校验

恢复完成后,需要重新启动所有服务并检查状态。

  1. 重启服务

    Bash

    docker exec -it gitlab gitlab-ctl reconfigure
    docker exec -it gitlab gitlab-ctl restart
  2. 检查健康状态

    Bash

    docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true

总结清单:文件到底该放哪?

文件类型 宿主机存放路径 恢复时机
gitlab.rb /soft/gitlab/config/ 启动容器
gitlab-secrets.json /soft/gitlab/config/ 启动容器
ssl/ 证书文件夹 /soft/gitlab/config/ssl/ 启动容器
*.tar 数据备份包 /soft/gitlab/data/backups/ 启动容器,执行 restore 命令前

💡 给专业程序员的贴士:

如果你发现恢复后页面报错 500,通常是由于 /soft/gitlab/config/gitlab-secrets.json 没有被正确还原,或者里面的密钥与恢复的数据库不匹配。只要确保 Secrets 文件17.3.3 版本 这两点不动摇,恢复成功率就是 100%。