Jenkins入门教程(十五):Jenkins备份与恢复

定期备份Jenkins可以防止数据丢失。本文将详细介绍Jenkins的备份策略和恢复方法,包括完整的脚本和操作步骤。

JENKINS_HOME目录结构

# Jenkins所有数据都存储在JENKINS_HOME目录
$ echo $JENKINS_HOME
/var/lib/jenkins

# 目录结构
/var/lib/jenkins/
├── config.xml                 # Jenkins主配置
├── credentials.xml            # 凭据配置(已废弃,使用secrets/)
├── hudson.model.UpdateCenter.xml
├── identity.key.enc           # 实例唯一标识
├── jenkins.telemetry.Correlator.xml
├── nodeMonitors.xml
├── queue.xml                  # 构建队列
├── secret.key                 # 加密密钥
├── secret.key.not-so-secret
├── secrets/                   # 凭据和密钥存储
│   ├── master.key
│   ├── hudson.util.Secret
│   └── credentials.xml
├── users/                     # 用户配置
│   ├── admin_xxx/
│   │   └── config.xml
│   └── developer_xxx/
│       └── config.xml
├── jobs/                      # Job配置和构建历史
│   ├── my-job/
│   │   ├── config.xml         # Job配置
│   │   ├── nextBuildNumber
│   │   └── builds/            # 构建历史
│   │       ├── 1/
│   │       ├── 2/
│   │       └── lastSuccessfulBuild -> 2
│   └── another-job/
├── plugins/                   # 已安装插件
│   ├── git.jpi
│   ├── git/
│   ├── pipeline.jpi
│   └── pipeline/
├── workspace/                 # 工作空间(可重建,通常不备份)
├── logs/                      # 日志文件
├── war/                       # Jenkins WAR解压内容(可重建)
└── updates/                   # 更新信息

# 查看目录大小
$ du -sh /var/lib/jenkins/*
4.0K    config.xml
120M    jobs
450M    plugins
2.5G    workspace
100M    logs

需要备份的内容

# 必须备份
/var/lib/jenkins/config.xml           # 主配置
/var/lib/jenkins/secrets/             # 凭据和密钥(最重要!)
/var/lib/jenkins/users/               # 用户配置
/var/lib/jenkins/jobs/*/config.xml    # Job配置
/var/lib/jenkins/plugins/*.jpi        # 插件文件

# 建议备份
/var/lib/jenkins/nodes/               # Agent节点配置
/var/lib/jenkins/*.xml                # 其他配置文件

# 可选备份(占用空间大)
/var/lib/jenkins/jobs/*/builds/       # 构建历史

# 不需要备份(可重建)
/var/lib/jenkins/workspace/           # 工作空间
/var/lib/jenkins/war/                 # WAR解压内容
/var/lib/jenkins/plugins/*/           # 插件解压内容
/var/lib/jenkins/logs/                # 日志
/var/lib/jenkins/updates/             # 更新信息
/var/lib/jenkins/caches/              # 缓存

手动备份

# 停止Jenkins(确保数据一致性)
sudo systemctl stop jenkins

# 创建完整备份
sudo tar -czvf /backup/jenkins-full-$(date +%Y%m%d).tar.gz \
    --exclude='workspace' \
    --exclude='war' \
    --exclude='caches' \
    --exclude='logs' \
    --exclude='plugins/*/' \
    /var/lib/jenkins/

# 启动Jenkins
sudo systemctl start jenkins

# 查看备份文件
ls -lh /backup/
-rw-r--r-- 1 root root 150M Feb  8 12:00 jenkins-full-20260208.tar.gz

自动备份脚本

#!/bin/bash
# /opt/scripts/jenkins-backup.sh

set -e

# 配置
JENKINS_HOME="/var/lib/jenkins"
BACKUP_DIR="/backup/jenkins"
RETENTION_DAYS=7
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="jenkins-backup-${DATE}.tar.gz"

# 创建备份目录
mkdir -p ${BACKUP_DIR}

echo "=== Jenkins Backup Started: $(date) ==="

# 检查Jenkins状态
if systemctl is-active --quiet jenkins; then
    JENKINS_WAS_RUNNING=true
    echo "Stopping Jenkins for consistent backup..."
    sudo systemctl stop jenkins
    sleep 5
else
    JENKINS_WAS_RUNNING=false
    echo "Jenkins is not running"
fi

# 执行备份
echo "Creating backup: ${BACKUP_FILE}"
tar -czvf ${BACKUP_DIR}/${BACKUP_FILE} \
    --exclude='workspace' \
    --exclude='workspace@*' \
    --exclude='war' \
    --exclude='caches' \
    --exclude='logs' \
    --exclude='plugins/*/' \
    --exclude='*.log' \
    --exclude='*.tmp' \
    -C $(dirname ${JENKINS_HOME}) \
    $(basename ${JENKINS_HOME})

# 重启Jenkins
if [ "$JENKINS_WAS_RUNNING" = true ]; then
    echo "Restarting Jenkins..."
    sudo systemctl start jenkins
fi

# 计算备份大小
BACKUP_SIZE=$(du -h ${BACKUP_DIR}/${BACKUP_FILE} | cut -f1)
echo "Backup completed: ${BACKUP_FILE} (${BACKUP_SIZE})"

# 清理旧备份
echo "Cleaning up backups older than ${RETENTION_DAYS} days..."
find ${BACKUP_DIR} -name "jenkins-backup-*.tar.gz" -mtime +${RETENTION_DAYS} -delete

# 列出当前备份
echo "Current backups:"
ls -lh ${BACKUP_DIR}/jenkins-backup-*.tar.gz

echo "=== Jenkins Backup Completed: $(date) ==="

# 可选:上传到远程存储
# aws s3 cp ${BACKUP_DIR}/${BACKUP_FILE} s3://my-bucket/jenkins-backups/
# gsutil cp ${BACKUP_DIR}/${BACKUP_FILE} gs://my-bucket/jenkins-backups/
# 设置执行权限
chmod +x /opt/scripts/jenkins-backup.sh

# 添加到crontab(每天凌晨2点执行)
crontab -e
0 2 * * * /opt/scripts/jenkins-backup.sh >> /var/log/jenkins-backup.log 2>&1

# 测试运行
/opt/scripts/jenkins-backup.sh

使用ThinBackup插件

# 1. 安装ThinBackup插件
# 系统管理 > 插件管理 > 搜索 ThinBackup

# 2. 配置备份
# 系统管理 > ThinBackup > Settings

Backup directory: /backup/jenkins-thinbackup
Backup build results: 勾选(如果需要保留构建历史)
Backup 'userContent': 勾选
Backup next build number file: 勾选
Backup plugins archives: 勾选

# 定时备份
Full backup schedule: H 2 * * 0    # 每周日凌晨2点完整备份
Diff backup schedule: H 2 * * 1-6  # 周一到周六差异备份

Max number of backup sets: 4
Files excluded from backup: *.log, *.tmp, *.old

# 3. 手动触发备份
# 系统管理 > ThinBackup > Backup Now

# 4. 查看备份
$ ls -la /backup/jenkins-thinbackup/
drwxr-xr-x 2 jenkins jenkins 4096 Feb  8 02:00 FULL-2026-02-08_02-00
drwxr-xr-x 2 jenkins jenkins 4096 Feb  7 02:00 DIFF-2026-02-07_02-00
drwxr-xr-x 2 jenkins jenkins 4096 Feb  6 02:00 DIFF-2026-02-06_02-00

恢复Jenkins

完整恢复步骤

#!/bin/bash
# /opt/scripts/jenkins-restore.sh

set -e

BACKUP_FILE=$1

if [ -z "$BACKUP_FILE" ]; then
    echo "Usage: $0 "
    echo "Available backups:"
    ls -lh /backup/jenkins/jenkins-backup-*.tar.gz
    exit 1
fi

if [ ! -f "$BACKUP_FILE" ]; then
    echo "Error: Backup file not found: $BACKUP_FILE"
    exit 1
fi

echo "=== Jenkins Restore Started: $(date) ==="
echo "Restoring from: $BACKUP_FILE"

# 停止Jenkins
echo "Stopping Jenkins..."
sudo systemctl stop jenkins
sleep 5

# 备份当前配置(以防万一)
echo "Backing up current configuration..."
sudo mv /var/lib/jenkins /var/lib/jenkins.old.$(date +%Y%m%d%H%M%S)

# 解压备份
echo "Extracting backup..."
sudo tar -xzvf $BACKUP_FILE -C /var/lib/

# 修复权限
echo "Fixing permissions..."
sudo chown -R jenkins:jenkins /var/lib/jenkins

# 启动Jenkins
echo "Starting Jenkins..."
sudo systemctl start jenkins

# 等待启动
echo "Waiting for Jenkins to start..."
for i in {1..60}; do
    if curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/login | grep -q "200\|403"; then
        echo "Jenkins is up!"
        break
    fi
    echo "Waiting... ($i/60)"
    sleep 5
done

echo "=== Jenkins Restore Completed: $(date) ==="
echo "Please verify Jenkins is working correctly."
echo "Old configuration saved to: /var/lib/jenkins.old.*"

ThinBackup恢复

# 通过界面恢复
# 系统管理 > ThinBackup > Restore

# 选择要恢复的备份日期
# 点击 Restore
# 重启Jenkins

sudo systemctl restart jenkins

Configuration as Code

# 安装Configuration as Code插件 (JCasC)

# 导出当前配置
# 系统管理 > Configuration as Code > View Configuration

# 配置文件示例: /var/lib/jenkins/casc_configs/jenkins.yaml
jenkins:
  systemMessage: "Jenkins configured by JCasC"
  numExecutors: 0
  mode: EXCLUSIVE
  
  securityRealm:
    local:
      allowsSignup: false
      users:
        - id: admin
          password: ${JENKINS_ADMIN_PASSWORD}
  
  authorizationStrategy:
    roleBased:
      roles:
        global:
          - name: admin
            permissions:
              - "Overall/Administer"
            assignments:
              - admin
          - name: developer
            permissions:
              - "Overall/Read"
              - "Job/Build"
              - "Job/Read"
            assignments:
              - developers

  nodes:
    - permanent:
        name: "build-agent-01"
        labelString: "linux docker"
        remoteFS: "/home/jenkins"
        launcher:
          ssh:
            host: "192.168.1.100"
            credentialsId: "ssh-agent-key"

credentials:
  system:
    domainCredentials:
      - credentials:
          - usernamePassword:
              id: "github-token"
              username: "github-user"
              password: "${GITHUB_TOKEN}"
          - basicSSHUserPrivateKey:
              id: "ssh-deploy-key"
              username: "deploy"
              privateKeySource:
                directEntry:
                  privateKey: "${SSH_PRIVATE_KEY}"

tool:
  jdk:
    installations:
      - name: "JDK17"
        home: "/usr/lib/jvm/java-17-openjdk-amd64"
  maven:
    installations:
      - name: "Maven3"
        home: "/usr/share/maven"

# 应用配置
# 系统管理 > Configuration as Code > Apply new configuration

# 或通过环境变量指定配置文件位置
# CASC_JENKINS_CONFIG=/var/lib/jenkins/casc_configs/

灾难恢复测试

# 定期测试恢复流程

# 1. 在测试环境中恢复
docker run -d --name jenkins-test \
    -p 9080:8080 \
    -v /backup/jenkins/jenkins-backup-latest.tar.gz:/backup.tar.gz \
    jenkins/jenkins:lts

# 进入容器恢复
docker exec -it jenkins-test bash
cd /var/jenkins_home
tar -xzvf /backup.tar.gz --strip-components=3

# 2. 验证关键功能
# - 用户能否登录
# - Job配置是否完整
# - 凭据是否可用
# - 插件是否正常
# - 能否成功运行构建

# 3. 记录恢复时间(RTO)
echo "Recovery Time: XX minutes"

备份最佳实践

  • 定期备份:每天至少一次完整备份
  • 异地存储:将备份复制到远程存储(S3、GCS等)
  • 测试恢复:定期验证备份可以成功恢复
  • 保护密钥:secrets目录是最关键的,需要特别保护
  • 版本一致:恢复时使用相同版本的Jenkins
  • 文档化:记录备份和恢复流程

总结

本文详细介绍了Jenkins的备份与恢复方法,包括手动备份、自动化脚本、ThinBackup插件和Configuration as Code。定期备份是保护CI/CD系统的重要措施。

下一篇我们将学习Jenkins共享库开发。

发表回复

后才能评论