最近接到一个需求,需要做文件同步,一个程序在某个文件夹下生成数据,其他的几台服务器需要用到这些数据,不愿意弄共享存储服务以及搞NAS什么的,就用 rsync + inotify做下实时同步好了,简单方便,这这篇文章是为了记录下,免得以后有类似需求再忘记。
需求如下,一共7台服务器,其中一台服务器在某个目录下面生成文件,然后同步到6台服务器上去。
生成文件的服务器为:192.168.0.1
其他六台服务器为:192.168.0.2-7
服务器端 rsync 的安装和配置
在6台被同步的服务器 192.168.0.2-7 上面安装 rsync ,作为懒人,当然不可以一台台服务器登录去安装了,自动化工具 fabric 派上用场(我前面有讲解 fabric 用法的系列文章)。上代码
#!/usr/bin/python env
# -*- coding: UTF-8 -*-
from fabric.api import env
from fabric.api import run
from fabric.api import put
from fabric.api import execute
from fabric.api import roles
from fabric.api import parallel
from fabric.api import cd
env.user = 'username'
env.password = 'password'
env.roledefs = {
'rsync-server': ['192.168.0.2', '192.168.0.3','192.168.0.4','192.168.0.5','192.168.0.6','192.168.0.7'],
}
@roles('rsync-server')
def install_rsync():
run('sudo yum -y install rsync')
@roles('rsync-server')
def put_rsync_conf():
put('rsyncd.conf','/tmp/rsyncd.conf')
@roles('rsync-server')
def put_rsync_pass_conf():
put('rsync.password','/tmp/rsync.password')
@roles('rsync-server')
def copy_rsync_conf():
run('sudo cp -av /tmp/rsyncd.conf /etc/rsyncd.conf')
@roles('rsync-server')
def copy_rsync_pass_conf():
run('sudo cp -av /tmp/rsync.password /etc/rsync.password')
@roles('rsync-server')
def change_auth_rsync_pass():
run('sudo chmod 600 /etc/rsync.password') # 这个必须修改权限为600,不然无法认证
@roles('rsync-server')
def start_rsync_deamon():
run('sudo /usr/bin/rsync --daemon --config=/etc/rsyncd.conf')
@parallel
def execute_all():
execute(install_rsync)
execute(put_rsync_conf)
execute(put_rsync_pass_conf)
execute(copy_rsync_conf)
execute(copy_rsync_pass_conf)
execute(change_auth_rsync_pass)
execute(start_rsync_deamon)
其中 /etc/rsyncd.conf
的配置文件如下:
uid = root #全局配置开始,运行rsync的用户
gid = root #运行rsync的用户组
usechroot = no #是否让进程离开工作目录
max connections = 20 #最大进程并发数
timeout = 600 #连接超时时间
pid file = /var/run/rsyncd.pid #指定运行的rsync进程的pid存放路径
lock file = /var/run/rsync.lock #指定运行的rsync进程的锁文件存放路径
log file = /var/log/rsyncd.log #指定运行的rsync进程的日志文件路径
hosts allow = 192.168.0.1 #运行访问的主机地址,如果要放开所有的权限可以用 * 号表示,也可以用网段表示,比如 192.168.0.1/24,同时这个还可以放在模块 rank 那
hosts deny = 192.168.1.1/24 #禁止访问的主机,同时这个还可以放在模块 rank 那
[rank] #表示一个模块,待会客户端同步的脚本会用到这个
use chroot = yes # 当同步的目录中有软连接的时候需要用这个选项忽略软连接,不然会报错。即 use chroot = yes。而不能等于 no
path = /tmp/data/ #同步的路径
ignore errors = yes #忽略一些无关的I/O错误
read only = false #false为关闭,true表示开启。表示只读,不允许上传文件
write only = false #不允许下载
list = false #客户请求可以使用模块列表时是否被列出
hosts allow = *
auth users = test #自定义连接该模块的用户名,多个用户用逗号分隔
secrets file = /etc/rsync.password #指定一个包含“用户名:密码”格式的文件
注:一定要确保该服务器的
/tmp/data/
目录已经创建,不能无法同步数据,其不会自动创建目录
其中 /etc/rsync.password
配置文件如下:
test:12345
客户端 inotify 的安装以及同步脚本
- 安装 inotify 软件,好吧,一台我也用 fabric
#!/usr/bin/python env
# -*- coding: UTF-8 -*-
from fabric.api import env
from fabric.api import run
from fabric.api import put
from fabric.api import execute
from fabric.api import roles
from fabric.api import parallel
from fabric.api import cd
env.user = 'username'
env.password = 'password'
env.roledefs = {
'rsync-client': ['192.168.0.1'],
}
@roles('rsync-client')
def install_rsync():
run('sudo yum -y install rsync')
@roles('rsync-client')
def down_inotify():
#run('wget http://cloud.github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz')
run('wget http://pkgs.fedoraproject.org/repo/pkgs/inotify-tools/inotify-tools-3.14.tar.gz/b43d95a0fa8c45f8bab3aec9672cf30c/')
roles('rsync-client')
def make_install_inotify():
with cd('inotify-tools-3.14'):
run('./configure && make')
run('sudo make install')
@roles('rsync-client')
def tar_inotify():
run('tar -zxvf inotify-tools-3.14.tar.gz')
@roles('rsync-client')
def copy_rsync_pass_conf():
run('sudo cp -av /tmp/rsync.password_client /etc/rsync.password') #这个密码文件和服务器端的不一样,该文件中只需要配置一个密码 ‘12345’
@roles('rsync-client')
def change_auth_rsync_pass():
run('sudo chmod 600 /etc/rsync.password') # 这个必须修改权限为600,不能无法认证
@parallel
def execute_all():
execute(install_rsync)
execute(down_inotify)
execute(tar_inotify)
execute(make_install_inotify)
execute(copy_rsync_pass_conf)
execute(change_auth_rsync_pass)
以上执行完成后,进行后面的同步脚本编写了,同步脚本的名字为 rsync_inotify.sh
#!/bin/bash
SRC='/tmp/data/'
USER=test
host1=192.168.0.2
host2=192.168.0.3
host3=192.168.0.4
host4=192.168.0.5
host5=192.168.0.6
host6=192.168.0.7
DES_MODEL=rank
/usr/local/bin/inotifywait -mr --timefmt '%d/%m/%y %H:%M' --format '%T %w %f' -e modify,delete,create,attrib ${SRC} |while read DATE TIME DIR FILE
do
FILECHAGE=${DIR}${FILE}
/usr/bin/rsync -av --progress --delete --password-file=/etc/rsync.password $SRC $USER@$host1::$DES_MODEL && echo "At ${TIME} on ${DATE}, file $FILECHAGE was backed up via rsync" >> /var/logs/rsyncd.log
/usr/bin/rsync -av --progress --delete --password-file=/etc/rsync.password $SRC $USER@$host2::$DES_MODEL && echo "At ${TIME} on ${DATE}, file $FILECHAGE was backed up via rsync" >> /var/logs/rsyncd.log
/usr/bin/rsync -av --progress --delete --password-file=/etc/rsync.password $SRC $USER@$host3::$DES_MODEL && echo "At ${TIME} on ${DATE}, file $FILECHAGE was backed up via rsync" >> /var/logs/rsyncd.log
/usr/bin/rsync -av --progress --delete --password-file=/etc/rsync.password $SRC $USER@$host4::$DES_MODEL && echo "At ${TIME} on ${DATE}, file $FILECHAGE was backed up via rsync" >> /var/logs/rsyncd.log
/usr/bin/rsync -av --progress --delete --password-file=/etc/rsync.password $SRC $USER@$host5::$DES_MODEL && echo "At ${TIME} on ${DATE}, file $FILECHAGE was backed up via rsync" >> /var/logs/rsyncd.log
/usr/bin/rsync -av --progress --delete --password-file=/etc/rsync.password $SRC $USER@$host6::$DES_MODEL && echo "At ${TIME} on ${DATE}, file $FILECHAGE was backed up via rsync" >> /var/logs/rsyncd.log
done
以上脚本对 /tmp/data/
目录下面的所有数据的 ```mdca`` 进行监听,如果发现有变更,会立即进行同步。
inotify相关参数介绍
脚本中相关参数的解释
- timefmt -- 指定时间的输出格式。
- format -- 指定变化文件的详细信息。
- m -- 监控
- r -- 递归
q -- 静默模式
e -- 指定你要同步的事件
modify 修改
delete 删除
create 创建
attrib 属性
注: 该需求实现参考了 liangxiaowei66 的博客 rsync+inotify实时同步,关于rsync 的参数的详细解释,就不在本文讲了,各位有兴趣可以看 man 手册,或者是该作者的这篇博客
注:如果出现如下错误
name lookup failed for XX.XX.XX.XX: Name or service not known
,这是因为没有在服务器端的/etc/hosts
文件中配置客户端的 IP 和 主机名,只要配置了 IP 和主机名即可。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。