有些應用需要自我感知,也就是取得關於自身的資訊。「自我察覺」模式描述的 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.namePod 名稱
metadata.namespacePod 所在的命名空間
status.podIPPod IP 位址
spec.serviceAccountName該 Pod 使用的 ServiceAccount
metadata.uidPod 的唯一 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.labelsmetadata.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