继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Ansible 进阶 | synchronise 文件同步模块

不正经程序员
关注TA
已关注
手记 39
粉丝 7374
获赞 315

准备从远程主机上拉取文件,这时我想到了 Ansible 中的 fetch 模块,但是发现 fetch 模块支持远程文件的拉取,而不支持目录!

于是,我就找到了 synchronise

synchronise 模块是对 rsync 的封装,实现控制机和目标机之间的数据同步。当然,你也可以在 command 模块中直接调用 rsync 命令,但是 synchronise 对其进行了封装,提供了一些规范化的东西,使用起来更加方便、高效,还可以增量同步。

简单了解下 rsync

rsync 是一个快速且功能非常丰富的文件拷贝工具。它可以在本地和远程之间通过 shell 或 rsync 服务互相拷贝文件。它提供了大量的选项来控制它各方面功能的行为,且在指定待拷贝文件方面非常有弹性。

它以其增量拷贝算法而出名,只拷贝源和目标不同的文件部分,因此减少网络间要传输的数据。rsync 被广泛用于做备份、镜像和当作升级版拷贝命令。

rsync 同步过程中由两部分模式组成:决定哪些文件需要同步的检查模式以及文件同步时的同步模式,也就是先检查哪些要同步,然后再进行同步。

  1. 检查模式是指按照指定规则来检查哪些文件需要被同步,例如哪些文件是明确被排除不传输的。默认情况下,rsync 使用 quick check 算法快速检查源文件和目标文件的大小、mtime(修改时间)是否一致,如果不一致则需要传输。当然,也可以通过在r sync 命令行中指定某些选项来改变 quick check 的检查模式,比如 --size-only 选项表示仅检查文件大小不同的文件作为待传输文件。rsync 支持非常多的选项,其中检查模式的自定义性是非常有弹性的。

  2. 同步模式是指在文件确定要被同步后,在同步过程发生之前要做哪些额外工作。例如上文所说的是否要先删除源主机上没有但目标主机上有的文件,是否要先备份已存在的目标文件,是否要追踪链接文件等额外操作。rsync 也提供非常多的选项使得同步模式变得更具弹性。

相对来说,为 rsync 手动指定同步模式的选项更常见一些,只有在有特殊需求时才指定检查模式,因为大多数检查模式选项都可能会影响 rsync 的性能。

rsync

总之,rsync 是非常强大的,参数选项非常多,能够实现非常具有弹性的功能,关于更完整更详细的选项说明可以参考:http://www.cnblogs.com/f-ck-need-u/p/7221713.html

synchronise

参数说明

  • src:必填,地址路径
  • dest:必填,目的地址路径
  • modemode=push,推送 ansible(src) -> 远程主机(dest);mode=pull,拉取,远程主机(src) -> ansible(dest),默认为 push
  • group:文件属组
  • owner:文件属主
  • archive:是否采用归档模式同步,即以源文件相同属性同步到目标地址,默认为 yes
  • delete:是否删除源中没有而目标存在的文件(即以推送方为主),默认为 no
  • compress:是否开启压缩,默认为 yes
  • rsync_opts:rsync 参数部分,--exclude:忽略同步文件、目录
  • rsync_timeout:指定 rsync 操作的 IP 超时时间,和 rsync 命令的 --timeout 参数效果一样

简单使用

本文中用两台主机进行试验:192.168.31.63(server端)、192.168.31.64(client端)。

我们现在 client 端随便新建一些文件:

# pwd
/tmp/client

# tree
.
└── sync_test
    └── haha.t

1 directory, 1 file
  • 从远程主机 pull 文件

这时远程主机是源文件。

# ansible test -m synchronize -a "src=/tmp/client/ dest=/tmp/server mode=pull"
client | SUCCESS => {
    "changed": true, 
    "cmd": "/usr/bin/rsync --delay-updates -F --compress --archive --rsh=/usr/bin/ssh -S none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null --out-format=<<CHANGED>>%i %n%L root@client:/tmp/client/ /tmp/server", 
    "msg": "cd+++++++++ ./\ncd+++++++++ sync_test/\n>f+++++++++ sync_test/haha.t\n", 
    "rc": 0, 
    "stdout_lines": [
        "cd+++++++++ ./", 
        "cd+++++++++ sync_test/", 
        ">f+++++++++ sync_test/haha.t"
    ]
}

在 server 节点查看,数据已同步到 /tmp/server/ 目录下:

# pwd
/tmp/server
# tree
.
└── sync_test
    └── haha.t

1 directory, 1 file
  • push 文件

我们在 haha.t 文件中随便输入一些内容,并新建一个文件:

# ll
total 4
-rw-r--r-- 1 root   root 0 Aug 23 17:34 haha2.tt
-rw-r--r-- 1 liuhao root 7 Aug 23 17:33 haha.t
# cat haha.t 
hah
ha

需要注意的是,push 时,src 需要填本地目录,dest 填远程主机目录:

# ansible test -m synchronize -a "src=/tmp/server/ dest=/tmp/client/"
client | SUCCESS => {
    "changed": true, 
    "cmd": "/usr/bin/rsync --delay-updates -F --compress --archive --rsh=/usr/bin/ssh -S none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null --out-format=<<CHANGED>>%i %n%L /tmp/server/ root@client:/tmp/client/", 
    "msg": ".d..t...... sync_test/\n<f.st...... sync_test/haha.t\n<f+++++++++ sync_test/haha2.tt\n", 
    "rc": 0, 
    "stdout_lines": [
        ".d..t...... sync_test/", 
        "<f.st...... sync_test/haha.t", 
        "<f+++++++++ sync_test/haha2.tt"
    ]
}
  • 单个文件冲突时

默认情况下会以 src 端的数据为准。

  • dest 端有多余文件时

默认情况下会保留 dest 端有,而 src 端没有的文件。可以通过 delete 参数设置为 yes 来删除 dest 端多余的文件。

# ansible test -m synchronize -a "src=/tmp/client/ dest=/tmp/server mode=pull delete=yes"
client | SUCCESS => {
    "changed": true, 
    "cmd": "/usr/bin/rsync --delay-updates -F --compress --delete-after --archive --rsh=/usr/bin/ssh -S none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null --out-format=<<CHANGED>>%i %n%L root@client:/tmp/client/ /tmp/server", 
    "msg": "*deleting   sync_test/other.t\n", 
    "rc": 0, 
    "stdout_lines": [
        "*deleting   sync_test/other.t"
    ]
}
  • 忽略文件
# ansible test -m synchronize -a "src=/tmp/server/ dest=/tmp/client/ rsync_opts='--exclude=sync_test/other.t'"
client | SUCCESS => {
    "changed": true, 
    "cmd": "/usr/bin/rsync --delay-updates -F --compress --archive --rsh=/usr/bin/ssh -S none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null --exclude=sync_test/other.t --out-format=<<CHANGED>>%i %n%L /tmp/server/ root@client:/tmp/client/", 
    "msg": ".d..t...... sync_test/\n", 
    "rc": 0, 
    "stdout_lines": [
        ".d..t...... sync_test/"
    ]
}
  • 源主机有多个时

比如,一个主机组下配置了两个主机,并且都有 同一个目录 /tmp/client/,我们制造一个文件冲突的现场:

主机 1:

# tree
.
├── 21
└── 23

0 directories, 2 files

# ll
total 4
-rw-r--r-- 1 root root 4 Sep  5 11:39 21
-rw-r--r-- 1 root root 0 Sep  5 11:36 23

# cat 21
123

主机 2:

# tree
.
└── 21

0 directories, 1 file

# ll
total 4
-rw-r--r-- 1 liuhao root 4 Sep  5 11:29 21

# cat 21
456

可以看出,文件 21,不仅文件内容不同,文件权限也不同,那我们从两台主机进行拉取时,会得到什么样的结果呢?

执行:

# ansible test -m synchronize -a "src=/tmp/client/ dest=/tmp/server/ mode=pull"
主机1 | SUCCESS => {
    "changed": true, 
    "cmd": "/usr/bin/rsync --delay-updates -F --compress --archive --rsh=/usr/bin/ssh -S none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null --out-format=<<CHANGED>>%i %n%L root@主机1:/tmp/client/ /tmp/server/", 
    "msg": ".d..t...... ./\n>f.st...... 21\n", 
    "rc": 0, 
    "stdout_lines": [
        ".d..t...... ./", 
        ">f.st...... 21"
    ]
}
主机2 | SUCCESS => {
    "changed": true, 
    "cmd": "/usr/bin/rsync --delay-updates -F --compress --archive --rsh=/usr/bin/ssh -S none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null --out-format=<<CHANGED>>%i %n%L root@1主机2:/tmp/client/ /tmp/server/", 
    "msg": ".d..t...... ./\n>f..t.o.... 21\n", 
    "rc": 0, 
    "stdout_lines": [
        ".d..t...... ./", 
        ">f..t.o.... 21"
    ]
}

然后我们看结果:

# ll
total 4
-rw-r--r-- 1 liuhao root 4 Sep  5 11:29 21
-rw-r--r-- 1 root   root 0 Sep  5 11:36 23

# tree
.
├── 21
└── 23

0 directories, 2 files

# cat 21
456

显然,后面执行的主机 2 的文件内容,覆盖了前面主机 1 的文件内容。

注意点

  1. 本地和远程系统必须安装 rsync 包,否则无法使用这个模块;

  2. 对于 synchronize 模块,本地主机是同步任务发起的主机,目标主机是同步时被连接的主机;

  3. 也可以使用 delegate_to 将本地主机更改为其他主机。这样可以在两个远程主机之间进行复制,或者在一台远程机器上执行两个目录的同步。

delegate_to

需要注意的是,使用 delegate_to 授权机进行 synchronize,需要保证授权机能密钥访问远程机。因为 delegate_to 时,使用的帐户权限是授权机的,而非 ansible host 的。

# Synchronization of src on delegate host to dest on the current inventory host.
# 同步『授权机(delegate host)』的 src 目录到远程机器
# 注:需要指定 rsync_opts。
# 参考 https://github.com/ansible/ansible/issues/7250
- synchronize:
    src: /first/absolute/path
    dest: /second/absolute/path
    rsync_opts: '-e "ssh -p  -i /home/delegate_host_user/.ssh/id_rsa"'
  delegate_to: delegate.host
  1. src 的所属用户和权限是本地主机上运行 Ansible 任务的用户和权限(如果配置了 delegate_to,那就是授权机上的 remote_user 的);
  2. dest 的所属用户和权限是目标主机上 remote_user 的用户和权限,如果配置了 become=yes,则为 become_user的;
  3. 即使使用了 sudo, dest=~/x 也会变成 ~<remote_user>/x
  4. 如果 inventory 文件中使用 ansible_ssh_pass 进行用户名密码认证,在使用 synchronize 模块时由于模块使用的是独立的 ssh 通道,因此会再次提示输入密码,在大规模文件下发场景中使用体验较差,可以考虑通过其它途径实现。

和 copy/fecth 的区别

其实有点类似于 rsyncscp 的区别,Rsync 有着更丰富的特性,并且更快捷,当然,Rsync 使用起来相对复杂些,因为参数较多。

总结来看就是:

  • copy 模块不支持从远端到本地的拉去操作,fetch 模块支持,但是 src 参数不支持目录递归,只能回传具体文件;
  • copy 模块的 remote_src 参数是指定从远端服务器上往远端服务器上复制,相当于在 shell 模块中执行 copy 命令;
  • synchronize 则支持文件下发和回传,分别对应的 push 和 pull 模式。synchronize 模块的功能依赖于 rsync,但是功能不依赖于 rsync 配置文件中定义的模块;
  • copy 模块适用于小规模文件操作,synchronize 支持大规模文件操作。
打开App,阅读手记
5人推荐
发表评论
随时随地看视频慕课网APP