rsync はファイルを別のディレクトリやリモートのホストと同期させるためのプログラムだ。 例えば rsync の代わりに cp コマンドを使った場合、宛先の状態に関わらず全てのファイルがコピーされてしまう。 それに対し rsync では、宛先の状態を確認して異なる箇所 (差分) だけをコピーするため効率が良い。
今回はその rsync を使ってみよう。 検証の環境には CentOS7 を使った。
$ cat /etc/redhat-release CentOS Linux release 7.1.1503 (Core) $ uname -r 3.10.0-229.11.1.el7.x86_64
rsync をインストールする
rsync がインストールされていない場合は yum を使って入れる。 基本的には最初から入っているはず。
$ sudo yum -y install rsync
同じホストの中でシンプルに使ってみる
まずは同じホストで、異なるディレクトリを使って動作を確認しよう。 コピー元とコピー先のディレクトリを作っておく。
$ mkdir from to
コピー元となるディレクトリにファイルを用意する。
$ cat << EOF > from/sample.txt Hello, World EOF
準備ができたら rsync コマンドを実行する。
$ rsync -av from/ to/ sending incremental file list ./ sample.txt sent 123 bytes received 34 bytes 314.00 bytes/sec total size is 13 speedup is 0.08
オプションの意味は次の通り。
オプション | 意味 |
---|---|
-a | -rlptgoD と同意 (アーカイブモードと呼ばれる) |
-v | 処理内容の詳細を表示する |
-r | 再帰的にディレクトリを走査する |
-l | シムリンクをシムリンクとしてコピーする |
-p | パーミッションを維持する |
-t | 変更時間を維持する |
-g | グループを維持する |
-o | オーナーを維持する |
-D | --devices --specials と同意 (デバイスファイルを維持する) |
実行するとコピー先のディレクトリにファイルができる。
$ cat to/sample.txt Hello, World
もちろん、コピー元のファイルに変更を加えた上で再度実行すればその内容が同期される。
$ sed -i -e "s:World:Rsync:g" from/sample.txt $ rsync -av from/ to/ sending incremental file list ./ sample.txt sent 123 bytes received 34 bytes 314.00 bytes/sec total size is 13 speedup is 0.08 $ cat to/sample.txt Hello, Rsync
では、コピー元のファイルを削除するとどうなるだろうか?
$ rm from/sample.txt $ rsync -av from/ to/ sending incremental file list ./ sent 48 bytes received 15 bytes 126.00 bytes/sec total size is 0 speedup is 0.00
今度は rsync を実行してもファイルが残ったままになっている。
$ ls to/ sample.txt
ファイルの削除も反映するには --delete オプションをつける必要がある。 これはコピー元とコピー先を完全に同期することになる。
$ rsync -av --delete from/ to/ sending incremental file list deleting sample.txt sent 45 bytes received 12 bytes 114.00 bytes/sec total size is 0 speedup is 0.00 $ find to to
同期に含めたくないファイルがある場合
コピー元のディレクトリの中に同期したくないファイルが存在することもあるはず。 試しに exclude.txt というファイルを同期から除外する対象にしてみよう。
$ ls from/ exclude.txt sample.txt
同期したくないものについては --exclude オプションでファイル名のパターンを指定する。
$ rsync -av --exclude='exclude.*' from/ to/ sending incremental file list ./ sent 71 bytes received 15 bytes 172.00 bytes/sec total size is 13 speedup is 0.15
exclude という名前のファイルを同期の対象から除外しているのでコピー先には exclude.txt が同期されない。
$ ls to/ sample.txt
実行前に何が起こるかを確認する
実際に同期する前に、コマンドを叩くことで何が起こるかを確認したい場合は -n (--dry-run) オプションを付けて実行すると良い。
$ rsync -avn from/ to/ sending incremental file list exclude.txt sent 91 bytes received 15 bytes 212.00 bytes/sec total size is 13 speedup is 0.12 (DRY RUN)
ドライ・ランでは実際の処理は実行されないためコピー先のディレクトリに変化はない。
$ ls to/ sample.txt
--include オプションは --exclude オプションと併用する
rsync はコピー元ディレクトリを丸ごと同期するので --include オプションは単体で使っても特に意味がない。 --exclude オプションで同期対象から除外した中で、これだけは特別に同期したいといったものを指定するのに使う。
$ rsync -av --include='sample.txt' from/ to/ sending incremental file list exclude.txt sent 127 bytes received 31 bytes 316.00 bytes/sec total size is 13 speedup is 0.08 $ ls to exclude.txt sample.txt
リモートホストと同期してみる
ここまでは同じホスト内でディレクトリを同期させていたけど、それよりはリモートホストとの間で同期させる方が使用場面が多いはず。 何故なら rsync は複数のホストの間でファイルの状態を同期させたり、あるいはバックアップを取る目的で使われることが多いため。 今回は 192.168.33.12 という IP アドレスを持ったホストとディレクトリを同期させてみる。
$ ping -c 3 192.168.33.12 PING 192.168.33.12 (192.168.33.12) 56(84) bytes of data. 64 bytes from 192.168.33.12: icmp_seq=1 ttl=64 time=0.530 ms 64 bytes from 192.168.33.12: icmp_seq=2 ttl=64 time=0.321 ms 64 bytes from 192.168.33.12: icmp_seq=3 ttl=64 time=0.316 ms --- 192.168.33.12 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.316/0.389/0.530/0.099 ms
パスワード認証は面倒なので、まずは公開鍵を作って設置することにしよう。 ssh-keygen コマンドで公開鍵ペアを作っておく。
$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/vagrant/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/vagrant/.ssh/id_rsa. Your public key has been saved in /home/vagrant/.ssh/id_rsa.pub. The key fingerprint is: d0:7b:f3:0e:df:a0:4b:c4:fd:bc:68:ad:9f:cf:9c:ae vagrant@localhost.localdomain The key's randomart image is: +--[ RSA 2048]----+ | | | . | | . . | | . o . | | S = . | | o o o | | o o.o | | . =.+.=.| | oo=EB++| +-----------------+
ssh-copy-id コマンドを使って、生成した公開鍵をリモートホストに登録する。
$ sudo yum -y install openssh-clients $ ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.33.12 The authenticity of host '192.168.33.12 (192.168.33.12)' can't be established. ECDSA key fingerprint is 0e:ae:85:dc:52:d7:70:4d:fd:6f:9a:f7:0c:2f:a9:99. Are you sure you want to continue connecting (yes/no)? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys vagrant@192.168.33.12's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh '192.168.33.12'" and check to make sure that only the key(s) you wanted were added.
これで準備はできた。 あとは rsync コマンドでこれまでコピー先に指定していたディレクトリの前部分にリモートホストの IP アドレスを : (コロン) と一緒に付けるだけ。
$ rsync -av /tmp/from/ 192.168.33.12:/tmp/to/ sending incremental file list created directory /tmp/to ./ exclude.txt sample.txt sent 186 bytes received 53 bytes 478.00 bytes/sec total size is 13 speedup is 0.05
ssh コマンドを使って確認すると、ちゃんとディレクトリの内容が同期されていることが分かる。
$ ssh 192.168.33.12 "find /tmp/to" /tmp/to /tmp/to/exclude.txt /tmp/to/sample.txt
リモートホストと同期する際の注意点
リモートホストと同期する場合には、リモートホストにも rsync がインストールされている必要がある。 もし rsync がない場合には、以下のようにエラーになってしまうので注意が必要だ。
$ rsync -av /tmp/from/ 192.168.33.12:/tmp/to/ bash: rsync: コマンドが見つかりません rsync: connection unexpectedly closed (0 bytes received so far) [sender] rsync error: remote command not found (code 127) at io.c(605) [sender=3.0.9]
まとめ
今回は rsync を使ってファイルを効率的に同期する方法について書いた。 rsync は複数ホストの間でファイルの状態を同期したり、あるいはファイルのバックアップにと様々な場面で使われる。 また、MySQL をマルチマスタで冗長化できる Galera Cluster においても、変更内容の転送部分に rsync が使われていたりする。 このように、rsync はホストを管理する上で重要なプログラムなので使い方は覚えておきたい。