コンテンツにスキップ
use-cases / snapshot-before-migration / hero
ユースケース / マイグレーション前のスナップショット

夜間マイグレーションの直前にコンテナをスナップショット

03:00 のマイグレーションジョブの 5 分前に発火する hoody-cron エントリを追加します。snapshots URL を curl し、アーティファクトをロールバックポイントとしてタグ付けします。マイグレーションが失敗した場合、たった 1 つの PATCH で 30 秒以内に復元できます。

cron + snapshot ドキュメントを読む
use-cases / snapshot-before-migration / mechanism

2 つの URL、1 つの就寝前の習慣

cron サービスは curl をスケジュールします。snapshots サービスは凍結を行います。どちらも 5 分後に実行されるマイグレーションジョブのことを知らず、それこそが要点です。

POST cron/entries
スケジューラ
# register the recurring snapshot job (one-time setup)
curl -X POST \
  cron.containers.hoody.com/users/root/entries \
  -H "Content-Type: application/json" \
  -d '{
    "schedule": "55 2 * * *",
    "command": "curl -X POST $SNAP_URL -d '{\"alias\":\"rollback-point\"}'",
    "comment": "pre-migration snapshot"
  }'
発火
POST containers/[id]/snapshots
フリーザー
# what the cron entry curls every night at 02:55 UTC
curl -X POST \
  api.hoody.com/api/v1/containers/$ID/snapshots \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"alias": "rollback-point", "expiry": 7}'

# response from the snapshots service
200 OK · snap-2026-05-04 created in 8s

cron エントリは Hoody のどこかにある Postgres テーブルの 1 行です。snapshots URL はコンテナのストレージバックエンドにコンテンツアドレス指定の blob を書き込みます。どちらも永続的でバージョン管理されており、ノートパソコン上で長時間実行されるプロセスは必要ありません。

use-cases / snapshot-before-migration / anatomy

昨夜の解剖図

4 つの瞬間、4 つの URL、そしてセーフティネットと変更の間の 5 分間。マイグレーションは大半のエンジニアの最初のアラームより先に終わります。

0102:55:00Zcron 発火schedule: 55 2 * * *
0202:55:08Zスナップショット着地alias rollback-point
0303:00:00Zマイグレーション実行ALTER TABLE invoices
0403:01:42Z監査クローズsnapshot retained 7d

ステップ 03 が失敗した場合、ロールバックは `PATCH /snapshots/snap-2026-05-04` で、02:55:08Z の状態に戻ります。上の監査タイムラインは同じデータを JSON として提供しています。

use-cases / snapshot-before-migration / powers

この形が解き放つもの

スナップショット自体ではありません。形です: 変更前に存在し、URL でアドレス指定され、今日の日付を含む名前を持つバックアップ。

01 / 安全性

バックアップは変更の正確に 5 分前に存在する

ほとんどの障害ポストモーテムは「バックアップを取り忘れた」で始まります。バックアップが cron エントリなら、忘れることはできません。02:55 のスナップショットは、事前に書かれたランブックの最初の文です。

02 / 速度

ロールバックは 1 つの PATCH、40 ステップのランブックではない

snap-2026-05-04 の復元は、api.hoody.com に対するたった 1 つの HTTP コールです。コンテナは 30 秒以内に 02:55:08Z の状態に戻ります。チケットなし、オンコールエスカレーションなし、「AWS コンソールは誰が持ってる?」もなし。

03 / アイドルコスト

マイグレーションが成功すれば、スナップショットのコストはゼロ

スナップショットはコンテンツアドレス指定で、差分として保存されます。変更されていないベースディスク上の 412 MB の差分が支払う対象であり、しかも 7 日間の保持期間のみです。成功したマイグレーションはほとんど痕跡を残しません。

use-cases / snapshot-before-migration / rollback

ロールバック、ビフォーとアフター

ランブックがどんな形をしていたか、そしてスナップショットが今日の日付で命名され URL でアドレス指定可能になったとき、それがどう折りたたまれるか。

旧ランブック9 つの手動ステップ、20-40 分、1-2 人
  • 01
    オンコール DBA をページ、マイグレーションが本番を壊したことを確認中央値: 4 分で承認
  • 02
    AWS コンソールで最新のバックアップを探す24 時間以内であることを祈る
  • 03
    復元インスタンスを起動、オンラインになるまで待つdb.r6g.xlarge で 8-15 分
  • 04
    手書きの DOWN スクリプトで ALTER TABLE を手動で逆実行DOWN スクリプトが存在すればの話、たいてい存在しない
  • 05
    アプリケーションサーバーを再起動、キャッシュをフラッシュ、エラー率を観察そしてポストモーテムを書く
平均ロールバック時間、ops@acme 2024 インシデント: 27 分
新ランブック1 HTTP コール、約 30 秒、人間 0 人
# rollback last night's migrationcurl -X PATCH api.hoody.com/api/v1/containers/$ID/snapshots/snap-2026-05-04# response200 OK · container reverted to snap-2026-05-04 in 28s
PATCH は冪等で可逆

右側の新しい欄はツールではありません。ランブック内の 1 文です。バックアップはすでに存在しているので、その文は「まず、バックアップを取る」では始まりません。

use-cases / snapshot-before-migration / punchline

ロールバック計画は、存在するようにスケジュールした URL です。

ビフォー: 誰も読まない Notion ページアフター: cron の 1 行とオブジェクトストレージの blob
まず、バックアップを取るランブックの最初の文、03:02 に疲れた人間が手動で実行
バックアップはすでに存在し、今日の日付で命名され、変更の 5 分前に取得済みランブックの最初の文、cron エントリによって事前に書かれた
snapshot API を見る
use-cases / snapshot-before-migration / replaces

これが置き換えるもの

マイグレーション前のバックアップを巡るカーゴカルト。スナップショットをスケジュールし、マイグレーションウィンドウとともに眠ります。

  • 手動のマイグレーション前スナップショット02:54 に起きてバックアップボタンをクリック
  • ランブック チェックリスト項目誰も見つけないページの 14 中ステップ 1
  • ロールバック用オンコール待機何もないことを待つためにエンジニアを支払う
  • デプロイ前のアドホック pg_dump覚えていたことを祈り、完了したことを祈る
  • 「慎重にやればいい」リリースインシデントを出荷する楽観論
  • AWS RDS 自動スナップショット固定 5 分ウィンドウ、GB 日単位の支払い
use-cases / snapshot-before-migration / cta

ロールバック計画は、存在するようにスケジュールした URL です。

snapshots リファレンスを読む
use-cases / snapshot-before-migration / related

他のユースケースを読む