読者です 読者をやめる 読者になる 読者になる

treedown’s Report

システム管理者に巻き起こる様々な事象を読者の貴方へ報告するブログです。会社でも家庭でも"システム"に携わるすべての方の共感を目指しています。

rsyncでバックアップ取得している環境でのシンボリックリンクに注意

Linux サーバ 運用管理

シンボリックリンクを過信して失敗してしまいましたので、ご報告します。

rsyncシンボリックリンク参照では動作しない」ここからスタートしました。
今日はいつもより未検証の内容が多いのですがご容赦ください。

概要は

rsyncで参照していたディレクトリをシンボリックリンクにして別のボリュームに移したら、rsyncシンボリックリンクをコピーしてしまってファイルを複製しなくなってしまった、ということです。OH!NO!Misstake。失敗です。
cronでまわしていたコマンドラインはこんな感じです。

 rsync -av --delete --numeric-ids /DIR-A $DEST_DIR
 ※$DEST_DIR変数は別ホストのrsyncd.confでディレクトリが指定されています。

このコマンド中の「/DIR-A」をシンボリックリンクにしたところで、rsyncで複製する対象が、シンボリックリンク先にあるファイル群ではなくシンボリックリンクそのものがバックアップされるようになってしまいました。

発端は

長年運用していると、データが肥大化してパーティションの容量不足になりました。
当然容量追加をしたいところなのですが、データのバックアップを取得して、取得したバックアップを外部バックアップ用サーバへrsyncでコピー同期、という2段階でバックアップ取得を実行していたので、
「じゃあ、このバックアップを格納しているディレクトリだけ新しいパーティション(ボリューム)に移動すれば何にも変更しなくていいよね。」
と考えたのが始まりです。
シンボリックリンクで元ディレクトリのパスを新しいパーティション内のパスにリンクしてやれば、追加ディスクのパーティション内にあるバックアップ用ディレクトリが参照されて結果として容量追加もできてバックアップタスクも滞りなく動作するよね、と考えました。

概要図としてはこんな感じです。
図:ディスク追加した図

f:id:treedown:20151213234848p:plain

 

しかし目論見ははずれ…

rsyncはデフォルトではシンボリックリンクはリンクとしてコピーします。なのでシンボリックリンクで張ったディレクトリ内のデータを丸ごと取得していたバックアップタスクは残念なことにリンクをバックアップするという何とも間抜けなバックアップデータが生成されることに。
さらにrsyncの解釈ではシンボリックリンクはあくまでもファイルなので、リンクを張ったディレクトリの下流にあるデータは複製が生成されません。つまりシンボリックリンクの階層で複製は止まってしまいそれより下層に格納しているデータは同期・コピーが実行されません。

対策の選択肢は二つ

  1. シンボリックリンク経由ではなく実ディレクトリを指定してrsyncを実行するように実行コマンドを編集する
  2. rsync実行オプションを(--keep-dirlinksか--copy-linksに)変更して実行するようコマンドを編集する。

実ディレクトリをパス指定すればそれでことは済む、ということでその対処方法にしました。
シンボリックリンクの数が多い場合にはrsync実行オプションで対処したほうがよさそうです。(今回は採用していません。と、いうのも恥ずかしながらこのオプションを使ったことがないので、検証から始める必要があるのですが、時間の関係で検証に避ける余裕がない状況であります。)

もう一つの選択肢

実は仮説で実際に試したわけではありませんが、ここまでの対策以外に、もう一つの対策がありそれを最初から考慮すればよかった、と思っています。
今回、ディレクトリ丸ごと新しいディスクに移動していますので、「/etc/fstab」を元のディレクトリと同一の名称でマウントする、という方法です。
図:fstabで処理する場合の概要図

f:id:treedown:20151213235034p:plain

# cat /etc/fstab
とすると、ディスクとマウントするディレクトリ一覧が表示されます。(※あくまで例です。
 /dev/hda    /      ext3    defaults    1 1
 /dev/hdb    swap    swap    defaults    0 0
 /dev/hdc    /DIR-A    ext3    defaults    0 0
この「/dev/hdc」が追加したディスクだとするとその隣にあるパス「/DIR-A」がOS内で認識するディレクトリ名=マウントポジションとなります。
fstabで最初からこの「DIR-A」のパスが新規ディレクトリでなく従来から存在して参照されているディレクトリのパス名として入力されていれば、全体の動作として影響があるものではありません。
(ただし、作業中にディレクトリ名が重複しないよう、旧DIR-Aのディレクトリ名は仮のディレクトリ名に変更しておく必要があります。)

追加ディスク/dev/hdcに既存の同名DIR-Aディレクトリを作成しデータ移動してしまえば、ディスク単位でみるとデータ自体は/dev/hdcに移動するが、ディレクトリは同一の「/DIR-A」をfstabで指定しているので、OSから見るとディスクもディレクトリも追加されたわけではなく、あるディレクトリの記憶装置が変更になっただけ、という認識の仕方をするはずです。

これはWindowsだとボリュームはドライブレター単位で割り当てるという基本原則があるので、Windows脳だと混乱しがちです。ちょっと理解するにはLinux脳に切り替える必要があります。
ようするにfstabで指定するということはこんなイメージです。
図:イメージ図

f:id:treedown:20151213235130p:plain


ちょっと乱暴なイメージですが、ディレクトリ名「DIR-A」の領域だけディスクを追加して増やした、というようなイメージで捉えると分かりやすいかもしれません。
つまり、Windowsなら「c:\DIR-A」は追加ディスクE:にパーティションを変更してしまうと「E:\DIR-A」と指定するしかないのですが、Linuxの場合ドライブレターという縛りがないのでデバイスとディレクトリは別に考えてOKです。(重複しなければOK、ということです。)
システムディスク自体は「/」をマウントする必要はありますが、追加ディスクは「/」配下のなんだって指定可能です。なので、今回のような「DIR-A」ディレクトリのように途中のディレクトリを別のHDD上にあるパーティションを指定してマウントすることができる、ということです。

これならOSから見たらディレクトリも変わらないし、rsyncの仕様でリンクの向こう側の取得ができない、という仕様も関知するところではなくなりそうです。

最初からこれを考えることができていれば…。と悔やんでも後の祭り、もう実ディレクトリを参照するようにrsyncの動作コマンドを変更してしまった後でした。

次から気を付けよう。