rsyncで効率的なファイル同期
要件と前提
rsyncコマンドを用いてリモートサーバー間でファイルを効率的かつ安全に同期するためのDevOpsプラクティスを解説します。具体的には、以下の要件を満たすことを目指します。
効率性: 差分転送によりネットワーク帯域と時間を節約します。
安全性: シェルスクリプトは冪等性を保ち、エラーハンドリングを適切に行い、一時ファイルを安全に扱います。
自動化:
systemd unitとsystemd timerを用いて定期的な同期を自動化します。拡張性:
jqを用いたJSONデータの処理や、curlを用いたAPI連携の例を示します。権限管理:
root権限の適切な扱いと権限分離について考慮します。
前提条件:
Linux環境(Ubuntu/CentOSなど)が動作していること。
rsync,bash,systemd,jq,curlがインストールされていること。SSH鍵認証が設定されており、パスワードなしでリモートサーバーに接続できること。
実装
フローの概要
systemd timerによって定期的にrsync実行サービスが起動される流れを図1に示します。
graph TD
A["systemd Timer"] -- 定期実行をスケジュール --> B("systemd Service");
B -- サービス起動コマンド実行 --> C{"Bashスクリプト"};
C -- SSH経由でファイルを転送 --> D("rsyncコマンド");
D -- ファイル同期を処理 --> E["リモートサーバー"];
C -- 実行結果を出力 --> F["ログファイル"];
C -- 処理結果を通知 (JSON形式) --> G["監視システム/API"];
図1: rsync同期処理フロー
rsync実行スクリプトの作成
rsyncを実行するシェルスクリプトは、冪等性を保ち、エラー時に適切に終了し、一時ファイルを安全に扱う必要があります。
#!/usr/bin/env bash
# rsync_sync.sh: 安全なrsyncファイル同期スクリプト
# 1. 厳格なエラーハンドリングとパイプ失敗時の即時終了
set -euo pipefail
# 2. 一時ディレクトリの安全な作成とクリーンアップ
# trapコマンドでスクリプト終了時に必ず一時ファイルを削除
RSYNC_TMPDIR=$(mktemp -d -t rsync-tmp-XXXXXXXXXX)
trap 'rm -rf "${RSYNC_TMPDIR}"' EXIT SIGHUP SIGINT SIGTERM
# ログファイルパス
LOG_DIR="/var/log/rsync"
LOG_FILE="${LOG_DIR}/rsync_sync_$(date +%Y%m%d%H%M%S).log"
exec > >(sudo tee -a "${LOG_FILE}") 2>&1
echo "$(date '+%Y-%m-%d %H:%M:%S JST') - INFO: rsync同期処理を開始します。"
echo "一時ディレクトリ: ${RSYNC_TMPDIR}"
# 設定変数
SOURCE_DIR="/path/to/local/source/" # 同期元ローカルディレクトリ
REMOTE_USER="remote_user" # リモートサーバーのユーザー
REMOTE_HOST="remote.example.com" # リモートサーバーのホスト名
DEST_DIR="/path/to/remote/destination/" # 同期先リモートディレクトリ
# rsyncオプション
RSYNC_OPTIONS="-avz --delete --exclude 'tmp/' --partial-dir='${RSYNC_TMPDIR}'"
# rsyncコマンドの実行
if ! rsync ${RSYNC_OPTIONS} "${SOURCE_DIR}" "${REMOTE_USER}@${REMOTE_HOST}:${DEST_DIR}"; then
echo "$(date '+%Y-%m-%d %H:%M:%S JST') - ERROR: rsync同期に失敗しました。"
MESSAGE="rsync同期が ${REMOTE_HOST} で失敗しました。"
PAYLOAD=$(jq -n \
--arg msg "${MESSAGE}" \
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'{ "status": "failed", "message": $msg, "timestamp": $timestamp }')
if ! curl -sS --retry 5 --retry-delay 5 --retry-max-time 60 \
--fail-silent --show-error --tlsv1.2 \
-H "Content-Type: application/json" \
-d "${PAYLOAD}" "https://api.example.com/notifications"; then
echo "$(date '+%Y-%m-%d %H:%M:%S JST') - ERROR: 監視システムへの通知に失敗しました。"
else
echo "$(date '+%Y-%m-%d %H:%M:%S JST') - INFO: 監視システムへ失敗を通知しました。"
fi
exit 1
fi
echo "$(date '+%Y-%m-%d %H:%M:%S JST') - INFO: rsync同期処理が正常に完了しました。"
exit 0
コード1: rsync_sync.sh
コードのポイント:
set -euo pipefail: エラー発生時の即時終了、未定義変数の禁止、パイプ中のエラー伝播を強制します。mktemp -d: 一時ディレクトリを安全に作成します。trap 'rm -rf "${RSYNC_TMPDIR}"' EXIT: スクリプト終了時に一時ディレクトリを確実に削除します。rsyncオプション(-avz,--delete,--exclude,--partial-dir)により効率的かつ安全な差分転送を実現します。
systemd unitとtimerの定義
systemdを用いて、上記のスクリプトを定期的に実行するように設定します。
1. rsync-sync.service ファイル (/etc/systemd/system/rsync-sync.service)
[Unit] Description=rsync based file synchronization service Documentation=https://example.com/docs/rsync-sync-service-info Wants=network-online.target After=network-online.target [Service] User=rsync_user Group=rsync_user WorkingDirectory=/opt/rsync-scripts Type=oneshot ExecStart=/bin/bash /opt/rsync-scripts/rsync_sync.sh Restart=no StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target
コード2: rsync-sync.service
2. rsync-sync.timer ファイル (/etc/systemd/system/rsync-sync.timer)
[Unit] Description=Run rsync file synchronization every 1 hour Documentation=https://example.com/docs/rsync-sync-timer-info [Timer] OnCalendar=*-*-* *:30:00 AccuracySec=1min Persistent=true Unit=rsync-sync.service [Install] WantedBy=timers.target
コード3: rsync-sync.timer
検証
systemdの設定を反映し、タイマーを有効化して動作を確認します。
スクリプトと
systemdファイルの配置と権限設定:rsync_sync.shを/opt/rsync-scripts/に配置し、実行権限を付与します。専用ユーザー(
rsync_user)の作成と権限設定を行います。
systemd設定のリロードとタイマー有効化:sudo systemctl daemon-reload sudo systemctl enable --now rsync-sync.timer
まとめ
rsyncは、適切なスクリプト、systemdによる自動化、そして堅牢なエラーハンドリングを組み合わせることで、非常に効率的かつ信頼性の高いファイル同期ソリューションとなります。
この記事の更新履歴
この記事は、生成AIを活用した自動レビュー・更新フローにより内容を見直し、必要な修正を反映しています。
2026年9月16日
- 削除冒頭のGemini未検証ドラフト表記を削除しました。
- 変更要件と前提セクション冒頭の不要な読点を削除しました。

