网络文件共享(6)之使用rsync完成备份

网络文件共享(6)之使用rsync完成备份

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

为什么要做备份?

我们都知道,天有不测风云,再好的电脑,也有可能突然就坏了,毫无征兆。而我们存在电脑里的重要资料,可能就面临丢失的风险。

特别是一些做技术的,做数据的,做财务的,电脑上特别多的 EXCEL 文档,甚至一些重要的技术文件、图纸等。在没有备份的情况下,遇到电脑突然损坏、中病毒等,一个是没法马上继续工作,另外就是万一电脑修不好,数据都丢了怎么办?当然,这个仅仅是对于个人电脑而言,如果是服务器的话,损失就很严重了。

对于企业而言,备份已经是一个不能忽视问题!而对于个人而言,备份是否同样重要?

在我看来,是的。数据无价,在互联网时代,我们有特别多的电子资源存放在我们的电脑上(照片、视频、素材、学习资料等),工作中也会有很多公司资料存在电脑中。虽然可能我们还能重做,或者重新找到这些资源,但是你需要很多的时间或者金钱。

备份,就像给资料买一份保险,可能它不能完全让你没有损失,但是却能在电脑出问题或者中病毒时,将你的损失降到最低。

备份的分类

按照备份设备的位置可分为本地备份和异地备份:

  • 本地备份指的是在单台主机上将指定资源拷贝到另一个存储设备,这个设备可能是个 U 盘,也可能是一块硬盘;
  • 异地备份指的是将本机的指定资源通过网络传输到远程主机保存到远程主机的存储设备;

按照备份文件的策略还可分为全量备份和增量备份:

  • 全量备份(full backup):每隔一段时间对系统进行一次完全备份,这样在备份时间间隔内一旦系统发生故障导致数据丢失,就可以用上一次的备份数据恢复到上一次备份时的情况。例如,星期一用一盘磁带备份整个系统,星期二再用另一盘磁带 备份,依次类推。
    优点:备份的数据最全面且最完整,当发生数据丢失灾难时只要用一盘磁带(即灾难发生前一天的备份磁带)就可以恢复全部的数据。
  • 增量备份(incremental backup):首先进行一次完全备份,然后每隔一个较短时间进行一次备份,但仅备份在这个期间更改的内容。这样一旦发生数据丢失,首先恢复到前一个完全备份。然后按日期逐个恢复每天的备份,就能恢复到前一天的情况。例如,在星期天进行一次完全备份,然后在接下来的6天中只备份当天新的或被修改过的数据。
    优点:这种备份策略的有点是备份速度快,没有重复的备份数据,节省了磁带空间,缩短 了备份时间。

备份的实现方案

先说一下我们已经了解的备份方案:

  • 本地备份直接使用 cp 命令就可以完成,直接将一个文件拷贝到挂载到指定目录的另一个存储设备中,这个就不赘述了;
  • 远程备份可使用 OpenSSH 客户端组件提供的 scp 命令完成,该命令详细使用可参考【使用 scp 传送文件】;

上述两种方案有一个共同的缺陷,就是只支持全量备份。要实现增量备份,可使用下面的 rsync 命令。

rsync 入门及使用

rsync 命令是一个远程数据同步工具,可通过 LAN/WAN 快速同步多台主机间的文件。rsync 使用所谓的“rsync 算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而不是每次都整份传送,因此速度相当快。 rsync 是一个功能非常强大的工具,其命令也有很多功能特色选项,我们下面就对它的选项一一进行分析说明。

语法:

rsync [OPTION]... SRC DEST
rsync [OPTION]... SRC [USER@]HOST:DEST
rsync [OPTION]... [USER@]HOST:SRC DEST
rsync [OPTION]... [USER@]HOST::SRC DEST
rsync [OPTION]... SRC [USER@]HOST::DEST
rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]

对应于以上六种命令格式,rsync 有六种不同的工作模式:

  1. 拷贝本地文件。当 SRCDES 路径信息都不包含有单个冒号 “:” 分隔符时就启动这种工作模式。如:rsync -a /data /backup
  2. 使用一个远程 shell 程序(如 rsh、ssh)来实现将本地机器的内容拷贝到远程机器。当 DST 路径地址包含单个冒号 “:” 分隔符时启动该模式。如:rsync -avz *.c foo:src
  3. 使用一个远程 shell 程序(如 rsh、ssh)来实现将远程机器的内容拷贝到本地机器。当 SRC 地址路径包含单个冒号 “:” 分隔符时启动该模式。如:rsync -avz foo:src/bar /data
  4. 从远程 rsync 服务器中拷贝文件到本地机。当 SRC 路径信息包含 “::” 分隔符时启动该模式。如:rsync -av root@192.168.1.192::www /databack
  5. 从本地机器拷贝文件到远程 rsync 服务器中。当 DST 路径信息包含 “::” 分隔符时启动该模式。如:rsync -av /databack root@192.168.78.192::www
  6. 列出远程机的文件列表。这类似于 rsync 传输,不过只要在命令中省略掉本地机信息即可。如:rsync -v rsync://192.168.1.192/www

各选项含义如下:

-v, --verbose 详细模式输出。
-q, --quiet 精简输出模式。
-c, --checksum 打开校验开关,强制对文件传输进行校验。
-a, --archive 归档模式,表示以递归方式传输文件,并保持所有文件属性,等于 -rlptgoD。
-r, --recursive 对子目录以递归模式处理。
-R, --relative 使用相对路径信息。
-b, --backup 创建备份,也就是对于目的已经存在有同样的文件名时,将老的文件重新命名为 ~filename。可以使用 --suffix 选项来指定不同的备份文件前缀。
--backup-dir 将备份文件(如 ~filename )存放在在目录下。
-suffix=SUFFIX 定义备份文件前缀。
-u, --update 仅仅进行更新,也就是跳过所有已经存在于 DST,并且文件时间晚于要备份的文件,不覆盖更新的文件。
-l, --links 保留软链结。
-L, --copy-links 想对待常规文件一样处理软链结。
--copy-unsafe-links 仅仅拷贝指向 SRC 路径目录树以外的链结。
--safe-links 忽略指向 SRC 路径目录树以外的链结。
-H, --hard-links 保留硬链结。
-p, --perms 保持文件权限。
-o, --owner 保持文件属主信息。
-g, --group 保持文件属组信息。
-D, --devices 保持设备文件信息。
-t, --times 保持文件时间信息。
-S, --sparse 对稀疏文件进行特殊处理以节省 DST 的空间。
-n, --dry-run现实哪些文件将被传输。
-w, --whole-file 拷贝文件,不进行增量检测。
-x, --one-file-system 不要跨越文件系统边界。
-B, --block-size=SIZE 检验算法使用的块尺寸,默认是 700 字节。
-e, --rsh=command 指定使用 rsh、ssh 方式进行数据同步。
--rsync-path=PATH 指定远程服务器上的 rsync 命令所在路径信息。
-C, --cvs-exclude 使用和 CVS 一样的方法自动忽略文件,用来排除那些不希望传输的文件。
--existing 仅仅更新那些已经存在于 DST 的文件,而不备份那些新创建的文件。
--delete 删除那些 DST 中 SRC 没有的文件。
--delete-excluded 同样删除接收端那些被该选项指定排除的文件。
--delete-after 传输结束以后再删除。
--ignore-errors 及时出现 IO 错误也进行删除。
--max-delete=NUM 最多删除 NUM 个文件。
--partial 保留那些因故没有完全传输的文件,以是加快随后的再次传输。
--force 强制删除目录,即使不为空。
--numeric-ids 不将数字的用户和组id匹配为用户名和组名。
--timeout=time ip超时时间,单位为秒。
-I, --ignore-times 不跳过那些有同样的时间和长度的文件。
--size-only 当决定是否要备份文件时,仅仅察看文件大小而不考虑文件时间。
--modify-window=NUM 决定文件是否时间相同时使用的时间戳窗口,默认为 0。
-T --temp-dir=DIR 在 DIR 中创建临时文件。
--compare-dest=DIR 同样比较 DIR 中的文件来决定是否需要备份。
-P 等同于 --partial。
--progress 显示备份过程。
-z, --compress 对备份的文件在传输时进行压缩处理。
--exclude=PATTERN 指定排除不需要传输的文件模式。
--include=PATTERN 指定不排除而需要传输的文件模式。
--exclude-from=FILE 排除 FILE 中指定模式的文件。
--include-from=FILE 不排除 FILE 指定模式匹配的文件。
--version 打印版本信息。
--address 绑定到特定的地址。
--config=FILE 指定其他的配置文件,不使用默认的 rsyncd.conf 文件。
--port=PORT 指定其他的 rsync 服务端口。
--blocking-io 对远程 shell 使用阻塞 IO。
-stats 给出某些文件的传输状态。
--progress 在传输显示传输过程。
--log-format=FORMAT 指定日志文件格式。
--password-file=FILE 从 FILE 中得到密码。
--bwlimit=KBPS 限制 I/O 带宽,KBytes per second。
-h, --help 显示帮助信息。

安装

使用 yum 安装:

$ yum install rsync -y

我这里准备服务端(IP:172.16.1.41),客户端(IP:172.16.1.200)来完成下面实例。

ssh 方式

1、首先要在服务端启动 ssh 服务:

$ systemctl start sshd

2、在服务端准备测试目录及文件:

$ mkdir /www
$ touch /www/{1..3}.txt

3、接下来就可以在客户端使用 rsync 命令来备份服务端上的数据了,先准备一下备份的目录:

$ mkdir /data_backup/rsync -p

4、SSH 方式是通过系统用户账号认证来进行备份的,以将服务端的 /www 目录备份到客户端的 /data_backup/rsync 目录为例,客户端执行如下命令:

$ rsync -vzrtopg --progress -e ssh --delete root@172.16.1.41:/www /data_backup/rsync
root@172.16.1.41's password: 
receiving incremental file list
www/
www/1.txt
              0 100%    0.00kB/s    0:00:00 (xfr#1, to-chk=2/4)
www/2.txt
              0 100%    0.00kB/s    0:00:00 (xfr#2, to-chk=1/4)
www/3.txt
              0 100%    0.00kB/s    0:00:00 (xfr#3, to-chk=0/4)

sent 85 bytes  received 221 bytes  47.08 bytes/sec
total size is 0  speedup is 0.00

$ tree /data_backup/rsync/
/data_backup/rsync/
└── www
    ├── 1.txt
    ├── 2.txt
    └── 3.txt

1 directory, 3 files

上面这个命令行中 -vzrtopg 里的 v 是显示进度,z 是压缩,r 是递归目录,topg是保持文件原有属性如属主、时间的参数(也可以用直接用 a 来代替 rtopga--archive 归档模式,表示以递归方式传输文件,并保持所有文件属性,等于 -rlptgoD)。--progress 是指显示出详细的进度情况,--delete 是指如果服务器端删除了这一文件,那么客户端也相应把文件删除,保持真正的一致。
如果是 CentOS 6,需在服务端编辑 /etc/xinetd.d/rsync 文件,将其中的 disable=yes 改为 disable=no,并重启 xinetd 服务。

守护进程方式

服务端配置

1、查看 rsync 配置文件位置:

$ rpm -qc rsync
/etc/rsyncd.conf
/etc/sysconfig/rsyncd

2、我们只需要关注 /etc/rsyncd.conf 文件,rsync 默认使用的是系统用户做认证,这里我们来配置虚拟用户,修改该配置文件如下:

# 运行进程的用户
uid = rsync
# 运行进程的用户组
gid = rsync
# 监听的端口
port = 873
# 无需让 rsync 以 root 身份运行,允许存储文件的完整属性
fake super = yes
# 关闭假根功能
use chroot = no
# 最大连接数
max connections = 200
# 超时时间
timeout = 600
# 忽略错误信息
ignore errors
# 对备份数据可读写
read only = false
# 不允许查看模块信息
list = false
# 定义虚拟用户,作为连接认证用户
auth users = rsync_backup
# 定义 rsync 服务用户连接认证密码文件路径
secrets file = /etc/rsync.password
# 日志文件路径
log file = /var/log/rsyncd.log

# 上面配置内容为全局配置,对下面所有模块配置生效。
#####################################
# 定义模块
[backup]
# 模块的说明信息
comment = welcome to backup!
# 接收备份数据的目录
path = /backup

3、创建傀儡用户:

$ useradd -M -s /sbin/nologin rsync

4、创建备份目录,并授权 rsync 用户为属主:

$ mkdir /backup
$ chown -R rsync.rsync /backup

5、创建虚拟用户的密码文件,并赋予其权限为 600

$ echo "rsync_backup:1" >/etc/rsync.password
$ chmod 600 /etc/rsync.password

这里 rsync_backup 是虚拟用户的用户名,1 为密码,用于客户端向服务端推送时使用。

6、启动 rsync 服务,并设定开机自启:

$ systemctl start rsyncd
$ systemctl enable rsyncd

7、检查 873 端口是否处于监听状态:

$ netstat -tanl | grep 873
tcp        0      0 0.0.0.0:873             0.0.0.0:*               LISTEN     
tcp6       0      0 :::873                  :::*                    LISTEN

测试同步

1、在客户端将 /data_backup/rsync/www 目录中的所有文件推送到服务端的 backup 模块:

$ rsync -avz /data_backup/rsync/www rsync_backup@172.16.1.41::backup
Password: 
sending incremental file list
www/
www/1.txt
www/2.txt
www/3.txt

sent 225 bytes  received 85 bytes  12.16 bytes/sec
total size is 0  speedup is 0.00

2、查看服务端 /backup 目录是否接收到了文件:

$ tree /backup/
/backup/
└── www
    ├── 1.txt
    ├── 2.txt
    └── 3.txt

1 directory, 3 files

3、清空客户端的 /data_backup/rsync/ 目录,拉取服务端 backup 模块目录中的文件到该目录:

$ rm -rf /data_backup/rsync/*
$ tree /data_backup/rsync/
/data_backup/rsync/

0 directories, 0 files

$ rsync -avz rsync_backup@172.16.1.41::backup /data_backup/rsync/
Password: 
receiving incremental file list
./
www/
www/1.txt
www/2.txt
www/3.txt

sent 92 bytes  received 268 bytes  55.38 bytes/sec
total size is 0  speedup is 0.00

4、查看客户端 /data_backup/rsync 目录是否接收到了拉取的文件:

$ tree /data_backup/rsync/
/data_backup/rsync/
└── www
    ├── 1.txt
    ├── 2.txt
    └── 3.txt

1 directory, 3 files

同步时不输入密码指定密码文件

1、在客户端创建密码文件并赋予 600 权限:

$ echo "1" >/etc/rsync.password 
$ chmod 600 /etc/rsync.password

2、清空客户端的 /data_backup/rsync/ 目录,拉取服务端 backup 模块目录中的文件到该目录时使用 --password-file 指定密码文件:

$ rm -rf /data_backup/rsync/*
$ rsync -avz rsync_backup@172.16.1.41::backup /data_backup/rsync/ --password-file=/etc/rsync.password
receiving incremental file list
./
www/
www/1.txt
www/2.txt
www/3.txt

sent 92 bytes  received 268 bytes  720.00 bytes/sec
total size is 0  speedup is 0.00

3、再次查看 /data_backup/rsync/ 目录会发现拉取成功了:

$ tree /data_backup/rsync/
/data_backup/rsync/
└── www
    ├── 1.txt
    ├── 2.txt
    └── 3.txt

1 directory, 3 files

同步时不输入密码指定环境变量

1、清空客户端的 /data_backup/rsync/ 目录,将密码赋值给 RSYNC_PASSWORD 变量并导出:

$ rm -rf /data_backup/rsync/*
$ export RSYNC_PASSWORD=1 

2、拉取服务端 backup 模块目录中的文件到 /data_backup/rsync/ 目录:

$ rsync -avz rsync_backup@172.16.1.41::backup /data_backup/rsync/
receiving incremental file list
./
www/
www/1.txt
www/2.txt
www/3.txt

sent 92 bytes  received 268 bytes  240.00 bytes/sec
total size is 0  speedup is 0.00

可以看到不用输入密码直接拉取成功~

综合案例

要求如下:

  1. 将客户端的 /etc/fstab/etc/rc.d/rc.local/etc/hosts 备份到备份服务器;
  2. 客户端每天凌晨一点执行推送操作备份到服务端;
  3. 客户端仅保留 7 天内的备份文件;
  4. 服务端每天凌晨两点要检查文件的完整性;
  5. 需要将检查结果通过邮件通知用户;
  6. 服务端备份目录格式为 HOSTNAME_IP_YYYY-mm-dd,其中 HOSTNAMEIP 分别为客户端的主机名和 IP,YYYY-mm-dd 为当日日期;
  7. 服务端仅保留 6 个月内的文件;

客户端

1、编写名为 backup.sh 的 Shell 脚本如下:

#!/bin/bash
# 
# 备份客户端 172.16.1.31
#
# 备份文件到 172.16.1.41

backup_path="/backup/`hostname`_`ifconfig eth1 | awk 'NR==2{print $2}'`_`date +%F`"
[ ! -d $backup_path ] && mkdir $backup_path -p
rsync -az /etc/{fstab,rc.d/rc.local,hosts} $backup_path

# 生成校验文件
find $backup_path -type f -not -name 'checksum'| xargs -i md5sum {} > "$backup_path/checksum"

export RSYNC_PASSWORD=1 
rsync -avz --bwlimit=1 $backup_path rsync_backup@172.16.1.41::backup &> /dev/null
# 删除七天之前的文件
find /backup -type d -mtime +7 -not -name '..' -not -name '.' | xargs rm -rf

2、执行 crontab -e 编写定时任务如下:

PATH="$PATH:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"

00 01 * * * bash /scripts/backup.sh

服务端

1、完成 rsyncd 守护进程方式配置。
2、编写名为 sendmail.sh 发送邮件的 Python 脚本:

#!/usr/bin/python3
#

import smtplib
import sys
from email.mime.text import MIMEText

msg_from = '发件人邮箱'
passwd = '密码或授权码'
msg_to = ['收件人邮箱']
content = sys.argv[1]

subject = "备份通知"
msg = MIMEText(content)
msg['Subject'] = subject
msg['From'] = msg_from
try:
    s = smtplib.SMTP_SSL("smtp.qq.com", 465)
    s.login(msg_from, passwd)
    s.sendmail(msg_from, msg_to, msg.as_string())
    print('发送成功')
except s.SMTPException as e:
    print(e)
finally:
    s.quit()

也可以直接配置 mailx 服务发送邮件账号,以 QQ 邮箱为例,编辑 /etc/mail.rc 在底部添加如下配置:

set from=发送邮件的账号
set smtp="smtp.qq.com"
set smtp-auth-user="同 from"
set smtp-auth-password="aaavvvsdasd"   # 邮箱授权码
set smtp-auth="login"

然后按以下格式即可发送邮件:

echo '邮件内容'| mailx -s '邮件标题' 目标邮箱

3、编写名为 backup_checksum.sh 的 Shell 脚本如下:

#!/bin/bash
#
# rsync 服务端
#
# 检查今日备份文件的完整性

fail_dir_str=''

# 遍历今天生成的备份目录
for backup_today_dir in `find /backup/* -type d -mtime -1`
do
        # 检查是否存在失败的文件
        fail_file=`md5sum -c "$backup_today_dir/checksum" 2> /dev/null | grep ': OK' -v`
        # 如果存在检查失败的文件
        if [ $? -eq 0 ];then
                # 保存失败文件列表到 checkresult 中
                echo $fail_file | xargs -n2 > "$backup_today_dir/checkresult"
                # 记录备份失败的目录
                fail_dir_str="$fail_dir_str\n$backup_today_dir"
        fi
done

if [ -z $fail_dir_str ];then
        email_content='备份成功'
        echo $email_content > "$backup_today_dir/checkresult"
else
        email_content="在如下目录中有备份失败的文件,请查看:\n$fail_dir_str"
fi

# 发送邮件
# echo -e $email_content | mailx -s "[`date +%F`]备份通知" root@127.0.0.1
python3 /scripts/python/sendmail.py "$email_content" &> /dev/null
find /backup/* -type d -mtime +180 | xargs rm -rf

4、执行 crontab -e 添加如下定时任务:

PATH="$PATH:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"

00 02 * * * bash /scripts/backup_checksum.sh &> /dev/null

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/linux-file-sharing56.html

Buy me a cup of coffee ☕.