這篇寫的是我們自己犯的錯。
一次升級我們自己環境裡的主機時,我們檢查完、回報「全部零損失」。之後告警進來,逐台檢查才發現:有多台虛擬機內部已經寫不進任何檔案。
回頭看,問題不在升級本身,而在我們驗證的層次不對。
一、發生了什麼事
升級過程中,虛擬機共用的儲存中斷了 170 秒。
儲存恢復後,我們檢查的是主機這一層:
- 每台虛擬機的狀態都是「執行中」;
- 共用儲存也重新掛載、看起來正常。
於是我們回報:全部零損失。

圖:主機層的檢查全部打勾,問題卻在樓下:虛擬機內部已經切成唯讀,寫不進去。
二、為什麼主機層正常,虛擬機裡面卻壞了
儲存中斷時,虛擬機裡面的系統正在寫入資料。寫入一直等不到回應、逾時之後,系統為了保護資料,會自動把檔案系統切成唯讀。
關鍵在於兩層的恢復方式不一樣:
- 主機層:儲存回來之後,會自己重新接上。
- 虛擬機內部:已經切成唯讀的檔案系統,不會自己恢復,要重新開機才會好。
所以從主機看,一切正常;從虛擬機裡面看,已經壞了。
圖:同一次中斷,每一層看起來和實際的樣子。我們當時只驗到最上面的主機層。
三、告警也只報了一小部分
一開始告警只報了其中少數幾台,實際出問題的比告警多。原因有兩個:
- 有的主機根本沒有裝監控;
- 有的虛擬機切成唯讀之後,監控程式自己也起不來,自然不會報。
告警說「這幾台有問題」,不代表其他台沒問題。這次是我們逐台檢查,才看到全貌。
四、看起來「可讀寫」,其實寫不進去
還有一個更隱蔽的假象:系統顯示的掛載狀態是「可讀寫」,但實際寫入一個檔案時卻失敗。
當時有一個判斷就是根據這個狀態,認為某一台「已經恢復、不用重開」。事後從主機端的紀錄確認,那台大約 24 分鐘後還是被重開了,它從來沒有自己恢復過。
另外,管理工具也曾把「暫停」中的虛擬機顯示成「執行中」。狀態欄位寫什麼,不一定就是實際的狀況。
五、我們後來改用的四個驗證判準
這次之後,我們不再用「狀態欄位」判斷系統有沒有事,而是直接測會出事的那一層:
| 想確認的事 | 不要只看 | 要實際做的 |
|---|---|---|
| 系統能不能寫入 | 掛載狀態寫「可讀寫」 | 實際寫一個檔案 |
| 系統還活著 | 狀態顯示「執行中」 | 在裡面實際執行一個指令 |
| 服務有在運作 | 服務狀態「啟用中」 | 看它有沒有新的產出(新的紀錄、新的資料) |
| 重新啟動有生效 | 指令回報成功 | 確認主程序真的換了一個 |
當次的處理,也是照這個方式:逐台重開,每一台修好之後立刻做一次寫入測試,最後全部通過,才算結束。
六、為什麼要把這件事寫出來
「零損失」是一句很容易說出口的話。但如果驗證只停在主機層,這句話其實只代表「主機層零損失」。
我們把這次的錯誤寫成判準,之後每一次升級、修補、切換,都照這張表驗證到虛擬機和服務那一層,才回報結果。
你可以先問自己的幾個問題
- 你的「升級成功」,是在哪一層確認的?主機、虛擬機,還是應用程式?
- 有沒有實際寫入一個檔案,確認系統可以寫?
- 出事的時候,監控程式本身還能運作嗎?
- 告警說「這幾台出事」,你會不會順便檢查全部?
- 廠商回報「已完成、沒有影響」時,可以問一句:是怎麼驗證的?
我們在升級與修補時,都會照這套方式驗證並回報。想了解我們的做法,也可以參考 PHP2Shell 漏洞應變 這篇的實際處理經過,或 系統開發・平台建置 服務說明,也歡迎直接 與我們聯繫。