最近迁移服务器,优化了一直使用的 VPS 资料备份的脚本,增加结果发送到 telegram,使用配置文件等一些优化,跟大家分享一下。
1. 背景简介
在我的 1C1.3G 40G rackNerd 小鸡 上跑着 mjj 三件套(探针、图床、博客)和一些个人折腾的小脚本,所有服务已经 docker 化,外网入口到服务器后,由 docker 版 nginx 代理转发内部 dockge 管理的各个 docker 服务。
项目文件主要在:
- 网站项目文件统一放在
/var/www/html
- Docker 及配置文件及数据放在
/opt/docker/data
2. 备份什么?
为避免数据丢失可能导致不可逆转的损失,定期备份服务器上的文件和数据库,确保始终可以恢复到最新的状态。
每日凌晨四点备份以下数据:
- 网站文件:包括 HTML、CSS、图片以及其它的静态文件
- 应用程序代码:如 PHP、Python、等语言编写的源代码
- 配置文件:有关服务器、数据库、应用程序等的配置设置
- 数据库:MySQL 保存应用程序的动态数据
- 镜像压缩包:自定义 Docker 镜像的压缩包
每日打包文件和数据,压缩到一个 gz 文件,并且保留备日志以备检查。
保存最近 7 天 gz 备份文件,并 rsync 同步到拷贝备份机进行异地镜像存储。
3. 如何备份?
使用 tar 命令打包压缩文件
# 备份
cd /backup/path/data && tar zcvf /backup/storage/data.tar.gz --transform='s/^\.\///' .
# 查看
tar -tvf /backup/storage/data.tar.gz
# 解压到指定路径
tar -xzf data.tar.gz -C /path/to/destination example.txt # 或者 example_dir/
使用 mysqldump 命令备份 MySQL 数据库
# 备份
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME > "/backup/storage/db_backup.sql"
# 还原
mysql -u $DB_USER -p$DB_PASS $DB_NAME < /backup/storage/db_backup.sql
脚本备份过程:
3. 主要代码
# 备份网站
backup_www() {
cp -rf /var/www/html ${BACKUP_DAYS}/www/
cd ${BACKUP_DAYS}/www && tar zcvf ${BACKUP_DAYS}/tar/www.tar.gz --transform='s/^\.\///' .
if [ $? -eq 0 ]; then
coloured_text "网站 WWW 文件打包成功" "${COLOR_GREEN}"
else
ERROR_MESSAGE="网站 WWW 文件打包失败"
echo "$ERROR_MESSAGE"
return 1
fi
return 0
}
# 备份数据库
backup_mysql() {
echo "开始备份 MySQL"
# docker 镜像名称
local container_name="mysql"
local backup_time=`date +%Y%m%d%H%M`
# database
local backup_database=app_data
docker exec -e MYSQL_PWD=$MySQL_PASSWORD $container_name mysqldump -h$MySQL_HOST -P$MySQL_PORT -u$MySQL_USER -B $backup_database > $BACKUP_DAYS/sql/$backup_database-$backup_time.sql
if [ $? -eq 0 ]; then
coloured_text "备份数据库 ${backup_database} 成功" "${COLOR_GREEN}"
else
ERROR_MESSAGE="备份数据库失败,请检查配置参数"
echo "$ERROR_MESSAGE"
return 1
fi
# 打包SQL文件
echo "开始打包 MySQL"
cd ${BACKUP_DAYS}/sql && tar zcvf ${BACKUP_DAYS}/tar/sql.tar.gz --transform='s/^\.\///' .
if [ $? -eq 0 ]; then
coloured_text "数据库 MySQL 文件打包成功" "${COLOR_GREEN}"
else
ERROR_MESSAGE="数据库 MySQL 文件打包失败"
echo "$ERROR_MESSAGE"
return 1
fi
return 0
}
# 清理旧备份文件
clean_old_files() {
echo "开始删除过期文件"
# data 目录
num=$(ls -l ${BACKUP_DATA}/backup-*.tar.gz | grep "^-" | wc -l)
while [ ${num} -gt ${MAX_NUM} ]
do
filename=$(ls -rt ${BACKUP_DATA}/backup-*.tar.gz | head -n 1)
if [ -n "${filename}" ]; then
rm -f "${filename}"
echo "删除旧文件 ${filename}"
fi
local log=$(echo "$filename" | sed 's#/data/#/logs/#; s#\.tar\.gz$#.log#')
if [ -n "${log}" ]; then
rm -f "${log}"
echo "删除日志 ${log}"
fi
let num--
done
# days 目录(保留 1 天,共2 份)
find $BACKUP_ROOT/days -maxdepth 1 -type d -mtime +1 -exec echo "删除旧文件夹" {} \; -exec rm -r {} +
coloured_text "删除过期文件完毕" "${COLOR_GREEN}"
return 0
}
# 同步到远程文件机
sync_to_remote() {
echo "开始同步文件到远程服务器"
rsync -e "ssh -p${PUSH_TO_PORT}" -avz --delete ${BACKUP_DATA}/ root@${PUSH_TO_SERVER}:${BACKUP_DATA}/
if [ $? -eq 0 ]; then
coloured_text "同步文件到远程服务器成功" "${COLOR_GREEN}"
else
ERROR_MESSAGE="推送到备份机失败,请检查网络设置是否正确"
echo "$ERROR_MESSAGE"
return 1
fi
return 0
}
main() {
# 执行备份任务
backup_www || return 1
backup_mysql || return 1
# 清理旧备份文件
clean_old_files || return 1
# 同步到远程文件机
sync_to_remote || return 1
# 任务结束
return 0
}
# 捕获信号
trap cleanup INT TERM EXIT
# 执行主程序
main
status=$?
if [ "$status" -ne 0 ]; then
echo "script failed"
fi
# 移除捕获
trap - INT TERM EXIT
coloured_text "备份全部完毕,最终状态 ${status}" "${COLOR_GREEN}"
exit $status