Google Guest Agent 完全指南
#DevOps #GCP #Compute Engine #VM #SSH
GCE 虛擬機內建的 Google 代理程式:SSH 金鑰佈建、startup script、網路設定背後的主角,以及 2025 年的 Plugin 架構改版。
目錄
- 什麼是 Guest Agent?
- Guest Environment 的組成
- 架構演進:Monolithic 到 Plugin
- 運作機制:Metadata Server 長輪詢
- 核心功能詳解
- 服務、檔案與日誌位置
- 設定檔說明
- 常用操作指令
- 常見問題
- 最佳實踐
- 參考資源
- 總結
什麼是 Guest Agent?
一句話理解:Guest Agent 是 Google 預裝在 GCE 虛擬機裡面的一支常駐程式,負責把「你在 GCP Console/API 上做的設定」實際套用到 VM 的作業系統內部。
從外部看,GCE 有許多功能像是「雲端自己就會處理」:
- 在 Console 按下「SSH」按鈕,幾秒後就能登入,而且帳號自動被建立好
- 在執行個體 metadata 貼上
startup-script,VM 開機時就會自動執行 - 掛第二張網卡、設定 alias IP,開機後 OS 裡的路由表就有了
- 啟用 OS Login 後,改用 IAM 權限就能控制誰能 SSH
這些都不是 hypervisor 變魔術,而是 VM 內部這支 agent 持續向 metadata server 查詢設定,再實際去改 /etc/passwd、authorized_keys、sshd_config、路由表所達成的。理解這件事,是排查 GCE「SSH 突然登不進去」「startup script 沒跑」類問題的關鍵前提。
核心特點
- 預裝:Google 提供的公用映像檔(Debian、Ubuntu、RHEL、Windows Server 等)都已內建,不需自行安裝
- 開源:以 Go 撰寫,程式碼在 GitHub(
GoogleCloudPlatform/guest-agent、新版google-guest-agent) - 常駐:以 systemd service(Linux)或 Windows Service 形式執行,開機自動啟動
- 由 metadata 驅動:幾乎所有行為的輸入來源都是 metadata server,而非 API 呼叫
Guest Environment 的組成
Guest Agent 屬於更大的 Guest Environment(客體環境),這是一組安裝在 VM 內的 script、daemon 與 binary 的集合。常見成員:
| 元件 | 角色 | 是否等於 Guest Agent |
|---|---|---|
google-guest-agent |
核心代理程式:帳號、網路、時鐘、metadata 監聽 | ✅ 本篇主角 |
google-metadata-script-runner |
實際執行 startup/shutdown script 的執行器 | 同一套件,獨立 binary |
google-osconfig-agent |
OS Config:修補管理、套件與設定政策(OS Patch Management) | ❌ 不同 agent |
Ops Agent(google-cloud-ops-agent) |
收集 logs/metrics 到 Cloud Logging / Monitoring | ❌ 需自行安裝 |
gce-disk-expand 等公用程式 |
開機時自動擴充根分割區等雜項 | ❌ 輔助套件 |
常見誤解:把「VM 沒有監控資料」歸咎於 guest agent。監控資料是 Ops Agent 的職責,且 Ops Agent 預設不會安裝;guest agent 只負責平台功能與少量遙測(telemetry)。
架構演進:Monolithic 到 Plugin
這是近兩年變動最大的部分,也是查資料時最容易看到過時內容的地方。
三個階段
| 時期 | 架構 | 特徵 |
|---|---|---|
| ~2024/11 | Monolithic(單體) | 單一 google-guest-agent 行程長輪詢 metadata,所有功能塞在同一個行程裡 |
| 2024/12 起 | 加入 Manager | 額外安裝 google-guest-agent-manager,開始具備管理外掛生命週期的能力 |
| 20250901.00 起 | Plugin(外掛式) | Manager 為中央行程,功能拆成獨立行程的外掛 |
⚠️ 注意:Ubuntu 與 SLES 映像檔目前仍使用 monolithic 架構。看到「我的機器上沒有 manager service」時,先確認發行版。
Plugin 架構的組成
- Guest Agent Manager:中央行程,負責啟動、監控、崩潰後重啟各外掛
- Core Plugin:封裝必要功能(帳號、網路、腳本、OS Login 等),不可停用
- Extensions:選用外掛,用於整合其他 Google Cloud 服務
- VM Extension Manager:Google Cloud 端的後端服務,控制選用外掛的部署與生命週期
為什麼要改?
單體架構缺乏元件隔離:任何一個功能出錯,整個 agent 就一起倒;而 SSH 帳號佈建也在同一個行程裡,等於「監控功能的 bug 可能害你登不進機器」。
外掛化後:
- 每個外掛獨立行程,單一外掛崩潰不影響核心 agent 或其他外掛
- 可對外掛套用 OS 層級資源限制,避免吃光 VM 資源
- 崩潰自動復原
- 選用功能可按需啟用,不必為了一個功能升級整包 agent
回退到單體架構
若新架構在特定環境有問題,可設定執行個體或專案 metadata:
gcloud compute instances add-metadata INSTANCE_NAME \
--zone=ZONE \
--metadata=enable-guest-agent-core-plugin=false
此時會改由相容性管理服務(google-guest-compat-manager / GCEWindowsCompatManager)接手,回到單體行為。
運作機制:Metadata Server 長輪詢
Guest Agent 的資料來源是 metadata server,位址固定為 169.254.169.254(DNS 名稱 metadata.google.internal),這是 link-local 位址,只在 VM 內部可達。
手動模擬 agent 在做的事:
# 讀取目前的 SSH 金鑰設定
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/attributes/ssh-keys"
# 讀取整棵 metadata 樹
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/?recursive=true&alt=json"
Agent 使用**長輪詢(long polling)**而非固定間隔輪詢——送出請求後由 server hold 住連線,直到內容變更或逾時才回應:
# hang 住直到 attributes 有變更(或 60 秒逾時)
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&wait_for_change=true&timeout_sec=60"
這解釋了兩件事:
- 為什麼在 Console 加一把 SSH 金鑰,幾秒內 VM 上的
authorized_keys就更新了——不是等下一次輪詢,是連線本來就掛著等變更 - 為什麼 agent 掛掉後,既有 SSH 連線不受影響,但新的金鑰佈建會停擺——沒有人在監聽變更了
Metadata-Flavor: Google 這個 header 是必要的防護:它讓 metadata server 拒絕來自瀏覽器或簡單 SSRF 的請求(無法輕易偽造自訂 header),避免 metadata(含服務帳號 token)外洩。
核心功能詳解
1. 帳號與 SSH 金鑰管理(Linux)
這是最常被感受到的功能:
- 監聽 metadata 中的
ssh-keys(專案層級與執行個體層級) - 對每個金鑰項目自動建立對應的本機使用者帳號
- 維護該使用者的
~/.ssh/authorized_keys - 將使用者加入
google-sudoers群組以取得 sudo 權限 - 當金鑰從 metadata 移除,對應的帳號也會被移除
相關 metadata key:
| Key | 作用 |
|---|---|
ssh-keys |
金鑰清單,格式為 使用者名稱:ssh-rsa AAAA... 註解 |
block-project-ssh-keys |
設為 true 時,此 VM 忽略專案層級金鑰,只認執行個體層級 |
對應設定區塊:[Accounts]。
💡 這也是為什麼「手動
useradd建的帳號」與「agent 建的帳號」行為不同:agent 管理的帳號會隨 metadata 變動而被增刪,手動改authorized_keys可能被覆寫。
2. OS Login(Linux)
啟用 OS Login(metadata enable-oslogin=true)後,agent 會實際去修改系統設定:
- 調整 sshd 設定(
AuthorizedKeysCommand等) - 更新
nsswitch.conf(使用者/群組查詢改走 OS Login) - 更新 PAM 設定
改用 IAM 角色(roles/compute.osLogin、roles/compute.osAdminLogin)控管登入權限,就不必再管理 metadata 裡的金鑰。
取捨:OS Login 的存取控制集中在 IAM、可搭配 2FA 與稽核,但登入路徑依賴 agent 與 OS Login API;metadata 金鑰方式較單純,但金鑰散落且難以稽核。
3. Metadata 啟動/關機腳本
由 google-metadata-script-runner 執行,行為細節:
- 在 shell 環境中執行腳本
- 多個腳本依序執行
- 同時存在 URL 型與 inline 型時,URL 型先執行
- 執行結束後記錄 exit status 到日誌
| Metadata key | 時機 |
|---|---|
startup-script |
每次開機 |
startup-script-url |
每次開機,從 GCS/HTTP 下載 |
shutdown-script |
關機/刪除前(有時間上限,逾時會被強制中斷) |
shutdown-script-url |
同上,從 URL 取得 |
對應設定區塊:[MetadataScripts]。
⚠️ 關機腳本不保證跑完:GCE 對 shutdown script 有執行時限,且 VM 被搶佔(preempt)或硬體故障時可能完全不執行。不要把資料一致性押在 shutdown script 上。
4. 網路介面設定
每次開機時,agent 會:
- 偵測系統實際使用的網路管理器(netplan、wicked、NetworkManager、dhclient)並沿用它
- 啟用所有次要 NIC(多網卡 VM 若少了 agent,第二張以後的網卡不會自動起來)
- 設定 IPv4 路由,使用協定 ID
66(可用ethernet_proto_id調整) - 確保主要介面能連到 metadata server
- 自動處理掛在 NIC 上的 VLAN 設定
以及 IP forwarding 與 alias IP:agent 會在主要乙太介面上建立對應路由,讓 alias IP 範圍與 IP 轉送真的生效。
查看 agent 建立的路由:
# 只列出協定 ID 66(Google agent 建立)的路由
ip route show proto 66
對應設定區塊:[NetworkInterfaces]、[IpForwarding]。
5. 時鐘校正(Linux)
clock_skew_daemon 元件定期把系統時間與實體主機對齊,實際執行的是:
/sbin/hwclock --hctosys -u --noadjfile
若偵測到 RTC 使用本地時區而非 UTC,會自動停用同步以免造成錯亂。這個機制主要處理 VM 遷移或暫停後恢復造成的時鐘跳動。
6. 執行個體初始化與最佳化
僅首次開機:
- 產生 SSH host key(類型由
host_key_types決定,預設ecdsa,ed25519,rsa) - 建立 boto 設定檔(供 Cloud Storage 存取)
每次開機:
- Local SSD 最佳化
- virtionet 裝置啟用 multi-queue
對應設定區塊:[InstanceSetup]。
💡 製作自訂映像檔時的雷區:若在 image 中留下已產生的 SSH host key,所有由該 image 開出的 VM 會共用相同 host key(安全問題,且客戶端會出現 host key 衝突警告)。封裝 image 前應清除 host key,讓 agent 在新 VM 首次開機時重新產生。
7. 遙測與 MDS mTLS 憑證
- 遙測:開機時與之後至少每 24 小時記錄一次系統資訊(agent 版本與架構、OS 名稱/版本/核心版本、偵測到的 ISV 應用程式)。可用 metadata
disable-guest-telemetry=true關閉 - MDS 憑證:為 HTTPS/mTLS 版本的 metadata server 端點準備並輪替憑證,供工作負載對工作負載的驗證使用
8. Windows 專屬功能
- 自動佈建 SSH 使用者的本機帳號
- 產生/重設 Windows 密碼(Console 的「設定 Windows 密碼」就是走這條路)
- 位址管理與 WSFC(Windows 容錯移轉叢集)支援
服務、檔案與日誌位置
| 項目 | Linux | Windows |
|---|---|---|
| 管理器服務 | google-guest-agent-manager.service |
GCEAgentManager |
| 單體 agent 服務(舊版/Ubuntu、SLES) | google-guest-agent.service |
GCEAgent |
| 相容性管理服務 | google-guest-compat-manager.service |
GCEWindowsCompatManager |
| Core Plugin | 由管理器啟動 | CorePlugin.exe |
| 設定檔 | /etc/default/instance_configs.cfg |
C:\Program Files\Google\Compute Engine\instance_configs.cfg |
| 日誌 | journald(journalctl -u ...),部分版本另有 /var/log/google-guest-agent.log |
Windows 事件檢視器 |
| 集中式日誌 | 預設同時送 Cloud Logging(cloud_logging_enabled) |
同左 |
另一個常被忽略的日誌來源是序列埠輸出(Serial console):VM 連不上、SSH 進不去時,agent 的早期啟動訊息通常只能從這裡看到。
gcloud compute instances get-serial-port-output INSTANCE_NAME --zone=ZONE
設定檔說明
檔案優先序(Linux)
同一個設定項若出現在多個檔案,優先序由高到低:
| 順位 | 檔案 | 用途 |
|---|---|---|
| 1(最高) | /etc/default/instance_configs.cfg.template |
使用者覆寫,套件升級不會被覆蓋 |
| 2 | /etc/default/instance_configs.cfg.distro |
發行版預設值 |
| 3(最低) | /etc/default/instance_configs.cfg |
基礎設定 |
✅ 要改設定就寫在
.template。直接改instance_configs.cfg可能在 agent 套件升級時被蓋掉。
語法與常用選項
格式為 INI:
[Accounts]
useradd_cmd = useradd -m -G google-sudoers
[InstanceSetup]
host_key_types = ecdsa,ed25519
set_boto_config = false
optimize_local_ssd = true
[Daemons]
clock_skew_daemon = true
accounts_daemon = true
network_daemon = true
[Core]
log_level = 4
cloud_logging_enabled = true
| 選項 | 區塊 | 說明 |
|---|---|---|
accounts_daemon |
Daemons |
帳號與 SSH 金鑰管理開關 |
clock_skew_daemon |
Daemons |
時鐘校正開關 |
network_daemon |
Daemons |
網路管理開關 |
host_key_types |
InstanceSetup |
首次開機產生的 SSH host key 類型 |
set_boto_config |
InstanceSetup |
是否建立 boto 設定檔 |
optimize_local_ssd |
InstanceSetup |
Local SSD 最佳化 |
ethernet_proto_id |
IpForwarding |
agent 建立路由使用的協定 ID(預設 66) |
log_level |
Core |
0–4,對應 FATAL / ERROR / WARN / INFO / DEBUG |
cloud_logging_enabled |
Core |
是否把 agent 日誌送到 Cloud Logging |
acs_client |
Core |
是否與 agent 控制平面通訊 |
修改後必須重啟 agent 才會生效。
常用操作指令
檢查狀態
# 新架構(20250901.00+)
systemctl status google-guest-agent-manager
systemctl status google-guest-compat-manager
# 單體架構(舊版 / Ubuntu / SLES)
systemctl status google-guest-agent
看日誌
# 即時追蹤
journalctl -u google-guest-agent-manager -f
# 本次開機以來的完整輸出
journalctl -u google-guest-agent -b --no-pager
# 舊版檔案日誌(若存在)
tail -f /var/log/google-guest-agent.log
重啟
# 20250901.00 之前
sudo systemctl restart google-guest-agent
# 20250901.00 之後(重啟 core plugin)
sudo ggactl_plugin coreplugin restart
Windows(PowerShell):
Restart-Service GCEAgent
# 或
Stop-Service GCEAgent; Start-Service GCEAgent
查版本
# Debian / Ubuntu
dpkg-query -W -f='${Package} ${Version}\n' google-guest-agent
# RHEL / CentOS / Rocky
rpm -q google-guest-agent
Windows:
googet installed
更新
# Debian / Ubuntu
sudo apt-get update && sudo apt-get install --only-upgrade google-guest-agent
# RHEL 系
sudo yum update google-guest-agent
讓自己的服務等 agent 就緒
Agent 會先完成最低限度的準備(網路設定、MDS 憑證、host key)才對外標示就緒。相依服務應在 systemd unit 中宣告:
[Unit]
After=google-guest-agent-manager.service
Windows 則用服務相依設定指向 GCEAgentManager。
常見問題
問題 1:新加的 SSH 金鑰無法登入,但舊連線正常
判斷方向:典型的 agent 停擺症狀——既有 sshd 連線與 agent 無關,但金鑰佈建停了。
# 從序列埠輸出檢查(因為可能已經 SSH 不進去)
gcloud compute instances get-serial-port-output INSTANCE_NAME --zone=ZONE | tail -50
# 若還能進去(例如用 OS Login 或其他帳號)
systemctl status google-guest-agent-manager
journalctl -u google-guest-agent-manager -b --no-pager | tail -50
其他可能原因:VM 設了 block-project-ssh-keys=true 而金鑰只加在專案層級;或 VM 已啟用 OS Login,此時 metadata 金鑰會被忽略。
問題 2:用 Packer 做的自訂映像檔,開機後 agent 是 dead
成因:封裝 image 時殘留了不該保留的狀態(例如已標記為完成的首次啟動狀態、殘留的機器識別資訊),或在 image 中停用了服務。
處理方向:封裝前清理 agent 狀態與 SSH host key、確認服務為 enabled,並避免在 image 內留下已產生的一次性檔案。
sudo systemctl is-enabled google-guest-agent-manager
sudo rm -f /etc/ssh/ssh_host_* # 封裝前清除,讓新 VM 重新產生
問題 3:startup script 沒有執行
排查順序:
# 1. 確認 metadata 真的有拿到
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/attributes/startup-script"
# 2. 看 script runner 的執行紀錄與 exit status
journalctl -u google-startup-scripts --no-pager
常見原因:script 沒有 shebang、URL 型腳本因權限問題下載失敗(服務帳號缺 GCS 讀取權)、或腳本本身在早期開機階段依賴尚未就緒的服務。
問題 4:第二張網卡沒有 IP/路由
多網卡 VM 的次要 NIC 由 agent 啟用。若 network_daemon 被關閉或 agent 未執行,OS 內就只有主要介面可用。
ip -brief addr
ip route show proto 66
問題 5:可以停用 Guest Agent 嗎?
技術上可以(systemctl disable --now),但會同時失去:SSH 金鑰佈建、OS Login、startup/shutdown script、次要 NIC 與 alias IP 設定、Windows 密碼重設、時鐘校正。
除非有明確理由(例如以自有組態管理工具完全接管,且已用其他方式建立登入路徑),否則不要停用。 若只是想關掉單一功能,改用設定檔中對應的 [Daemons] 開關,而非整支停用。
問題 6:找到的文件說明和機器上的實際狀況對不上
先確認三件事:agent 版本(20250901.00 前後架構不同)、發行版(Ubuntu/SLES 仍為單體)、是否被設為回退模式(enable-guest-agent-core-plugin=false)。多數「文件說有這個 service,但我機器上沒有」都出在這裡。
最佳實踐
1. 設定寫在 .template,不要改主設定檔
# ✅ 推薦:/etc/default/instance_configs.cfg.template
[Daemons]
clock_skew_daemon = false
# ❌ 不推薦:直接改 /etc/default/instance_configs.cfg(升級可能被覆蓋)
2. 自訂映像檔封裝前清除一次性狀態
# ✅ 清除 host key,讓每台新 VM 產生自己的
sudo rm -f /etc/ssh/ssh_host_*
# ❌ 直接把跑過的 VM 打成 image,導致所有機器共用 host key
3. 用 OS Login 取代 metadata 金鑰管理
規模化環境下,OS Login 讓存取權跟著 IAM 走,離職/換組時撤權是改 IAM 而非逐台清 metadata。
4. 相依服務明確宣告 After=
不要用 sleep 30 去猜 agent 何時就緒,宣告 systemd 相依關係。
5. 排查順序:序列埠 → service 狀態 → journald
SSH 不通時序列埠是唯一還看得到的窗口,養成先看它的習慣。
6. 要關功能就關單項,不要停整支 agent
[Daemons] 區塊提供逐項開關,粒度足夠。
參考資源
- About the guest agent — Compute Engine 官方文件
- Guest agent functionality — 功能逐項說明
- Configure the guest agent — 設定檔與管理
- GoogleCloudPlatform/guest-agent(GitHub)
- GoogleCloudPlatform/google-guest-agent(新版,GitHub)
總結
核心要點
- Guest Agent 是 GCE VM 內部的常駐程式,把雲端設定實際套用到 OS:SSH 帳號金鑰、OS Login、startup/shutdown script、網路介面與路由、時鐘校正
- 資料來源是 metadata server(
169.254.169.254),採長輪詢監聽變更,所以設定改動能在數秒內生效 - 架構在 2024/12(加入 manager)與 2025/09(
20250901.00外掛化)兩次改版;Ubuntu 與 SLES 仍為單體架構,查文件時務必先確認版本與發行版 - Core Plugin 不可停用;選用外掛由 Google 後端的 VM Extension Manager 控制;可用 metadata
enable-guest-agent-core-plugin=false回退 - Agent 停擺的典型症狀是「既有連線正常,但新金鑰無法登入、startup script 不跑」,排查從序列埠輸出與 service 狀態開始
快速參考
| 需求 | 做法 |
|---|---|
| 看狀態 | systemctl status google-guest-agent-manager |
| 看日誌 | journalctl -u google-guest-agent-manager -b |
| SSH 不通時看日誌 | gcloud compute instances get-serial-port-output INSTANCE --zone=ZONE |
| 重啟(新版) | sudo ggactl_plugin coreplugin restart |
| 重啟(舊版) | sudo systemctl restart google-guest-agent |
| 改設定 | 寫入 /etc/default/instance_configs.cfg.template 後重啟 |
| 查 agent 路由 | ip route show proto 66 |
| 讀 metadata | curl -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/... |
| 回退單體架構 | metadata enable-guest-agent-core-plugin=false |
| 關遙測 | metadata disable-guest-telemetry=true |
建立日期:2026-07-28