三つの痛み:転送成功後に表面化する不整合
痛み1:メタデータ錯覚による静かなスキップ。既定の rsync はサイズと mtime で再転送要否を判定します。ビルド基盤でタイムスタンプを揃える、コンテナがサブ秒を丸める、修復スクリプトが内容を変えず mtime だけ更新する、といった状況では破損ファイルをスキップする偽陰性が起き得ます。数千ファイルの dist では CDN やコード署名で初めて発覚し、調査コストが跳ね上がります。
痛み2:中断と部分ファイル。大容量アーカイブを --partial-dir なしで再開すると、最終名の横に半端なデータが残り、CI の再試行と混線します。監査ログにバッチ IDを残さない限り、最後の終了コードだけでは説明できません。
痛み3:SFTP ログが「誰が書いたか」を答えられない。共有鍵や GUI クライアントでは、認証成功とバイト数しか残らないことがあります。マルチテナントや並行上限と組み合わせる際は、パイプライン別キーとディレクトリラベルが不可欠です。
mtime と size だけでは「内容の同一性」を証明できない理由
mtime/size はメタデータの近似であり内容の十分条件ではありません。強いリリース規律では、ビルド時に manifest を作り、リモートで shasum -c を通すか、rsync --checksum で転送判断にハッシュを入れます。後者は CPU 負荷が高くなりがちです。マニフェスト方式は 原子リリース と相性が良く、releases/バッチ を検証してから current を切り替えられます。SFTP と rsync はシンボリックリンクや拡張属性の扱いが異なるため、フラグを文書化し、マニフェストには実行時に必要なファイルだけを載せます。
方針表:チェックサム、マニフェスト、サンプリング
CPU とリスクのトレードオフを明示するための表です。
| 方針 | 向く場面 | コスト | 失敗の見え方 |
|---|---|---|---|
rsync --checksum | 中規模ツリー、CPU に余裕、単一コマンドで完結したい | 同期スキャンで全ファイルハッシュ、大規模は時間増 | ログにスキップ/再送理由 |
マニフェスト+shasum -c | CI が成果物レイアウトを固定できる | マニフェスト生成とパス正規化の保守 | 非ゼロで昇格を止めやすい |
| デプロイ後サンプリング | 巨大オブジェクトストアで全件ハッシュ不可 | 運用コストは低い | 検知が遅れる |
| size/mtime のみ | 信頼できる LAN のスモーク | 最低 | 本番昇格には非推奨 |
実践:再開対応 rsync と五ステップの SHA256 ゲート
本番前にステージングで検証し、ホスト名とパスを置換してください。原子リリースではバージョンディレクトリを宛先にします。
# 手順1:ビルド側で manifest を生成(例:dist)
cd dist && find . -type f -print0 | sort -z | xargs -0 shasum -a 256 > ../manifest.sha256
# 手順2:partial-dir 付き rsync
rsync -avP --partial --partial-dir=.rsync-partial \
--bwlimit=8000 \
-e "ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=6" \
./ ../manifest.sha256 \
deploy@remote-mac:/srv/app/releases/202603281200/
# 手順3:リモートで shasum -c(非ゼロなら昇格禁止)
ssh deploy@remote-mac "cd /srv/app/releases/202603281200 && shasum -a 256 -c manifest.sha256"
# 手順4:JSONL に監査行を追記
ssh deploy@remote-mac "echo '{\"ts\":\"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'\",\"batch\":\"202603281200\",\"gate\":\"shasum\",\"exit\":0}' >> /var/log/ci-publish-audit.jsonl"
# 手順5:検証後に ln -sfn(原子リリース記事参照)
# ssh deploy@remote-mac "ln -sfn /srv/app/releases/202603281200 /srv/app/current"
GUI の SFTP でも、検証前に本番パスへ直接上書きせず、releases 配下へ送ってから shasum -c してください。シンボリック切替のモデルと整合します。
数値基準:ディスク、タイムアウト、保持期間
(1)空き容量は最大成果物の2.5 倍以上。(2)CI タイムアウトは転送 P95 の3 倍目安。300MB 級は越境で 45〜180 秒に及ぶことがあります。(3)監査にはパイプライン ID、コミット SHA、バッチディレクトリ、検証終了コードを含め、90 日以上保持を推奨。(4)--checksum 導入時は初回全件の所要時間を記録します。書き込みは releases/* のみ、読み取りは current 経由。Chroot と併用時は CI を単一プレフィックスに限定できます。
FAQ とホスト型リモート Mac
部分転送ディレクトリを Git に含める?
いいえ。.rsync-partial は .gitignore へ。
マニフェストとロックファイルの違いは?
ロックファイルは依存関係の版を固定します。マニフェストはビルド成果物のバイト列を固定します。
いつゲートが必須?
署名・ストア提出・有償顧客向け配布で、公網や多段プロキシを挟む場合は、トラフィック切替前に shasum -c を推奨します。
オンプレでもレンタルリモート Macでも手順は同じです。公開頻度が上がるほど、ディスク監視と鍵ローテーションの負担が増えます。SFTPMAC では隔離パス上で再開・SHA256・原子リリースを継続できます。ステージングで「同期→検証→切替」を先に固めてください。
自管の運用負荷を下げつつゲートを維持したい場合は、SFTPMAC のプランとノード仕様を確認してください。
