Google Guest Agent 完全指南

GCE 虛擬機內建的 Google 代理程式:SSH 金鑰佈建、startup script、網路設定背後的主角,以及 2025 年的 Plugin 架構改版。

Google Guest Agent 完全指南

#DevOps #GCP #Compute Engine #VM #SSH

GCE 虛擬機內建的 Google 代理程式:SSH 金鑰佈建、startup script、網路設定背後的主角,以及 2025 年的 Plugin 架構改版。


目錄


什麼是 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/passwdauthorized_keyssshd_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"

這解釋了兩件事

  1. 為什麼在 Console 加一把 SSH 金鑰,幾秒內 VM 上的 authorized_keys 就更新了——不是等下一次輪詢,是連線本來就掛著等變更
  2. 為什麼 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.osLoginroles/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] 區塊提供逐項開關,粒度足夠。


參考資源


總結

核心要點

  • 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

🔗相關文章