准备从远程主机上拉取文件,这时我想到了 Ansible 中的 fetch 模块,但是发现 fetch 模块支持远程文件的拉取,而不支持目录!
于是,我就找到了 synchronize
。
synchronize 模块是对 rsync
的封装,实现控制机和目标机之间的数据同步。当然,你也可以在 command 模块中直接调用 rsync 命令,但是 synchronize 对其进行了封装,提供了一些规范化的东西,使用起来更加方便、高效,还可以增量同步。
简单了解下 rsync
rsync 是一个快速且功能非常丰富的文件拷贝工具。它可以在本地和远程之间通过 shell 或 rsync 服务互相拷贝文件。它提供了大量的选项来控制它各方面功能的行为,且在指定待拷贝文件方面非常有弹性。
它以其增量拷贝算法而出名,只拷贝源和目标不同的文件部分,因此减少网络间要传输的数据。rsync 被广泛用于做备份、镜像和当作升级版拷贝命令。
rsync 同步过程中由两部分模式组成:决定哪些文件需要同步的检查模式以及文件同步时的同步模式,也就是先检查哪些要同步,然后再进行同步。
检查模式是指按照指定规则来检查哪些文件需要被同步,例如哪些文件是明确被排除不传输的。默认情况下,rsync 使用
quick check
算法快速检查源文件和目标文件的大小、mtime(修改时间)是否一致,如果不一致则需要传输。当然,也可以通过在r sync 命令行中指定某些选项来改变 quick check 的检查模式,比如--size-only
选项表示仅检查文件大小不同的文件作为待传输文件。rsync 支持非常多的选项,其中检查模式的自定义性是非常有弹性的。同步模式是指在文件确定要被同步后,在同步过程发生之前要做哪些额外工作。例如上文所说的是否要先删除源主机上没有但目标主机上有的文件,是否要先备份已存在的目标文件,是否要追踪链接文件等额外操作。rsync 也提供非常多的选项使得同步模式变得更具弹性。
相对来说,为 rsync 手动指定同步模式的选项更常见一些,只有在有特殊需求时才指定检查模式,因为大多数检查模式选项都可能会影响 rsync 的性能。
总之,rsync 是非常强大的,参数选项非常多,能够实现非常具有弹性的功能,关于更完整更详细的选项说明可以参考:http://www.cnblogs.com/f-ck-need-u/p/7221713.html
synchronize
参数说明
src
:必填,源地址路径dest
:必填,目的地址路径mode
:mode=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 端随便新建一些文件:
1 | # pwd |
- 从远程主机 pull 文件
这时远程主机是源文件。
1 | # ansible test -m synchronize -a "src=/tmp/client/ dest=/tmp/server mode=pull" |
在 server 节点查看,数据已同步到 /tmp/server/ 目录下:
1 | # pwd |
- push 文件
我们在 haha.t 文件中随便输入一些内容,并新建一个文件:
1 | # ll |
需要注意的是,push 时,src 需要填本地目录,dest 填远程主机目录:
1 | # ansible test -m synchronize -a "src=/tmp/server/ dest=/tmp/client/" |
- 单个文件冲突时
默认情况下会以 src 端的数据为准。
- dest 端有多余文件时
默认情况下会保留 dest 端有,而 src 端没有的文件。可以通过 delete
参数设置为 yes
来删除 dest 端多余的文件。
1 | # ansible test -m synchronize -a "src=/tmp/client/ dest=/tmp/server mode=pull delete=yes" |
- 忽略文件
1 | # ansible test -m synchronize -a "src=/tmp/server/ dest=/tmp/client/ rsync_opts='--exclude=sync_test/other.t'" |
- 源主机有多个时
比如,一个主机组下配置了两个主机,并且都有 同一个目录 /tmp/client/
,我们制造一个文件冲突的现场:
主机 1:
1 | # tree |
主机 2:
1 | # tree |
可以看出,文件 21
,不仅文件内容不同,文件权限也不同,那我们从两台主机进行拉取时,会得到什么样的结果呢?
执行:
1 | # ansible test -m synchronize -a "src=/tmp/client/ dest=/tmp/server/ mode=pull" |
然后我们看结果:
1 | # ll |
显然,后面执行的主机 2 的文件内容,覆盖了前面主机 1 的文件内容。
注意点
- 本地和远程系统必须安装 rsync 包,否则无法使用这个模块;
对于 synchronize 模块,
本地主机
是同步任务发起的主机,目标主机
是同步时被连接的主机;也可以使用 delegate_to 将
本地主机
更改为其他主机。这样可以在两个远程主机之间进行复制,或者在一台远程机器上执行两个目录的同步。
需要注意的是,使用 delegate_to
授权机进行 synchronize,需要保证授权机能密钥访问远程机。因为 delegate_to 时,使用的帐户权限是授权机的,而非 ansible host 的。
1 | # Synchronization of src on delegate host to dest on the current inventory host. |
src
的所属用户和权限是本地主机上运行 Ansible 任务的用户和权限(如果配置了 delegate_to,那就是授权机上的 remote_user 的);dest
的所属用户和权限是目标主机上 remote_user 的用户和权限,如果配置了become=yes
,则为 become_user的;- 即使使用了 sudo,
dest=~/x
也会变成~<remote_user>/x
; - 如果 inventory 文件中使用 ansible_ssh_pass 进行用户名密码认证,在使用 synchronize 模块时由于模块使用的是独立的 ssh 通道,因此会再次提示输入密码,在大规模文件下发场景中使用体验较差,可以考虑通过其它途径实现。
和 copy/fecth 的区别
其实有点类似于 rsync
和 scp
的区别,Rsync 有着更丰富的特性,并且更快捷,当然,Rsync 使用起来相对复杂些,因为参数较多。
总结来看就是:
- copy 模块不支持从远端到本地的拉去操作,fetch 模块支持,但是 src 参数不支持目录递归,只能回传具体文件;
- copy 模块的 remote_src 参数是指定从远端服务器上往远端服务器上复制,相当于在 shell 模块中执行 copy 命令;
- synchronize 则支持文件下发和回传,分别对应的 push 和 pull 模式。synchronize 模块的功能依赖于 rsync,但是功能不依赖于 rsync 配置文件中定义的模块;
- copy 模块适用于小规模文件操作,synchronize 支持大规模文件操作。