TT Lab
はじめる
学ぶ 学習パス コース

SSHとファイル転送

rsyncで同期する

TT Labで続きを見る

目標

rsyncの核心的なオプションを、手で確認します。特に、末尾のスラッシュの規則、--deleteの危険とガード、--link-destの世代バックアップの3つを、自分で作ります。

なぜ重要なのか

rsyncは、最もよく使われ、最もよく間違えられるツールです。-aがACL・拡張属性・ハードリンクを含まないこと、元のパスの末尾のスラッシュ1つがディレクトリの深さを変えること、--deleteが元が空のときに対象を全滅させること。この3つは、すべて実際の事故につながったことがあります。--link-destは、逆にrsyncの最も美しい機能です。各世代が完全なスナップショットのように見えながら、ディスクは変更分だけを占めます。

ステップ

  1. /root/sync/srcの下に、次のものを作成してください。app/main.py、app/util.py、conf/app.yaml、logs/app.log、logs/error.log。各ファイルには、任意の内容を1行以上入れてください。
  2. /root/sync/src/を/root/sync/dst1/へ同期するdry-runを、変更内容の表示付きで実行して、/root/sync/dryrun.txtに保存してください。
  3. 同じ同期を、SSH経由で実際に実行してください。宛先はroot@127.0.0.1:/root/sync/dst1/で、ポートは2222、鍵は/root/.ssh/id_labhubです。完了後、/root/sync/dst1/app/main.pyが存在する必要があります。
  4. 末尾のスラッシュの違いを実証してください。/root/sync/src(スラッシュなし)を/root/sync/dst2/へ送ると、/root/sync/dst2/src/app/main.pyができる必要があります。
  5. /root/sync/backup.shスクリプトを作成してください。set -euo pipefailで始め、元が空なら終了コード1で中断する検査を含め、--deleteを使って/root/sync/src/を/root/sync/dst3/へ同期する必要があります。元のパスは第1引数で受け取り、引数がなければ/root/sync/src/を使います。採点ツールが、空のディレクトリを第1引数として渡して、ガードが実際に動作するかを確認します。スクリプトを実行して、/root/sync/dst3を作成してください。
  6. logs/の下を除外して、/root/sync/src/を/root/sync/dst4/へ同期してください。/root/sync/dst4/logsは存在してはいけません。
  7. 世代バックアップを作成してください。まず/root/sync/gen/daily.1/へ全体を同期し、そのあと--link-destで/root/sync/gen/daily.0/を作成してください。変更されていないファイルは、2つの世代が同じinodeを共有する必要があります。
  8. /root/sync/final.txtを次の3行で作成してください。 PENDING=<3번과 같은 동기화를 다시 dry-run 했을 때 전송 예정 파일 수> / DST4_HAS_LOGS=no / SHARED_INODE=yes(プレースホルダーは、ステップ3と同じ同期をもう一度dry-runしたときの、転送予定のファイル数です) PENDINGは0である必要があります。

参考

元のツリーの作成

/root/sync/srcの下に、次のものを作成してください。app/main.py、app/util.py、conf/app.yaml、logs/app.log、logs/error.log。各ファイルには、任意の内容を1行以上入れてください。

サブディレクトリとログファイルを混ぜておくと、後のステップの除外ルールが意味を持ちます。

まずシミュレーション

/root/sync/src/を/root/sync/dst1/へ同期するdry-runを、変更内容の表示付きで実行して、/root/sync/dryrun.txtに保存してください。

実際には変更せず、何が変わるかだけを表示するオプションと、変更内容を1行ずつ表示するオプションを、一緒に使います。

SSH経由で実際に同期

同じ同期を、SSH経由で実際に実行してください。宛先はroot@127.0.0.1:/root/sync/dst1/で、ポートは2222、鍵は/root/.ssh/id_labhubです。完了後、/root/sync/dst1/app/main.pyが存在する必要があります。

rsyncには、リモートシェルのコマンドを丸ごと指定するオプションがあります。ポートと鍵を、その中に入れてください。

末尾のスラッシュの違いの実証

末尾のスラッシュの違いを実証してください。/root/sync/src(スラッシュなし)を/root/sync/dst2/へ送ると、/root/sync/dst2/src/app/main.pyができる必要があります。

同じ元を、スラッシュの有無だけを変えて2つの宛先にそれぞれ送り、結果の構造を比較してください。

ガード付きの--delete

/root/sync/backup.shスクリプトを作成してください。set -euo pipefailで始め、元が空なら終了コード1で中断する検査を含め、--deleteを使って/root/sync/src/を/root/sync/dst3/へ同期する必要があります。元のパスは第1引数で受け取り、引数がなければ/root/sync/src/を使います。採点ツールが、空のディレクトリを第1引数として渡して、ガードが実際に動作するかを確認します。スクリプトを実行して、/root/sync/dst3を作成してください。

元が空ならすぐに中断する検査を、スクリプトの先頭に入れてください。set -euo pipefailも一緒に。

除外ルールの適用

logs/の下を除外して、/root/sync/src/を/root/sync/dst4/へ同期してください。/root/sync/dst4/logsは存在してはいけません。

除外パターンは、複数回指定することも、ファイルから読み込むこともできます。ログファイルが宛先にない必要があります。

ハードリンクによる世代バックアップ

世代バックアップを作成してください。まず/root/sync/gen/daily.1/へ全体を同期し、そのあと--link-destで/root/sync/gen/daily.0/を作成してください。変更されていないファイルは、2つの世代が同じinodeを共有する必要があります。

--link-destは、相対パスで指定すると、宛先を基準に解釈されます。絶対パスが安全です。確認は、statのリンク数で行います。

同期完了の証明

/root/sync/final.txtを次の3行で作成してください。 PENDING=<3번과 같은 동기화를 다시 dry-run 했을 때 전송 예정 파일 수> / DST4_HAS_LOGS=no / SHARED_INODE=yes(プレースホルダーは、ステップ3と同じ同期をもう一度dry-runしたときの、転送予定のファイル数です) PENDINGは0である必要があります。

正しく同期されたなら、同じコマンドをもう一度dry-runで実行したとき、転送するものがない必要があります。