誤って削除したチケットを復旧する

CloudflareBeginner
オンラインで実践に進む

はじめに

誤って SQL で削除したためにチケットが消えますが、アプリケーションの設定は正しいままです。この実験では、D1 Time Travel のブックマークを取得し、1 件の合成レコードを使って障害を再現します。その後、影響を受けていないチケットを保持したまま、同じデータベースを復元します。

この独立した復旧演習では、破棄可能なリモートデータベースを 1 つと、提供されている読み取り専用 Worker を使用します。復元前に欠落した状態を確認し、復元後にアプリケーションからアクセスできることを確認します。

自分の学習用アカウントと新しい VM を使用してください。セットアップでは、まず Node.js 22.22.0 を準備し、その後 /home/labex/project/ticket-database でプロジェクト用の Wrangler 4.131.1 と評価に必要な依存関係を npm install でインストールします。依存関係のバージョンは固定されており、インストール時に専用の lockfile が作成されます。セットアップ中にクラウドへのログインや、評価対象となるデータベース操作は実行されません。個人のマシンでは、プロジェクト内で npm install --save-dev wrangler@4.131.1 を実行して同じバージョンの Wrangler をインストールしてください。

この演習では、D1 Free の利用枠内の小さな合成レコードを使用します。既存のアカウント使用量もこの利用枠に含まれます。購入済みのドメインは必要ありません。リソースの削除とログアウトの両方を確認するまで、この VM を保持してください。

この VM を認証してアカウントを選択する

このステップでは、新しいターミナルを自分の学習用アカウントに接続します。Dashboard にログインしただけでは、VM は認証されません。D1 の権限ではデータベースの作成、SQL の変更、削除を行います。Workers の権限ではデプロイを行い、KV の権限は Wrangler のクリーンアップ対象の一覧作成を支援します。認証する前に、Background Access を含む同意画面の内容を確認してください。

準備済みのプロジェクトを開き、固定されている CLI のバージョンを確認します。

cd /home/labex/project/ticket-database
npx wrangler --version

4.131.1 と表示されることを確認します。デバイス認証を開始します。--device はブラウザに入力するコードを表示し、--browser=false はブラウザの選択を自分で行えるようにします。

npx wrangler login --device --browser=false --scopes account:read user:read d1:write workers_scripts:write workers_kv:write

表示された URL をブラウザで開き、現在のコードを入力します。自分の学習用アカウントと権限を確認して、認証を許可してください。ターミナルに成功が表示されるまで待ちます。パスワードやトークンをプロジェクトファイルに貼り付けないでください。

npx wrangler whoami --json

loggedIn: true を確認し、アカウントが 1 つだけ表示される場合でも、アカウントの nameid を読み取ります。使用するアカウントの ID を、以下の設定にコピーしてください。次のシェル変数は、6 バイトのランダム値(12 個の 16 進数文字)を使用して、他の学習者との衝突を避けます。ヒアドキュメントは JSON の行の間にある JSON を書き込み、内部では $RUN が展開されます。

$schema の前のバックスラッシュは、この JSON キーを文字どおり保持します。$RUN は引き続き今回の実行に固有の名前に展開されます。

RUN=labex-c04-d07-$(openssl rand -hex 6)
cat > wrangler.jsonc <<JSON
{
  "\$schema": "./node_modules/wrangler/config-schema.json",
  "name": "$RUN",
  "account_id": "YOUR_ACCOUNT_ID",
  "main": "src/index.js",
  "compatibility_date": "2026-09-15",
  "workers_dev": true,
  "preview_urls": false
}
JSON

ブロックを実行する前に、YOUR_ACCOUNT_ID を置き換えてください。RUN の値を使えるように、このターミナルは開いたままにします。name は今回の実行を識別し、account_id はクラウド操作に使用するアカウントを選択します。このファイルは通常の JSON であり、JSONC としても有効です。このファイルを書き込んだだけでは Worker はデプロイされません。

正常な復元ポイントを作成する

このステップでは、破棄可能なデータベースと、提供されている読み取り専用のチケット API を作成します。Time Travel は、データベースを過去の状態にその場で復元します。置き換え用の新しいデータベースを作成する機能ではなく、選択した時点より後に行われた変更を上書きする可能性があります。ここでは、新しく作成したこの実験用リソースに対してのみ使用してください。

破棄可能なクラウドデータベースを作成します。--binding DB はアプリケーションコードから使う短い名前を設定し、--update-config は実際の名前と UUID を wrangler.jsonc に記録し、--use-remote=false は開発時にローカル環境を使用します。

npx wrangler d1 create "$RUN-db" --binding DB --update-config --use-remote=false

作成された名前と ID を読み取り、保存されたバインディングを確認します。

cat wrangler.jsonc

DB エントリに、この実験で作成したデータベースの名前が設定されている必要があります。バインディングは、コードとリソースを接続する設定です。UUID はクラウドデータベースを識別し、--local を指定すると、この VM 内の別の SQLite データベースを使用します。SQL コマンドでは、必ず --local または --remote のどちらかを指定してください。

npx wrangler d1 execute DB --remote --file schema.sql
npx wrangler deploy

デプロイされた URL をコピーし、2 件の合成チケットを読み取ります。

URL='YOUR_DEPLOYED_HTTPS_URL'
curl -i "$URL/tickets/1"
curl -i "$URL/tickets/2"

チケット 1(Cannot sign in、open)では 200 が返り、チケット 2(Invoice copy、closed)でも 200 が返ることを確認します。デプロイの反映に時間がかかる場合は、ステータスと JSON の内容が一致するまで、最大 1 分間これらの読み取りを繰り返してください。

データベース情報を確認し、現在のブックマークを復旧用アーティファクトとして保存します。ブックマークは、データベース履歴上の位置を表す不透明な値です。> によるリダイレクトを使うと、JSON レスポンスが指定したファイルに書き込まれます。

npx wrangler d1 info DB
npx wrangler d1 time-travel info DB --json > recovery.json
cat recovery.json

データベースが本番バックエンドを使用していることと、recovery.json に空ではない bookmark が含まれていることを確認します。このファイルは実験中、変更しないでください。本番 D1 では Time Travel が常に有効です。Free は 7 日間、Paid は 30 日間保持されます。今回の同一セッション内の復旧に必要なのは数分間の履歴だけです。CLI のヘルプに 30 日間と表示されていても、使用中のプランの保持期間が変わるわけではありません。

範囲を限定した誤削除を再現する

このステップでは、この実験用データベースから合成チケット 1 だけを削除し、アプリケーションに現れる症状を確認します。まず wrangler.jsonc を確認し、DB が直前に作成したデータベースの名前と UUID に対応していることを確認してください。既存のアプリケーションデータベースに対して実行しないでください。

cat wrangler.jsonc
npx wrangler d1 execute DB --remote --command "DELETE FROM tickets WHERE id = 1;"

API と、影響を受けていないレコードを読み取ります。

curl -i "$URL/tickets/1"
curl -i "$URL/tickets/2"
npx wrangler d1 execute DB --remote --command "SELECT id, subject, status, source FROM tickets ORDER BY id;"

チケット 1 では {"error":"not_found"} とともに 404 が返る必要があります。チケット 2 では元の 200 レスポンスが返り、SQL クエリの結果にはチケット 2 だけが含まれます。ネットワーク障害やプラットフォームの 404 ページだけでは、削除が発生したことを確認したことにはなりません。

復元する前に、このステップの確認を完了してください。これにより、実際に行が欠落している状態を確認できます。失敗を確認せずに復元すると、インシデントの証拠を取得できません。

履歴を復元してアプリケーションからのアクセスを確認する

このステップでは、保存したブックマークの時点まで同じデータベースを復元します。recovery.json を読み取り、正確な bookmark 文字列を BOOKMARK にコピーしてから、設定済みのデータベース ID を再確認します。

cat recovery.json
BOOKMARK='YOUR_SAVED_BOOKMARK'
cat wrangler.jsonc
npx wrangler d1 time-travel restore DB --bookmark "$BOOKMARK"

このコマンドは、データを上書きし、実行中のクエリをキャンセルすることを警告します。この破棄可能なデータベースだけを確認して続行してください。復元成功メッセージと、取り消し用のブックマークが表示されることを確認します。データベースを作り直したり、スキーマを再インポートしたり、欠落した行を挿入したりしないでください。これらの操作では、復旧手法を使わずに済ませることになるためです。

復元したデータベースと、既存のアプリケーションバインディングを使って確認します。

npx wrangler d1 execute DB --remote --command "SELECT id, subject, status, source FROM tickets ORDER BY id;"
curl -i "$URL/tickets/1"
curl -i "$URL/tickets/2"

元の 2 行と API レスポンスの両方が返る必要があります。Worker は引き続き同じ UUID を参照するため、バインディングを置き換える必要はありません。復元中に一時的に読み取りができない場合は、読み取りを繰り返してください。復元の代わりに新しいデータを初期投入することは避けてください。

Dashboard で該当する D1 データベースを正確に開き、ID が変わっていないことを確認します。読み取り専用ビューを使って、復元されたチケットを確認してください。この確認により、復旧したデータとリソースが対応していることを確認できます。機能面の証拠は SQL/API の結果です。アカウントの Audit Logs で、Resource ID をこのデータベースの UUID に絞り込み、復元時刻を含む期間を選択します。イベントの時刻をクリックして詳細を開き、Resource を展開して type: database.time_travel.restore を確認します。リソース ID と成功した操作が、復元コマンドの出力と一致することを確認してください。監査記録が表示されるまで時間がかかる場合があります。一時的に一覧が空でも、失敗だと判断しないでください。データの確認は復旧した状態を証明し、実際の復元出力と監査イベントは復旧操作を記録します。

同じ D1 データベースに復元されたチケット

この例では、同じデータベースで復元された元の 2 件のチケットを示しています。生成された名前はこの実行例を識別するもので、あなたの名前と UUID は異なります。スクリーンショットは復元後の行を示します。SQL/API チェックでアクセスの回復を確認し、実際の Time Travel コマンド出力と対応する監査イベントで復元操作を確認します。

Time Travel の監査イベント

イベントの見出しには汎用的な操作名 create が表示されます。展開した Resource セクションの type: database.time_travel.restore が復元操作を示します。成功結果、正確なデータベース UUID、時刻を確認してください。ここに示す値はこの実行例のものです。

破棄可能なリソースを削除する

このステップでは、VM がまだ認証されている間に、この実験で作成したリソースだけを削除します。すべての機能確認を先に完了してください。削除の確認が終わるまで、設定ファイルは保持します。

npx wrangler delete

この実行で設定した Worker の名前だけが表示されていることを確認します。

npx wrangler d1 delete DB

プロンプトの内容を確認し、この実験で作成したデータベースだけを削除対象として承認します。その後、データベースの一覧を表示します。

npx wrangler d1 list --json

正常なレスポンスに、記録したデータベース名と UUID が含まれていないことを確認します。他のリソースは残っている可能性があります。認証エラーやネットワークエラーが発生した場合、その結果だけでは削除を確認できません。アクセスを復旧し、次に進む前に一覧の取得を繰り返してください。まだログインしている状態で、このステップの確認を実行します。

この VM の認証を終了する

このステップでは、独立した削除確認が成功した後にのみ、認証を終了します。ログアウトすると、この VM に保存されている Wrangler の認証情報が削除されます。VM を閉じただけでは、クラウドのクリーンアップにはなりません。

npx wrangler logout
npx wrangler whoami --json

loggedIn: false と表示されることを確認します。この認証されていない状態でのクエリは、終了ステータスが 0 以外になる場合があります。構造化されたレスポンスにログアウト済みであることが明示されている場合に限り、それは想定された動作です。確認を完了してから、実験環境を閉じてください。

まとめ

誤って削除したチケットを復旧する手順を実践しました。データベースの状態を実際の結果で確認し、選択したアカウントとローカル状態を明示的に管理し、ログアウトする前に破棄可能なリソースを削除しました。