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

SSHとファイル転送

scpとrsyncとsftp、いつ何を

TT Labで続きを見る

一言でいうと

3つのツールはどれもSSHチャネルの上で動きます。違いは、一度にすべて送るか(scp)、差分だけを送るか(rsync)、対話するようにやり取りするか(sftp)です。

なぜ必要なのか

ファイル1つを移すのにツールが3つもあるのには、理由があります。100MBのファイル1つを初めて送るときと、10GBのディレクトリを毎日同期するときと、サーバー上のファイル一覧を見ながら選んで取得するときとでは、必要な性質が違います。

どう動くのか

scp: 単純なコピー

scp -P 2222 -i ~/.ssh/id_ed25519 ./app.tar.gz root@127.0.0.1:/tmp/
scp -r ./dist root@host:/srv/app/
scp -p ./config.yaml root@host:/etc/app/       # mtime/권한 보존
scp root@host:/var/log/app.log ./              # 내려받기

注意点が2つあります。

scpは再開できません。90%で切れたら、最初からやり直しです。そのため、大きな転送には向きません。

rsync: 差分だけを送る

rsync -aHAX --numeric-ids --delete --dry-run /srv/data/ backup@host:/backup/data/
rsync -avz -e 'ssh -p 2222 -i ~/.ssh/id_labhub' ./dist/ root@127.0.0.1:/srv/app/

オプションの正確な意味を知っておく必要があります。

そして、末尾のスラッシュの規則。これがrsyncで最も間違えやすいところです。

rsync -a /srv/data  /backup/    # /backup/data/... 가 만들어진다
rsync -a /srv/data/ /backup/    # /backup/... 에 내용이 바로 들어간다

元のパスの末尾のスラッシュは「このディレクトリの内容をコピーする」、ない場合は「このディレクトリ自体をコピーする」という意味です。

--deleteは破壊的です。元が空だったり、マウントが外れた状態で実行されたりすると、対象のデータをすべて消します。実務で実際によく起きる事故です。スクリプトには、必ずガードを入れます。

set -euo pipefail
[ "$(ls -A "$SRC" | wc -l)" -gt 0 ] || { echo "source empty, abort" >&2; exit 1; }
rsync -aHAX --numeric-ids --delete "$SRC/" "$DST"

世代バックアップは、ハードリンクで安く作れます。

rsync -aHAX --delete --link-dest=/backup/daily.1 /srv/data/ /backup/daily.0/

--link-destは、変更されていないファイルをコピーする代わりに、指定したディレクトリのファイルへハードリンクを張ります。各世代が完全なスナップショットのように見えますが、ディスクは変更分だけを占めます。

sftp: 対話型/バッチ

sftp -P 2222 -i ~/.ssh/id_labhub root@127.0.0.1
sftp -b /root/batch.txt -P 2222 root@127.0.0.1

バッチファイルにcd、put、get、ls、mkdirを書いておくと、非対話で実行されます。パートナー企業とファイルをやり取りする自動化では、今でも多く使われています。ChrootDirectory + ForceCommand internal-sftpの組み合わせで、シェルのない転送専用アカウントを作れることも、sftpの強みです。

現場での姿

世代バックアップを、ハードリンクを知らないツールでコピーして、容量が3倍になる事故。--link-destで節約した領域が、1回のコピーで吹き飛びます。-Hは-aに含まれないので、必ず別に指定する必要があります。

帯域を使い果たして、サービスを妨げるバックアップ。--bwlimit=50Mとionice -c 3 nice -n 19の組み合わせで、優先度を下げます。バックアップが運用を妨げなければ、かえって周期を短くする余裕が生まれます。

次のラボですること

2つのラボを続けて行います。まず、scpとsftpでファイルを往復させて、チェックサムで完全性を確認します。そのあと、rsyncで末尾のスラッシュの違い・--deleteのガード・--link-destの世代バックアップを自分で作ります。