バックアップは「取った」ではなく「戻せる」監視の緑が隠していた三つの穴
監視画面が一列に緑を並べていても、それが答えているのは「取れた」だけで、「戻せる」ではない。対象に書いてあるのに一度も取れていなかった DB、「取った」と言い張る画面、静かに何もしなかった「完全初期化」。この夏の運用でまとめて踏んだ、取得と復元のあいだの三つの穴。
緑は、雄弁だ

いまはこの緑を信じていい。だが少し前まで、同じ緑が嘘をついていた。
到達OK、鮮度OK、前回結果OK、ディスク余裕、レプリ健全。総合OK。監視が一列に緑を並べていると、誰もその下を疑わない。けれどこのパネルが答えているのは、たった一つの問いではない。いま、何を戻せるのか。 それだけが、どこにも映っていなかった。
「バックアップは取れています」と言うのは易しい。cron は毎日走り、ファイルは増え、ログは result=ok を刻む。だが「取れた」は経過であって、結果ではない。結果は復元の側にしかない。この夏、立て続けに踏んだ三つの穴は、どれも「取れているように見えて、戻せない」という同じ病の、別の顔だった。
穴① 対象に書いてあるのに、一度も取れていなかった
NGW は、一つの器に三つのアプリが同居している。本体(NGW)、外郭団体連携(CGW)、Webメール連携(IMAP)。そして各アプリの DB は持ち主が違う。本体は user01、外郭団体連携は user02、メール連携は user03。DB を増やすたび、バックアップ設定の対象にも形を足していた。
DB_AUTO_PATTERN="%_ngwdb"
DB_AUTO_PATTERN_EXTRA=("%_imapdb" "%_cgwdb")
設定はそろっている。監視も緑。隙は無いように見えた。だが cgwdb は、数ヶ月にわたって一本も取れていなかった。
原因は権限だった。バックアップはまず「何を取るか」を SHOW DATABASES で数える。ところがこの列挙は、実行した利用者に権限のある DB しか返さない。 列挙役はアプリ用の user01。cgwdb の持ち主は user02 だから、user01 の目には最初から映らない。
# user01 で数えると
SHOW DATABASES LIKE '%\_cgwdb';
→ (空) # 権限が無いので一件も返らない
# 全体が見える読み取り専用ユーザーなら
→ 46223_cgwdb / 56789_cgwdb / template_cgwdb # ちゃんと在る
映らないものは数えられず、数えられないものは取られない。「対象に書いてある」は「取れている」ではない。 設定は意図を表すだけで、実行は権限がやる。取る主体の目で、実際に見えて・読めて・出せるか。それを確かめない限り、対象リストは願望の一覧にすぎなかった。
直しは、列挙もダンプも全体が見える読み取り専用ユーザーに寄せること。ついでに気づいたが、imapdb も本来は所有者(user03)でないと SHOW EVENTS で弾かれる。DB を足すというのは、行を1つ増やすことではなく、誰の権限でそれを吸い上げるかを1つ決めることだった。
穴② 「取った」と言い張る画面、実態は「預かった」
NGWメインは、実は自分ではバックアップを取らない設計だ。負荷を避けるため、取るのは読み取り専用のレプリカ(NGWクローン)。NGWメインはその世代を受け取って保管する——単一障害点を避けるための、もう一つの置き場。役割は「取る」ではなく「預かる」。
なのに監視画面は、NGWメインの欄を「◯◯が取ったもの」と表示していた。しかも中身は、役割交代の前に残った古い残骸。今は無い団体の世代が、今日の成果のように並んでいた。
コードには、はっきりこう書いてあった。
# NGWメインは自分で世代を取らない(Cloneから from-clone に預かるだけ)
書いた本人が、画面のラベルでそれを裏切っていた。「取った」の一語が、読む人の視線を、戻せる対象からそらしていた。直しは表示だけでは足りない。「取った本数」を映すのをやめ、その機体が実際に守っている=戻せる世代を映すよう、収集側から作り替える。そして言葉を実態に合わせた——「取ったもの」から「預かったもの」へ。上の画面で「NGWメイン が預かったもの」と出ているのが、その直しだ。
監視とは、行われた作業の記録ではなく、いま何が戻せるかの地図であるべきだった。
穴③ 「完全に初期化」が、静かに何もしなかった
開発ペアを 0 から作り直すための「完全に初期化」ボタンを足した。押せば自前も預かりも消え、まっさらから取り直される——はずだった。工程は成功と出た。緑。だが実際には、何一つ消えていなかった。
原因は、消す対象の保管先パスを、アプリ側の設定既定(空)から読んでいたこと。パスが空なら対象が定まらず、削除は空振りする。しかもその空振りは、操作者に見えるエラーにならなかった。「削除しました」とだけ返して、次へ進んでいた。
これは、復元の裏返しの、同じ病だ。片方は「取れたように見えて戻せない」。もう片方は「壊したように見えて、何も変えていない」。どちらも、画面の成功と現実の距離から生まれる。
直しでは、保管先を実機の設定ファイルから正しく取り、破壊的操作の安全ガード(/ や /mnt のような危ういパスでは中止)を足した。そして何より、何を消したかを必ず件数で返すようにした。削除 0 項目 と 削除 54 項目 は、成功の顔が同じでも、意味がまるで違う。破壊・初期化のような操作こそ、「何もしなかった」を成功として見せてはいけない。
戻せるか、それだけを見る
三つは、道具の別々の欠陥ではなかった。ひとつの油断——「取れているか」で健全さを測ってしまう——の、三つの現れだ。バックアップに向けるべき問いは、本当は四つに分かれている。
- 誰の権限で取っているか。 列挙も取得も、その主体に見えて読めるものしか対象にならない。持ち主の違う DB は、設定に書いても取れない。
- どの DB・どのファイルを守っているか。 対象リストは意図。実際に世代として在るものと突き合わせる。
- どの世代から戻せるか。 自前と預かりを分け、最新だけでなく履歴が生きているかを見る。
- 本当に戻せるか。 取ったファイルは「戻せた」ではない。復元を定期的に実測して、はじめてそう言える。
そしてもう一つ、道具の側の戒め。無言の成功をなくすこと。 取ったなら何本を、消したなら何項目を、届いたなら何を。数を返さない「OK」が、いちばん危ういOKだ。緑は雄弁だが、雄弁ゆえに嘘をつく。
「取っている」と言うのは易しい。「戻せる」と言い切れるのは、一度でも戻してみた者だけだ。
AIとの協働作業での学び
この三つは、私が机の前で気づいたのではない。監視画面を Claude と一緒に読んでいて、順にほどけた。 きっかけは「なぜメインの ssh が停止に見えるのか」という小さな違和感で、そこから「cgwdb のバックアップが無い」に飛び火し、「そもそもメインは取らない設計では」と話が転がり、最後に「初期化が空振りしている」まで届いた。
面白かったのは、AI が偉かったのではなく、AI が私に説明させたことだ。「これは正常です」で流そうとするたびに、根拠(SHOW DATABASES の戻り、from-clone の中身、conf の値)を実機で突き合わせる流れになる。私が「取れているはず」と思い込んでいた場所ほど、突き合わせると食い違っていた。人間ひとりだと、緑を見て安心して終わっていた三箇所だ。
途中、私自身も一度やらかした。状態を確かめるつもりで打った「ドライラン」が、実際にはバックアップを本走させてしまった。AI はそれを隠さず「予定外の実行が走りました」と記録し、後始末(壊れた一時ファイルが無いか、プロセスが残っていないか)まで一緒に確認した。間違いを無かったことにしない——これも、無言の成功をなくすのと同じ作法だと思う。
道具は直した。だが本当に直ったのは、たぶん私の見方のほうだ。緑を見たら、その下で「いま何を戻せるか」を一度だけ疑う。それだけで、事故の多くは前の晩に見つかる。