rsync | ||
---|---|---|
HOME |
主にバックアップを目的とした rsync の実装方法について述べる。バックアップサーバ上で rsyncデーモンを待機させ、クライアントからファイルを同期できるようにする。rsyncデーモンは xinetd から起動するのが基本だが、よりダイハードでコントローラブルにするため、ここでは Upstart を利用して起動を制御する方法を紹介する。検証は RHEL/CentOS 6.6, CentOS 7.2 で行なった。
rsyncd というものは存在しない。クライアントとして使うのと同じ rsync コマンドに、--daemon オプションを与えるとデーモンとしての待機モードで起動するというだけだ。この時、rsyncデーモンは /etc/rsyncd.conf から設定を読み込む。既定ではこれだが、起動オプション --config=/PATH/TO/CONF を指定すれば変えることも可能。
rsyncd.conf の内容はグローバルコンテキストとモジュールブロックに別れる。モジュールとは、SMBやNFSv4の共有名と同種のもので、下記の例ではサーバの /backupshares/bakshare/ に "SERVER::bakshare/" でアクセスできることになる。モジュールブロックで指定できるディレクティブはグローバルコンテキストでも指定でき、グローバル指定は各モジュールの既定値として働き、モジュールブロック内での指定はグローバル設定をオーバーライドする。幾つかグローバルコンテキストでしか使用できないディレクティブもあるが下記では使用していない。
ディレクティブは `name = value' の形。`=' の直前/直後のスペースは無視されるので入れても入れなくても構わない。ブーリアン(真偽)値は yes/no の他 0/1, true/false も通用する。先頭に # を置けばその行はコメントと解釈されるが、`name = var #comment' という風に途中からコメントにすることはできない。
uid = root (1) gid = root max connections = 10 timeout = 600 (2) use chroot = yes (3) strict modes = yes (4) [bakshare] path = /backupshares/./bakshare (5) read only = no list = no (6) auth users = rsyncusr, rsyncusr2 (7) secrets file = /etc/rsync.pwd (8) hosts allow = 127.0.0.1, 192.168.1.0/24 (9) transfer logging = yes (10)
ディレクティブ | 説明 | |
(1) | uid gid | 転送に使用するシステムアカウント権限。当例はシステム系設定ファイルも含むバックアップが目的なので、あらゆるオーナーのファイル属性ビットが忠実に保持できるよう root とする。既定は nobody nobody。 |
(2) | timeout | クライアントからのI/Oリクエストタイムアウト(秒)。既定は0つまり無限に待ち続けてしまう。 |
(3) | use chroot | モジュールpathへchrootするかどうか。yes にするには rsyncデーモンは root で起動されなければならない(上記の転送ユーザ指定 uid, gid と混同するな)。 |
- | numeric ids | ファイル転送の中でファイルやディレクトリのオーナー/グループを名前でなく数値表現のuid/gidのまま遣り取りする。rsyncクライアントとサーバとで存在するユーザ/グループとそれらのuid/gidが統一されていれば `numeric id=no' でも気にする必要はないのだが、そうでない場合、例えばクライアント側のhogeのuidが500でサーバ側では501という環境では、オーナーhogeのファイルがサーバ上へはuid=501となって格納されてしまう。`use chroot=no' の時の既定値はnoつまり名前ベースだが、`use chroot=yes'時は既定値が暗黙的にyesとなる。chroot環境でユーザ名解決をするには環境内に etc/passwd, group ファイルなどが要ることを忘れずに。chroot環境の整備については vsftpd の記事をご参考に。 |
(4) | strict modes | (8)のパスワードファイルが rsyncデーモン起動ユーザ以外の読めるパーミッションになっていないかチェックする。 |
- | log file | rsyncに自力でログファイル出力をさせたい場合はそのPATHを指定。既定ではsyslogに送られる。 |
- | log facility | syslog送信の場合のログファシリティ。既定は daemon。 |
(5) | path | モジュールにマッピングするファイルシステムPATH。`use chroot=yes' の場合、例のようにドット・スラッシュを入れると、/backupshares/ へ chroot して bakshare へ cd する動きとなり、後述する logソケットの配備などに都合がよい。 |
(6) | list | list=no とすることにより、クライアントからのモジュール一覧取得命令にこのモジュールを開示しないようにする。 |
(7) | auth users | 接続を許可する rsyncユーザ。ここで言うユーザはシステムアカウントとは無関係で、次の secrets file 内で定義するrsync固有のもの。複数指定する場合はスペースまたはカンマで区切る。 |
(8) | secrets file | rsyncユーザのユーザ名とパスワードのリスト。`strict modes=yes' の時はファイルのパーミッションは 600 でなくてはならない。 |
(9) | hosts allow | 接続を許可するクライアントホストのリスト。複数指定する場合はスペースまたはカンマで区切る。IP, IP/PREFIX, IP/MASK, ホスト名(ワイルドカード使用可)が使用可能で、ホスト名の場合は、接続してきたIPからリバースルックアップによってホスト名を牽いてチェックされる。 |
- | hosts deny | 接続を拒否するクライアントホストのリスト。通常 `hosts allow' しか指定しない方がよい。両方設定されている場合は、先に allow が評価されてマッチすれば即許可、allow にも deny にもヒットしないホストは許可される。 |
(10) | transfer logging | 読んで字の如し。`use chroot=yes' の場合は chroot先にlogソケットを作っておく必要がある(後述)。 |
上記 `secrets file' で指定したパスにユーザリストを作成し、rsyncデーモン起動システムユーザだけの読めるパーミッションにしておく。当例だと /etc/rsync.pwd (root:root 600) の内容はこんな塩梅。
rsyncusr:hispassword rsyncusr2:herpassword
/etc/rsyslog.conf を調整。ただし、Systemd管理のシステム(RHEL/CentOS 7など)で rsyncd も systemd で駆動する場合は、journald だけでログを扱う限りは調整は不要だ。
既定のローカルログフィルタ(/var/log/messsagesなど)より手前に、下記のフィルタを挿入する。
if $programname startswith 'rsync' then -/var/log/rsyncd.log
& ~ <-rsyslog v7の場合は `& stop' と書くべき
rsyncd.conf で chroot を有効にしている場合には、chroot先ディレクトリに syslogソケットを作っておくべき。なくても基本的なログは出るが、転送ログが出力できない。先に /backupshares/dev ディレクトリ (root:root 755) を作成してから、rsyslog.conf を修正。
$ModLoad imuxsock <-既定で存在するこの記述の後あたりに、
$AddUnixListenSocket /backupshares/dev/log
rsyncd.conf のモジュールの path 指定に ./ を入れたのはこのためだ。他のモジュールも /backupshares/ の配下に置く限り、モジュール追加の度に logソケットを追加しなくて済む。
`service rsyslog restart' して /backupshares/dev/log ファイルができたことを確認。
rsyslogのデフォルトでは、syslogのUNIXソケットは入力レコードが 5秒間あたり 200メッセージを超えると Rateリミットが作動してメッセージを破棄するようになっている。Rateリミットが働くと messages に報告される。rsync は非常に高速にファイルを処理するので、rsyncd.conf で transfer logging = yes としている場合、これに引っかかることが多々ある。まずは、レートを倍にすることから始めて、調整するとよい。SystemLogRateLimit* は imuxsock モジュールのオプションなので、 rsyslog.conf の "$ModLoad imuxsock" ディレクティブより後、なお且つどのログ振り分けルールよりも前に書かなくてはいけない。
# $SystemLogRateLimitInterval 5 $SystemLogRateLimitBurst 400
上記は実は古い書き方で、rsyslog7 からの新しい設定書式で書くなら、デフォルト設定ファイルの "$ModLoad imuxsock" 行を下記のように丸ごと置き換える。
module(load="imuxsock" SysSock.RateLimit.Interval="5" SysSock.RateLimit.Burst="400")
これでもまだ破棄されるようであれば、~Burst値をもっと増やすか、逆に、単位時間を 3秒や 2秒のように短くするかしてさらに調整。rsyslog の新しい書式についてもっとよく知りたい輩は rsyslogのページをご参照いただきたい。
rsyncデーモンの待機動作の面で、やり方は大きく分けてふたつに別れる。
rsync の設計からすると、どちらかといえば前者の子プロセスを起こすパターンの方が適切な気がする。後者では、rsyncd.conf でログを自力でファイルへ直接書くように設定 している場合、複数のクライアントがつないで来た時に問題が起こるのではなかろうか。
/etc/init ディレクトリに root:root 644 で rsyncd.conf というJobファイルを作成する。
# rsyncd - rsync server daemon # # Starts rsync daemon start on started rc RUNLEVEL=[2345] stop on started rc RUNLEVEL=[S016] console output respawn respawn limit 10 120 exec /usr/bin/rsync --daemon --no-detach
respawn なので不意に落ちたらまた立ち上げられるが、limit により、120秒以内に 10回死んだら再立ち上げはされなくなる。肝は、rsyncコマンドに追加した `--no-detach' オプションだ。これを付けることによって rsync は、デーモンモードでありながら fork() することなくフォアグラウンドのままになる。同じことは、下の書き方でも実装できる - fork() させないか fork() を Upstart に追いかけさせるかの違いだけだ。2回 fork() することを期待する `expect daemon' ではダメだった。
# rsyncd - rsync server daemon # # Starts rsync daemon start on started rc RUNLEVEL=[2345] stop on started rc RUNLEVEL=[S016] console output expect fork respawn respawn limit 10 120 exec /usr/bin/rsync --daemon
ジョブファイルができたら、
root# initctl reload-configuration root# start rsyncd root# status rsyncd
tcpserverのページを参照のこと。ルールファイルは作らなくていい(より厳重にするなら作ってもいいが)。
/etc/init ディレクトリに root:root 644 で rsyncd.conf というJobファイルを作成する。
# rsyncd - rsync server daemon # # Starts rsync daemon start on started rc RUNLEVEL=[2345] stop on started rc RUNLEVEL=[S016] console output respawn respawn limit 10 120 exec /usr/local/bin/tcpserver -H -R -v -l0 0 rsync /usr/bin/rsync --daemon
この設定により、rsyncの既定TCPポート 873 で待ち受ける tcpserver が立ち上がる。respawn なので不意に落ちたらまた立ち上げられるが、limit により、tcpserver が 120秒以内に 10回死んだら再立ち上げはされなくなる。ジョブファイルができたら、
root# initctl reload-configuration root# start rsyncd root# status rsyncd
rsyncパッケージがインストールしてあれば /usr/lib/systemd/system/ に rsyncd.service がインストールされているので、これを /etc/systemd/system/ へコピー (root:root 644) して土台にする。ほとんどいじる必要もない。敢えて言うなら CGroup によるリソース制限を掛けてやるくらいだ。
[Unit]Description=fast remote file copy program daemon ConditionPathExists=/etc/rsyncd.conf [Service] CPUShares=2048 MemoryLimit=200M EnvironmentFile=/etc/sysconfig/rsyncd ExecStart=/usr/bin/rsync --daemon --no-detach "$OPTIONS" [Install] WantedBy=multi-user.target
# systemctl daemon-reload # systemctl start rsyncd.service # systemctl enable rsyncd.service
ちなみに、/usr/lib/systemd/system/ には、xinetd的にソケットで待ち受けてサービスへ引き渡す構造のユニットファイルセットも用意されている。そちらの方式を使ってみたい人は、rsyncd.socket ファイルと rsyncd@.service ファイルを /etc/systemd/system/ へそのままの名前でコピーし、rsyncd.socket の方を start および enable すればよい。ああ、IPv6を殺している人は rsyncd.socket の ListenStream=873 を ListenStream=0.0.0.0:873 と変えないと動かないことを申し添えておこう。
rsyncサーバ側でユーザ認証を掛けているので、接続の際にはパスワードを指定しなくてはならない。コマンドラインでその都度指定するか対話式でタイプしてもいいのだが、パスワードファイルを作っておくとスクリプト化する時に便利だ。当例ではrsyncクライアントを root で使うので root 権限で、
root# echo hispassword >~/.rsync.pwd root# chmod 600 ~/.rsync.pwd
rsyncサーバのIPが 192.168.1.1 だとすると、こんな塩梅。--password-file の引数は相対パスでもOKなのだが、~/.rsync.pwd とやるとチルダが展開されずに "No such file" エラーになってしまう。
root# rsync -azc --delete --password-file /root/.rsync.pwd \
/my/srcdir/ rsyncusr@192.168.1.1::bakshare/destdir/
URL は "protocol://" の形式でも指定できる。そちらで書くと、
root# rsync -azc --delete --password-file /root/.rsync.pwd \
/my/srcdir/ rsync://rsyncusr@192.168.1.1/bakshare/destdir/