購買谷歌雲賬號:利用Cloud Scheduler配合雲功能定時自動切換VM虛擬機
在日常的雲端運維中,很多團隊都會遭遇一個讓人肉疼的「預算黑洞」:
服務器空轉。
比如公司的開發環境、測試環境或者是內部的報表系統,通常只有在白天工作時間的 8 到 10 個小時內有人使用。 但因為運維懶得去折騰、或者經常下班忘了關機,這些服務器往往 24 小時、365 天無休止地在後台瘋狂開機空轉。
在 Google Cloud (GCP) 的計費模式里,虛擬機(Compute Engine)是按秒和實例規格算錢的。 這意味著,
如果你下班不關機,一整晚白白浪費的服務器費用,可能直接占到了你單月賬單的 60% 以上
。
傳統的做法是寫一個複雜的 Shell 腳本,配上本地的
Cron
定時任務。 但本地機器一旦斷網、斷電,腳本就會漏跑。
在谷歌雲的現代化生態裡,有一個堪稱優雅的無伺服器(Serverless)黃金組合:
利用 Cloud Scheduler(雲計劃任務)配合 Cloud Functions(雲功能)
。 它就像是一個全自動的「雲端開關櫃」,你只需要動動嘴皮子寫幾行排班表,谷歌就會在後台不占用任何服務器的前提下,秒級幫你完成服務器的定時開斷。
今天我們拒絕任何官方說教套話,直接從純實戰出發,手把手帶你焊死這套大廠級的定時省錢防線。
第一階段:深度拆解,雲端定時開關的「三維世界模型」
在動手寫代碼之前,你必須在腦子裡建立起這套自動化運維流轉的物理模型。 整套流水線由三個核心組件無縫組合:
雲端鬧鐘(Cloud Scheduler):完全託管的定時器(相當於雲端 crontab)。 你用標準的 Linux Cron 語法告訴它:「每天早上 9 點叫我,每天晚上 8 點叫我」。 它按時按點就會往外發射一個信號。
秘密信使(Pub/Sub 消息隊列):一個安全的內網無線電台。 鬧鐘響了之後,會把一個簡單的指令(比如 start 或 stop)打包投遞到電台的某個頻道里。
電工機器人(Cloud Functions):谷歌的輕量級無服務器函數。 它平時處於完全休眠狀態(0 成本)。 一旦聽到電台裡有對應的指令,它會瞬間在後台「起屍」0.5 秒,調用谷歌雲的 API 把目標虛擬機一鍵開機或關機,然後繼續原地物理銷毀。
第二階段:實戰前夜--為機器人開闢合法身份(IAM)
在讓 Cloud Functi
Ons 去動服務器之前,我們必須堅決貫徹「最小權限原則」,給它辦一張合法的特權工作證,防止它權限過大誤傷了其他核心資產。
登錄 GCP 控制台,導航到 「IAM 和管理」 -> 「服務賬號(Service Accounts)」。
點擊 「創建服務賬號」,起名叫 vm-timer-executor。
精準灌注最小角色:在角色賦予頁面,搜索並選擇 「Compute Instance Admin (v1)」(虛擬機實例管理員)。 註:如果為了更嚴苛的安全,你可以自定義一個只包含 compute.instances.start 和 compute.instances.stop 的自定義角色。
點擊完成。
第三階段:實戰演練一--編寫 Cloud Functions 核心開關代碼
我們來到核心計算戰場。 我們要寫一段極簡的 Node.js 代碼,讓它能接收暗號並對服務器下達指令。
搜索並進入 Cloud Functions(雲功能) 頁面,點擊 「創建函數」。
基礎設置:函數名稱:vm-auto-switcher。 區域(Region):選擇離你虛擬機最近的地域(如 asia-east1 台灣)。 觸發器類型(Trigger):下拉菜單選擇「Cloud Pub/Sub」。 點擊創建新主題,起名叫 vm-timer-topic。
運行時參數調整:展開下方的「運行時、構建、連接和安全設置」,在服務賬號一欄,必須把默認賬號切掉,精準選擇我們在第二階段建好的 vm-timer-executor。
點擊下一步,進入代碼編輯器。 運行環境選擇
Node.js 20
(或者任何你熟悉的語言)。
把
Index.js
里的代碼全部清空,貼入以下大廠生產環境標準的硬核控制代碼:
JavaScript
Const Compute = require('@google-cloud/compute');
Const compute = new Compute();
Exports.manageVmStatus = async (cloudEvent) => {
// 1. 強行解包從 Pub/Sub 電台傳過來的加密無線電信號
Const base64Data = cloudEvent.data.message.data;
Const jsonS
Tring = Buffer.from(base64Data, 'base64').toString();
Const payload = JSON.parse(jsonString);
// 2. 精準提取設計圖紙:你要動哪裡的哪台機器? 你想讓它幹嘛?
Const { zone, instanceName, action } = payload;
如果! Zone ||! InstanceName ||! Action) {
Console.error('【災難報錯】傳參缺失! 必須包含 zone, instanceName 和 action! ');
返回;
}
Const zoneObj = compute.zone(zone);
Const vm = zoneObj.vm(instanceName);
Console.log('【自動化運維激活】正在嘗試對位於 ${zone} 的虛擬機 [${instanceName}] 執行 [${action}] 操作...');
嘗試 {
If (action.toLowerCase() === 'start') {
// 執行一鍵開機
Await vm.start();
Console.log('【成功】虛擬機 [${instanceName}] 開機指令下發成功,正在全速喚醒中! ');
} Else if (action.toLowerCase() === 'stop') {
// 執行一鍵安全關機
Await vm.stop();
Console.log('【成功】虛擬機 [${instanceName}] 關機指令下發成功,開始安全斷電! ');
} 否則 {
Console.warn('【警告】無法識別的操作指令: ${action}。 本函數只支持 start 或 stop。 ');
}
} 捕捉 (錯誤) {
Console.error('【物理失敗】執行過程中遭遇報錯: ${error.message}');
}
};
順手把旁邊的
Package.json
修改為包含穀歌官方
Compute 庫的依賴:
JSON
{
"Dependencies": {
"@Google-cloud/compute": "^4.0.0",
"@Google-cloud/cloudevents-conformance": "^0.2.2"
}
}
把右上角的「要執行的函數(Entry point)」修改為:
ManageVmStatus
。 點擊
「部署(Deploy)」
。
第四階段:實戰演練二--配置 Cloud Scheduler 焊死定時發令槍
函數部署完後,它就像是一個靜靜等待暗號的特工。 現在,我們要去建兩個雲端鬧鐘,一個負責早上叫它開機,一個負責晚上催它睡覺。
搜索進入
Cloud Scheduler(雲計劃任務)
頁面。
1. 鬧鐘一:配置周一至周五早上 8:30 全速開機
點擊
「創建作業(Create job)」
:
名稱:cron-start-dev-vm。
頻次(Frequency):輸入標準的 Linux Cron 表達式:30 8 * * 1-5。 (翻譯:每周一到周五的早上 8 點 30 分觸發)。
時區:選擇你本地的主時區(如中國上海時間)。
目標類型(Target type):選擇 Pub/Sub。
主題(Topic):選擇我們剛才建好的 vm-timer-topic。
消息體(Message body):這是灌入機器人的核心 Payload,精準貼入以下 JSON 指令:JSON{ "zone": "asia-east1-a", "instanceName": "my-dev-workstation", "action": "start" }
點擊創建。
2. 鬧鐘二:配置周一至周五晚上 20:30 強行關機
再次點擊創建作業:
名稱:cron-stop-dev-vm。
頻次(Frequency):輸入 30 20 * * 1-5。 (翻譯:每周一到周五的晚上 20 點 30 分觸發)。
目標類型:Pub/Sub,主題依然是 vm-timer-topic。
消息體(Message body):把 action 改成關機指令:JSON{ "zone": "asia-east1-a", "instanceName": "my-dev-workst
Ation", "action": "stop" }
點擊創建。 至此,全自動開閉合的閉環鐵絲網已經徹底鎖死。
第五階段:見證奇蹟的現場--「肉身按壓」手動測試演練
配置完了,難道我們要一直傻等到晚上八點半去看它起不起效嗎? 大廠運維從來不憑運氣賭博,我們直接在現場進行「人工催化測試」。
確保你那台名叫 my-dev-workstation 的虛擬機當前正處於綠色運行狀態(Running)。
來到 Cloud Scheduler 列表頁面。
找到那個負責關機的 cron-stop-dev-vm 任務,點擊它右側的三個點,毫不猶豫選擇 「強制運行(Force run)」。
點擊的瞬間,Cloud Scheduler 會強行繞過時間限制,往 Pub/Sub 里拍進一發關機信號。
這時候,你立刻切回到
Compute Engine 虛擬機列表
。 你會神奇地發現,原本亮著綠燈的那台服務器,其狀態圖標在沒有人工干預的前提下,瞬間變成了黃色的
Stopping
,幾秒鐘後徹底變灰進入
Terminated
(已關機)休眠狀態。
去函數的
Logs(日誌)
大屏里看一眼,裡面清清楚楚地印著我們剛才寫的代碼痕跡:
【成功】虛擬機 [my-dev-workstation] 關機指令下發成功,開始安全斷電!
。
大功告成! 從此以後,這台機器會像規律作息的打工人一樣,到點打卡開機,到點強制睡覺。
第六階段:商業級自動化運維的避坑血淚史
這套無服務器架構用起來爽快無比,省錢效果立竿見影。 但要在真正的企業級大盤環境裡穩定活下來,作為首席架構師,你必須立刻對方案進行邊界加固,防範以下兩個隱形大坑:
1. 致命的「本地盤數據灰飛煙滅」隱患(GCP 特有深坑)
很多新手開虛擬機時,貪圖讀寫速度,會在機器裡掛載
局部 SSD(Local SSD)
或者給系統配置為不可持續的非持久性磁盤。
災難發生:在 GCP 的底層邏輯裡,如果你調用 vm.stop() 執行物理關機,掛載在這台機器上的所有 Local SSD 裡面的數據,在斷電的瞬間會被谷歌從物理硬件上徹底擦除抹清。 只有掛載標準持久盤(Persistent Disk)的數據才能在關機後保留。
架構師避坑規範:凡是要加入定時開關機隊列的服務器,內部嚴禁存放任何未做多活備份的 Loc
Al SSD 臨時核心數據。 確保全盤走 Persistent Disk 資產。
2. 警惕「深夜加班狗」的哀嚎(人性化熔斷機製)
自動化太硬核了,有時候也會帶來負面反饋。 比如某個周五晚上八點半,全組開發為了趕一個緊急項目正在服務器里瘋狂改 Bug,結果八點半一到,cloud Scheduler 極其敬業且冷酷無情地一鍵把服務器給拉閘斷電了,導致開發寫了一半的代碼直接斷聯丟包,全組直接心態崩潰。
硬核人性化調優:不要在代碼里盲目直接下達 vm.stop()。
高級解法:在關機代碼執行前,讓函數先執行一步內部探測(比如通過 SSH 或者是監控指標盤查當前服務器的 CPU 使用率或網絡內網連接數)。
如果發現 CPU 占用率仍然大於 20%(說明有人在壓測或者加班),函數自動發送一條飛書/釘釘通知:「監測到加班跡象,本次深夜關機自動跳過,延時一小時後再盤查」。 代碼留有一線溫情,才是成熟運維架構師的最高修養。
總結
利用 GCP Cloud Scheduler 配合 Cloud Functions 玩轉定時自動切換虛擬機,核心的工業級精髓其實就在於十六個字:
定時發令,無線投遞,函數接單,溫情熔斷
。
你徹底告別了過去肉身盯防、下班後還要提心吊膽用手機連 VPN 去手工關服務器的原始狀態。 用完全免費的 Serverless 算力,去死死扣住每一枚不該浪費的雲端硬幣。 讓機器去管理機器,這才是現代雲原生時代最地道、最優雅的省錢姿勢。
