有些應用需要自我感知,也就是取得關於自身的資訊。「自我察覺」模式描述的 Kubernetes Downward API,提供了一套簡單的自省與中繼資料注入機制。
問題#
多數使用案例中,雲原生應用是無狀態、可拋棄的,對其他應用而言沒有什麼相關的身分。但即使是這類應用,有時也需要知道自己以及所處環境的資訊:
- 只有在執行期才知道的資訊,例如 Pod 名稱、Pod IP 位址、應用被放置的主機名稱。
- 在 Pod 層級定義的靜態資訊,例如特定的資源 request 與 limit。
- 使用者可能在執行期改動的動態資訊,例如註解與標籤。
實際用途包括:
- 依容器可用的資源,調校應用的執行緒池大小、更換垃圾回收演算法或記憶體配置。
- 在記錄日誌、或向中央伺服器送出指標時,帶上 Pod 名稱與主機名稱。
- 發現同一命名空間中帶有特定標籤的其他 Pod,並與它們組成叢集化應用。
解法#
這類需求與解法並非容器獨有,而是存在於任何「資源中繼資料會變動」的動態環境。例如 AWS 提供 Instance Metadata 與 User Data 服務,可從任何 EC2 實例查詢自身的中繼資料;AWS ECS 也提供 API 讓容器查詢容器叢集資訊。
Kubernetes 的取徑更優雅也更易用:Downward API 透過環境變數與檔案,把 Pod 與叢集的中繼資料傳遞給容器。這與我們從 ConfigMap 和 Secret 傳遞應用相關資料的機制相同,差別在於資料不是由我們建立的——我們只指定感興趣的鍵,Kubernetes 動態填入其值。

圖 13-1:應用自省機制——Downward API 如何把資源與執行期資訊注入相關 Pod
關鍵在於:透過 Downward API,中繼資料被注入你的 Pod 並在本地可用。應用不需要使用客戶端與 Kubernetes API 互動,可以維持對 Kubernetes 無感(Kubernetes-agnostic)。
透過環境變數取得中繼資料#
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
env:
# 環境變數 POD_IP 取自本 Pod 的屬性,於 Pod 啟動時產生
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
# 環境變數 MEMORY_LIMIT 設為本容器的記憶體資源上限值
- name: MEMORY_LIMIT
valueFrom:
resourceFieldRef:
container: random-generator
resource: limits.memory上例用 fieldRef 存取 Pod 層級的中繼資料。以下鍵值可用於 fieldRef.fieldPath,環境變數與 downwardAPI volume 皆可使用:
| 名稱 | 說明 |
|---|---|
spec.nodeName | 承載該 Pod 的節點名稱 |
status.hostIP | 承載該 Pod 的節點 IP 位址 |
metadata.name | Pod 名稱 |
metadata.namespace | Pod 所在的命名空間 |
status.podIP | Pod IP 位址 |
spec.serviceAccountName | 該 Pod 使用的 ServiceAccount |
metadata.uid | Pod 的唯一 ID |
metadata.labels['key'] | Pod 標籤 key 的值 |
metadata.annotations['key'] | Pod 註解 key 的值 |
與 fieldRef 類似,resourceFieldRef 用來存取特定容器的中繼資料,容器以 resourceFieldRef.container 指定;作為環境變數使用時,預設是當前容器。resourceFieldRef.resource 可用的鍵為:
| 名稱 | 說明 |
|---|---|
requests.cpu | 容器的 CPU request |
limits.cpu | 容器的 CPU limit |
requests.memory | 容器的記憶體 request |
limits.memory | 容器的記憶體 limit |
透過 volume 取得中繼資料#
使用者可以在 Pod 執行期間改動標籤與註解這類中繼資料。
除了前述的個別欄位,downwardAPI volume 還能用 metadata.labels 與 metadata.annotations 引用,把所有 Pod 標籤與註解擷取成檔案:
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
volumeMounts:
- name: pod-info
mountPath: /pod-info
volumes:
- name: pod-info
downwardAPI: # Downward API 的值可以檔案形式掛載進 Pod
items:
# labels 檔案逐行以 name=value 格式包含所有標籤,標籤變動時此檔會更新
- path: labels
fieldRef:
fieldPath: metadata.labels
# annotations 檔案以相同格式存放所有註解
- path: annotations
fieldRef:
fieldPath: metadata.annotations使用 volume 時,Pod 執行期間的中繼資料變動雖會反映到 volume 檔案,但偵測檔案變動並讀取更新後的資料,仍是消費端應用自己的責任。若應用沒有實作這項功能,可能還是得重啟 Pod。
討論#
許多場合下,應用需要自我感知、知道自己與所處環境的資訊。Kubernetes 為自省與中繼資料注入提供了非侵入式的機制。
Downward API 的缺點之一是:它只提供固定數量的可引用鍵值。若你的應用需要更多資料,尤其是關於其他資源或叢集相關的中繼資料,就必須向 API Server 查詢。
許多應用正是這樣做的:查詢 API Server 以發現同一命名空間中帶有特定標籤或註解的其他 Pod,接著與這些 Pod 組成叢集並同步狀態;監控應用也用這個手法找出感興趣的 Pod 並開始為其埋設量測。
各語言都有許多客戶端函式庫可與 Kubernetes API Server 互動,取得超出 Downward API 範圍的自我參照資訊。
更多資訊#
- Self Awareness Example
- Expose Pod Information to Containers Through Files
- Expose Pod Information to Containers Through Environment Variables
- Amazon ECS Container Agent Introspection
- Instance Metadata and User Data