标签 backup 下的文章

差不多忙了一天,实现了CentOS上用Shell脚本备份SVN的项目。其实只要svnadmin hotcopy就可以实现svn项目的全量备份,但是想增加log文件,以记录备份是否成功。

一般的备份都不过是三个步骤:1)检查相关文件夹及文件;2)执行备份;3)删除旧的备份文件。

具体的代码如下:

#!/bin/sh
# 获取本文件所在的绝对路径
cd $(dirname $0)
CUR_PATH=$(pwd)
cd - > /dev/null

# 定义用户变量
# 注意:确保TMP_PATH设置为非空! 否则有可能导致根路径下的文件被删除!
# PROJECTS为svn的项目名称的数组
PROJECTS=("project1" "project2")
# SVN_PATH是svn的项目文件的所在路径
SVN_PATH=/opt/svn/projects
# BACKUP_PATH是备份文件的存放路径
BACKUP_PATH=${CUR_PATH}/daily_bak
# TMP_PATH是临时文件的存放路径
TMP_PATH=${CUR_PATH}/tmp
# DATE_STR是当前日期的字符串,备份文件名的组成部分
DATE_STR=$(date +%Y%m%d)

# 初始化相关目录
[ ! -d ${BACKUP_PATH} ] && mkdir ${BACKUP_PATH}
[ ! -d ${TMP_PATH} ] && mkdir ${TMP_PATH}
rm -rf ${TMP_PATH}/*

# 定义log文件
LOG_MSG=("" "[info]" "[warn]" "[error]")
LOG_FILE=${BACKUP_PATH}/svn_bak_log_${DATE_STR}.log
[ -f ${LOG_FILE} ] && rm -f ${LOG_FILE}
touch ${LOG_FILE}

# 函数,把消息记录到log文件的函数
function log()
{
     # $1: 第一个参数,消息类型,正整数,即数组$LOG_MSG的下标
     # $2: 第二个参数,文本,要记录到log文件的消息
     echo "${LOG_MSG[$1]} $2" >> ${LOG_FILE}
}

$(log 1 "Start backup svn $(date +%Y-%m-%d\ %H:%M:%S)")
if [ ! -d ${SVN_PATH} ]; then
    # 如果svn目录不存在,则退出
    $(log 3 "svn path not found: ${SVN_PATH}")
    exit 1
fi

# 执行备份
errInfo=""
for projName in ${PROJECTS[@]};
do
    $(log 0 "")
    $(log 1 "Backup SVN Project: ${projName} $(date +%Y-%m-%d\ %H:%M:%S)")
    bakFile=svn_${projName}_bak_${DATE_STR}.tar.gz
    
    # 复制svn的项目文件
    errInfo=$(svnadmin hotcopy ${SVN_PATH}/${projName} ${TMP_PATH}/${projName}/)
    if [ "$?" != "0" ]; then
        $(log 3 "svn hotcopy failed: ${projName}")
        $(log 0 ${errInfo})
        continue
    fi

    # 若存在同一天备份的文件,则删除
    [ -f ${BACKUP_PATH}/${bakFile} ] && rm -f ${BACKUP_PATH}/${bakFile}

    # 打包压缩备份文件
    cd ${TMP_PATH}
    errInfo=$(tar -zcPf ${BACKUP_PATH}/${bakFile} ${projName}/)
    cd ${CUR_PATH}
    if [ ! -f ${BACKUP_PATH}/${bakFile} ]; then
        $(log 3 "compress backup file failed: ${projName}")
        $(log 0 ${errInfo})
    fi

    # 删除没用的文件
    errInfo=$(rm -rf ${TMP_PATH}/${projName})
    if [ "$?" != "0" ]; then
        $(log 2 "clean files failed: ${projName}")
        $(log 0 ${errInfo})
    fi

    $(log 1 "Backup succeed: ${projName}")
done

# 清除旧的备份,由于是全量备份,所以只保留最新的备份就可以了
# 其中 -mmin 设置为120,即删除两小时前生成的文件,达到保留最新备份的目的
errInfo=$(find ${BACKUP_PATH} -mmin +120 -type f | xargs rm -rf)
if [ "$?" != "0" ]; then
    $(log 2 "clean old backup files failed: ${projName}")
    $(log 0 ${errInfo})
fi

$(log 1 "Backup svn finished")

最后,设置cron,实现自动备份就可以了。

还原备份文件,很简单,也是用svnadmin hotcopy命令,把备份文件复制到svn服务路径下就可以了。

tar -zxPf svn_project1_bak_20150710.tar.gz #解压备份文件
svnadmin hotcopy /backup/path/project1 /new/path/project1

今年4月份,Google drive的接口更新了,导致grive不可用。由于grive的作者已经N久没更新了,于是VPS的日常备份要做修改了。

一开始的方案是换个客户端。找来找去,就只有这个drive项目了:
https://github.com/odeke-em/drive
由于是用go写的,需要装go相关包。感觉很麻烦,于是放弃安装。

最后改为用Dropbox来做同步。优点是可选客户端比Google drive多,且安装方便。缺点就是免费空间小,默认只有2GB,目前还算够用。

Dropbox的Shell脚本客户端,只需要dropbox_uploader.sh文件就够了:
https://github.com/andreafabrizi/Dropbox-Uploader

参考了以下两个教程:
1)自动备份网站并同步到 Dropbox
http://www.lovelucy.info/backup-website-and-sync-to-dropbox.html
2)Linux VPS备份网站数据到Dropbox
https://maoxian.de/2013/01/linux-vps%E5%A4%87%E4%BB%BD%E7%BD%91%E7%AB%99%E6%95%B0%E6%8D%AE%E5%88%B0dropbox/755.html

简单总结一下步骤:
1)下载 dropbox_uploader.sh
2)登录 dropbox.com 并创建一个应用
3)初始化客户端,运行以下命令,并按提示输入App key和App secret,以及相关设置:

./dropbox_uploader.sh info

4)编写备份脚本。其实跟备份到Google drive的脚本差不多。
5)设置自动运行备份脚本,命令是:

crontab -e

备份脚本参考:

#!/bin/bash

# begin settings
# MySQL settings
MYSQL_USER=user #MySQL用于备份数据的用户
MYSQL_PASS=password #用户密码
MYSQL_BIN=/usr/bin
# backup directory and files
CUR_DIR=/opt/backup
TMP_DIR=$CUR_DIR/tmp
BAK_DIR=/opt/dropbox_bak/$(date +%Y%m%d)
BAK_DB_NAME=bak_$(date +"%Y%m%d")_mysql.tar.gz
BAK_FILE_NAME=bak_$(date +%Y%m%d)_file.tar.gz
# delete local backup files 20 days ago
BAK_EXPIRED=/opt/dropbox_bak/$(date -d -20day +"%Y%m%d")
# dropbox client
DROPBOX=$CUR_DIR/dropbox_uploader.sh
DROPBOX_DEL=/$(date -d -30day +%Y%m%d)
# website directory
WEB_DATA="/opt/www/"
# end settings

# Create the directory when not existed
if [ ! -d $BAK_DIR ]; then
    mkdir -p $BAK_DIR
fi
if [ ! -d $TMP_DIR ]; then
    mkdir -p $TMP_DIR
else
    rm -Rf $TMP_DIR/*
fi
cd $TMP_DIR

# begin backup database
DATABASES=`$MYSQL_BIN/mysql -h "127.0.0.1" -u$MYSQL_USER -p$MYSQL_PASS -Bse 'show databases'`

for DB in $DATABASES; do
    # ignore system tables
    if [ "$DB" == "information_schema" -o "$DB" == "performance_schema" -o "$DB" == "mysql" ]; then
        continue
    fi

    # export data to backup file
    $MYSQL_BIN/mysqldump -h "127.0.0.1" -u$MYSQL_USER -p$MYSQL_PASS $DB > $DB.sql
done

# compress and merge all the database backup files
tar zcf $BAK_DB_NAME *.sql
mv -f $BAK_DB_NAME $BAK_DIR/$BAK_DB_NAME
# end backup database

# backup website files
tar zcpf $BAK_FILE_NAME $WEB_DATA
mv -f $BAK_FILE_NAME $BAK_DIR/$BAK_FILE_NAME

# sync files
$DROPBOX upload -s $BAK_DIR /
$DROPBOX delete $DROPBOX_DEL

# delete local old files
rm -Rf $TMP_DIR/*
if [ -d $BAK_EXPIRED ]; then
    rm -Rf $BAK_EXPIRED
fi

dropbox_uploader.sh的操作跟一般的文件操作类似,可以上传指定的文件或文件夹。

好了,剩下的工作就是想办法免费扩容。