使用cron和scp备份数据

数据多备份几份,永远也不会错。如果数据量小,又没有条件买专用的备份服务器,本地的电脑也可以作为备份机子,一则数据多了一层保障,二则备份下来的数据,也可以更新本地测试环境的数据,一举两得。

为啥选cron和scp

平时在服务器间拷数据用的最多的就是scp,用起来还是很顺手的;本地电脑只能在半夜备份(不影响办公),cron自然就是首选了。

思路

先写一个scp脚本,找出服务器上最近的数据备份版本,使用cron定时在凌晨执行脚本备份。

scp脚本

  • 配置文件脚本,用来配置服务器相关信息

     # config file for local backup 
     # server config
     ServerIp=127.0.0.1
     ServerUser=user
     ServerPwd=pass
     ServerBackupHour=( "22"  "14" "05" )
     Path=/data1/backup/
    
  • 备份脚本 服务器会按固定的三个时间点以小时为版本备份数据,脚本只要找出最近的版本备份即可。 scp输入密码可以使用key解决,这里采用了sshpass传递。 脚本手动执行,运行很正常。

		#!/bin/bash

		# include config file
		source /etc/local_backup_config.sh 

		# path
		BackupPath=/home/slayer/databackup/
		LogPath=/tmp/local_backup.log

		# date
		BackupDate=$(date +%Y_%m_%d)
		

		# find the latest backup version to backup
		Hour=`date +%H`

		BackupDir=${BackupDate}_${Hour}
		for hour in ${ServerBackupHour[@]}; do
		    if [ "${BackupDate}_${Hour}" \> "${BackupDate}_${hour}" ]
		    then
		       BackupDir="${BackupDate}_${hour}";
		       break;
		    fi
		done

		echo `date +%Y-%m-%d %H:%I:%S`  backup ${BackupDir} ... >> $LogPath

		# backup
		# sshpass -p ${ServerPwd} scp -rv ${ServerUser}@${ServerIp}:${ServerPath}${BackupDir} $BackupPath 1>$LogPath 2>&1 

		echo `date +%Y-%m-%d %H:%I:%S` excute code $? >>$LogPath

		if [ $? -eq 0 ]
		then
		    echo `date +%Y-%m-%d %H:%I:%S` backup ${BackupDir} success >> $LogPath
		else 
		    echo `date +%Y-%m-%d %H:%I:%S` backup ${BackupDir} failed >> $LogPath
		fi
		
        

cron任务

local_backup_cron任务,放入/etc/cron.d/,在凌晨1点05分执行脚本:

# 5 1 * * *  root /home/slayer/vhost/sysadmin/shells/local_backup.sh >/dev/null

这里遇到一个很大的坑,cron到时间确实会执行脚本,但是scp却没有运行成功,查了很多资料,大部分都是说cron的环境变量与当前手动执行的环境不一样,最明显的就是PATH不一样,所以当前命令行能运行的命令,在cron的运行环境里面可能就找不到。 然后就一步一步排查:

  • 我试着打印出来cron的PATH,发现其值为 /usr/bin:/bin;但是脚本用到的sshpass,scp都在/usr/bin下面,说明是没有问题的。

  • 然后打开了scp的debug模式,在log下发现scp会无缘无故断掉,跑到服务器上看下,服务器显示的信息就是客户端关闭了链接,那就是客户端的scp链接有问题,突然想起来是定时脚本是使用root脚本,顿时想起ssh链接的时候需要去用户目录下.ssh验证一下一些信息,而我从没有在root下链接过那台服务器,恩,改成当前用户就可以了。

      # 5 1 * * *  slayer /home/slayer/vhost/sysadmin/shells/local_backup.sh >/dev/null
    

加上自动关机

为了省电,在数据下载完成后需要关闭计算机,那就必须使用root用户了,恩没办法了,只能在root下连了一下服务器;

但是shutdown命令并没有在/usr/bin和/bin里面,而是在/sbin里面,那只能在脚本最前面把/sbin加入到PATH:

PATH=$PATH:/sbin

在备份脚本里面加上关机的代码:

# shutdown system after job done
Halt=true
# shutdown system
if $Halt ; then
    echo `date +%Y-%m-%d %H:%I:%S` shutdown... >> $LogPath
    shutdown -h now >> $LogPath
    echo `date +%Y-%m-%d %H:%I:%S` shutdown $? >> $LogPath
fi

cron里面的坑

因为cron的环境变量不一样的坑,两种解决办法:

  • 脚本里面的命令使用绝对路径
  • 在脚本里面重新设置PATH

最后使用ssh目录的时候,不管是使用sshpass传递,还是sshkey登录,都需要注意cron任务里面的用户目录下的.ssh目录下存在目标计算机的链接信息。如果该用户没有链接过目标计算机,链接一下,就能跳出这个坑。