ConfigMap

ConfigMap 是一個 API 物件,用於以鍵值對的形式儲存非機密資料。Pod 可以將 ConfigMap 作為環境變數、命令列引數或 中的配置檔案使用。

ConfigMap 允許你將特定環境的配置與你的容器映象解耦,從而使你的應用程式易於移植。

動機

使用 ConfigMap 將配置資料與應用程式程式碼分開設定。

例如,假設你正在開發一個應用程式,你可以在自己的計算機上執行(用於開發),也可以在雲端執行(處理實際流量)。你編寫的程式碼會查詢名為 DATABASE_HOST 的環境變數。在本地,你將該變數設定為 localhost。在雲端,你將其設定為引用一個 Kubernetes Service,該服務將資料庫元件公開給你的叢集。這使得你可以在雲端獲取正在執行的容器映象,並在需要時在本地除錯完全相同的程式碼。

ConfigMap 物件

ConfigMap 是一個API 物件,它允許你儲存配置以供其他物件使用。與大多數具有 spec 的 Kubernetes 物件不同,ConfigMap 具有 databinaryData 欄位。這些欄位接受鍵值對作為其值。data 欄位和 binaryData 欄位都是可選的。data 欄位旨在包含 UTF-8 字串,而 binaryData 欄位旨在包含 base64 編碼的二進位制資料。

ConfigMap 的名稱必須是有效的 DNS 子域名

databinaryData 欄位下的每個鍵必須由字母數字字元、-_. 組成。儲存在 data 中的鍵不能與 binaryData 欄位中的鍵重疊。

從 v1.19 開始,你可以向 ConfigMap 定義新增一個 immutable 欄位,以建立不可變 ConfigMap

ConfigMaps 和 Pods

你可以編寫一個引用 ConfigMap 的 Pod spec,並根據 ConfigMap 中的資料配置該 Pod 中的容器。Pod 和 ConfigMap 必須位於相同的名稱空間中。

這是一個 ConfigMap 示例,其中一些鍵具有單個值,另一些鍵的值看起來像配置格式的片段。

apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # property-like keys; each key maps to a simple value
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # file-like keys
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true    

有四種不同的方式可以使用 ConfigMap 來配置 Pod 中的容器

  1. 在容器命令和引數中
  2. 作為容器的環境變數
  3. 在只讀卷中新增一個檔案,供應用程式讀取
  4. 編寫程式碼在 Pod 內部執行,使用 Kubernetes API 讀取 ConfigMap

這些不同的方法適用於對所消耗資料進行不同建模的方式。對於前三種方法,當 kubelet 啟動 Pod 的容器時,它會使用 ConfigMap 中的資料。

第四種方法意味著你必須編寫程式碼來讀取 ConfigMap 及其資料。但是,由於你直接使用 Kubernetes API,你的應用程式可以訂閱在 ConfigMap 更改時獲取更新,並在發生更改時做出反應。透過直接訪問 Kubernetes API,這種技術還允許你訪問不同名稱空間中的 ConfigMap。

這是一個 Pod 示例,它使用 game-demo 中的值來配置 Pod

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
spec:
  containers:
    - name: demo
      image: alpine
      command: ["sleep", "3600"]
      env:
        # Define the environment variable
        - name: PLAYER_INITIAL_LIVES # Notice that the case is different here
                                     # from the key name in the ConfigMap.
          valueFrom:
            configMapKeyRef:
              name: game-demo           # The ConfigMap this value comes from.
              key: player_initial_lives # The key to fetch.
        - name: UI_PROPERTIES_FILE_NAME
          valueFrom:
            configMapKeyRef:
              name: game-demo
              key: ui_properties_file_name
      volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
  volumes:
  # You set volumes at the Pod level, then mount them into containers inside that Pod
  - name: config
    configMap:
      # Provide the name of the ConfigMap you want to mount.
      name: game-demo
      # An array of keys from the ConfigMap to create as files
      items:
      - key: "game.properties"
        path: "game.properties"
      - key: "user-interface.properties"
        path: "user-interface.properties"
        

ConfigMap 不區分單行屬性值和多行檔案式值。重要的是 Pod 和其他物件如何使用這些值。

對於這個示例,定義一個卷並將其掛載到 demo 容器內作為 /config 會建立兩個檔案:/config/game.properties/config/user-interface.properties,儘管 ConfigMap 中有四個鍵。這是因為 Pod 定義在 volumes 部分指定了一個 items 陣列。如果你完全省略 items 陣列,ConfigMap 中的每個鍵都會變成一個與鍵同名的檔案,你將得到 4 個檔案。

使用 ConfigMaps

ConfigMaps 可以作為資料卷掛載。ConfigMaps 也可以由系統的其他部分使用,而無需直接暴露給 Pod。例如,ConfigMaps 可以儲存系統其他部分應用於配置的資料。

使用 ConfigMaps 最常見的方式是配置在同一名稱空間中的 Pod 中執行的容器的設定。你也可以單獨使用 ConfigMap。

例如,你可能會遇到外掛操作員,它們根據 ConfigMap 調整其行為。

從 Pod 中將 ConfigMap 作為檔案使用

要在 Pod 的卷中消耗 ConfigMap:

  1. 建立 ConfigMap 或使用現有 ConfigMap。多個 Pod 可以引用同一個 ConfigMap。
  2. 修改你的 Pod 定義,在 .spec.volumes[] 下新增一個卷。給卷命名,並設定 .spec.volumes[].configMap.name 欄位以引用你的 ConfigMap 物件。
  3. 向需要 ConfigMap 的每個容器新增一個 .spec.containers[].volumeMounts[]。指定 .spec.containers[].volumeMounts[].readOnly = true.spec.containers[].volumeMounts[].mountPath 到一個未使用的目錄名,你希望 ConfigMap 出現在其中。
  4. 修改你的映象或命令列,以便程式在該目錄中查詢檔案。ConfigMap data 對映中的每個鍵都成為 mountPath 下的檔名。

這是一個在卷中掛載 ConfigMap 的 Pod 示例

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    configMap:
      name: myconfigmap

你想要使用的每個 ConfigMap 都需要在 .spec.volumes 中引用。

如果 Pod 中有多個容器,則每個容器都需要自己的 volumeMounts 塊,但每個 ConfigMap 只需要一個 .spec.volumes

掛載的 ConfigMap 會自動更新

當卷中當前使用的 ConfigMap 更新時,投影的鍵也會最終更新。kubelet 在每次定期同步時都會檢查掛載的 ConfigMap 是否是新的。然而,kubelet 使用其本地快取來獲取 ConfigMap 的當前值。快取的型別可以透過 KubeletConfiguration 結構中的 configMapAndSecretChangeDetectionStrategy 欄位進行配置。ConfigMap 可以透過 watch(預設)、基於 ttl 或透過將所有請求直接重定向到 API 伺服器進行傳播。因此,從 ConfigMap 更新到新鍵投影到 Pod 的總延遲可能與 kubelet 同步週期 + 快取傳播延遲一樣長,其中快取傳播延遲取決於所選的快取型別(它分別等於 watch 傳播延遲、快取的 ttl 或零)。

作為環境變數使用的 ConfigMaps 不會自動更新,需要重啟 Pod。

將 ConfigMap 用作環境變數

要在 Pod 中將 ConfigMap 用於環境變數

  1. 對於 Pod 規範中的每個容器,為每個要使用的 ConfigMap 鍵將一個環境變數新增到 env[].valueFrom.configMapKeyRef 欄位。
  2. 修改你的映象和/或命令列,以便程式在指定的en環境變數中查詢值。

這是一個將 ConfigMap 定義為 Pod 環境變數的示例

以下 ConfigMap (myconfigmap.yaml) 儲存了兩個屬性:username 和 access_level

apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfigmap
data:
  username: k8s-admin
  access_level: "1"

以下命令將建立 ConfigMap 物件

kubectl apply -f myconfigmap.yaml

以下 Pod 將 ConfigMap 的內容作為環境變數使用

apiVersion: v1
kind: Pod
metadata:
  name: env-configmap
spec:
  containers:
    - name: app
      command: ["/bin/sh", "-c", "printenv"]
      image: busybox:latest
      envFrom:
        - configMapRef:
            name: myconfigmap

envFrom 欄位指示 Kubernetes 從其巢狀的源建立環境變數。內部的 configMapRef 透過名稱引用 ConfigMap,並選擇其所有鍵值對。將 Pod 新增到叢集,然後檢索其日誌以檢視 printenv 命令的輸出。這應該確認 ConfigMap 中的兩個鍵值對已設定為環境變數

kubectl apply -f env-configmap.yaml
kubectl logs pod/ env-configmap

輸出類似於:

...
username: "k8s-admin"
access_level: "1"
...

有時,Pod 不需要訪問 ConfigMap 中的所有值。例如,你可能有一個只使用 ConfigMap 中的 username 值的其他 Pod。對於這種情況,你可以改用 env.valueFrom 語法,它允許你選擇 ConfigMap 中的單個鍵。環境變數的名稱也可以與 ConfigMap 中的鍵不同。例如

apiVersion: v1
kind: Pod
metadata:
  name: env-configmap
spec:
  containers:
  - name: envars-test-container
    image: nginx
    env:
    - name: CONFIGMAP_USERNAME
      valueFrom:
        configMapKeyRef:
          name: myconfigmap
          key: username

在此清單建立的 Pod 中,你將看到環境變數 CONFIGMAP_USERNAME 設定為 ConfigMap 中 username 的值。ConfigMap 資料中的其他鍵不會複製到環境中。

需要注意的是,Pod 中環境變數名稱允許的字元範圍是受限的。如果任何鍵不符合規則,這些鍵將不會提供給你的容器,但 Pod 仍允許啟動。

不可變 ConfigMap

特性狀態: Kubernetes v1.21 [stable]

Kubernetes 特性“不可變 Secret 和 ConfigMap”提供了一個選項,可以將單個 Secret 和 ConfigMap 設定為不可變。對於廣泛使用 ConfigMap 的叢集(至少有數萬個獨特的 ConfigMap 到 Pod 掛載),阻止對其資料進行更改具有以下優點:

  • 保護你免受可能導致應用程式中斷的意外(或不必要的)更新
  • 透過關閉標記為不可變的 ConfigMap 的監視,顯著減少 kube-apiserver 的負載,從而提高叢集效能。

你可以透過將 immutable 欄位設定為 true 來建立不可變 ConfigMap。例如

apiVersion: v1
kind: ConfigMap
metadata:
  ...
data:
  ...
immutable: true

一旦 ConfigMap 被標記為不可變,就不可能撤銷此更改或修改 databinaryData 欄位的內容。你只能刪除並重新建立 ConfigMap。由於現有 Pod 維護指向已刪除 ConfigMap 的掛載點,建議重新建立這些 Pod。

下一步

最後修改於 2024 年 9 月 11 日下午 6:37(太平洋標準時間):在文件中新增 envFrom 詳細資訊 (#47709) (2ccaf064f8)