Kubernetes 為一般資料與機密資料提供了原生的組態資源,讓組態的生命週期與應用的生命週期解耦。本章說明 ConfigMap 與 Secret 資源的概念、用法,以及它們的侷限。
問題#
「環境變數組態」模式有兩個明顯缺點:
- 只適合少量變數與簡單組態。
- 定義位置分散、難以追查。 由於環境變數可以在許多地方定義,往往很難找到某個變數的定義;即使找到了,你也無法完全確定它沒有在別處被覆寫——例如 Docker 映像檔中定義的環境變數,可能在執行期被 Kubernetes Deployment 資源取代。
比較好的做法是把所有組態資料集中在一處,而不是散落在各個資源定義檔中。但把整份組態檔的內容塞進一個環境變數也不合理,因此需要多一層間接來換取彈性——這正是 Kubernetes 組態資源所提供的。
解法#
Kubernetes 提供了比純環境變數更靈活的專用組態資源:ConfigMap(通用資料)與 Secret(敏感資料)。
兩者用法相同,都提供鍵值對的儲存與管理。除了實際的資料編碼方式不同(Secret 使用 Base64)之外,兩者在使用上沒有技術差異。以下範例聚焦於 ConfigMap,但同樣適用於 Secret——唯一的大差別是 Secret 的值必須經過 Base64 編碼。
ConfigMap 建立並存有資料後,其鍵可以有兩種用法:
- 作為環境變數的引用,此時鍵就是環境變數的名稱。
- 作為映射到 Pod 掛載 volume 中的檔案,此時鍵被用作檔名。
兩種用法在「更新」行為上有關鍵差異:透過 Kubernetes API 更新 ConfigMap 時,掛載為 volume 的檔案會隨之更新——若應用支援組態檔熱重載,就能立即受益。但被當作環境變數使用的 ConfigMap 項目不會反映更新,因為環境變數在行程啟動後就無法改變。
定義 ConfigMap#
ConfigMap 資源在其 data 區段中包含鍵值對:
apiVersion: v1
kind: ConfigMap
metadata:
name: random-generator-config
data:
PATTERN: Configuration Resource
application.properties: |
# Random Generator config
log.file=/tmp/generator.log
server.port=7070
EXTRA_OPTIONS: "high-secure,native"
SEED: "432576345"ConfigMap 既可作為環境變數存取,也可作為掛載檔案存取。建議在 ConfigMap 中用大寫鍵名表示「供環境變數使用」,用正規檔名表示「供掛載檔案使用」。
如上所示,ConfigMap 也能承載完整組態檔的內容(例如 Spring Boot 的 application.properties)。可以想見,在非平凡的使用案例中,這個區段可能變得相當龐大。
除了手動撰寫完整資源描述,也可以用 kubectl 建立:
kubectl create cm spring-boot-config \
--from-literal=JAVA_OPTIONS=-Djava.security.egd=file:/dev/urandom \
--from-file=application.properties作為環境變數使用#
ConfigMap 可以在任何定義環境變數的地方讀取:
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- env:
- name: PATTERN
valueFrom:
configMapKeyRef:
name: random-generator-config
key: PATTERN若 ConfigMap 有許多項目都要當環境變數消費,逐一列出會很累贅。envFrom 可以一次曝露所有「鍵名本身即合法環境變數名」的項目,並可加上前綴:
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
envFrom:
# 挑出 random-generator-config 中所有可作為環境變數名稱的鍵
- configMapRef:
name: random-generator-config
# 為所有合適的鍵加上 CONFIG_ 前綴
prefix: CONFIG_搭配前面定義的 ConfigMap,這會曝露三個環境變數:
CONFIG_PATTERN、CONFIG_EXTRA_OPTIONS與CONFIG_SEED(application.properties因鍵名不是合法的環境變數名而被略過)。Secret 同樣可以逐項或整批作為環境變數消費,只需把
configMapKeyRef換成secretKeyRef。
作為 volume 掛載#
作為 volume 使用時,整個 ConfigMap 會被投射進該 volume,鍵被當作檔名:
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
volumeMounts:
- name: config-volume
mountPath: /config
volumes:
- name: config-volume
# ConfigMap 支撐的 volume 會含有與項目數相同的檔案,
# 鍵作為檔名,值作為檔案內容
configMap:
name: random-generator-config前述 ConfigMap 以 volume 掛載後,/config 資料夾中會產生兩個檔案:內容如 ConfigMap 所定義的 application.properties,以及只有一行內容的 PATTERN 檔案。
在 volume 宣告中加入額外屬性,可以更細緻地調整組態資料的映射:不必把所有項目都映射成檔案,也可以逐一挑選要曝露的鍵,並指定它以什麼檔名呈現。
Secret 到底有多安全?
Secret 存放 Base64 編碼的資料,在傳給 Pod(作為環境變數或掛載 volume)之前解碼。這點經常被誤認為是安全功能——Base64 編碼並非加密方法,從安全角度看它等同明文。 Secret 中使用 Base64 編碼是為了能存放二進位資料。
那為什麼 Secret 仍被認為比 ConfigMap 安全?因為 Secret 還有其他實作細節(這個領域持續在改進,目前主要是):
- Secret 只被派送到「執行需要它的 Pod」的節點上。
- 在節點上,Secret 存在 tmpfs 記憶體中,絕不寫入實體儲存,並在 Pod 移除時一併移除。
- 在 Etcd 中,Secret 以加密形式儲存。
儘管如此,仍有辦法取得 Secret:以 root 使用者身分存取,甚至只要建立一個 Pod 並掛載該 Secret 即可。
你可以對 Secret 套用基於角色的存取控制(RBAC),只允許具備預定義 service account 的特定 Pod 讀取它。但有能力在某命名空間建立 Pod 的使用者,仍可藉由建立 Pod 在該命名空間內提權——他們可以用權限更高的 service account 執行 Pod,照樣讀到 Secret。換言之,在某命名空間具有 Pod 建立權限的使用者或控制器,可以冒充任何 service account,存取該命名空間中所有的 Secret 與 ConfigMap。
因此,敏感資訊的額外加密往往也需要在應用層級進行。
另一種做法:gitRepo volume(已棄用)#
Kubernetes 還有一種儲存組態的方式是 gitRepo volume:在 Pod 上掛載一個空目錄,並把某個 Git 儲存庫複製進去。把組態放在 Git 的好處是免費獲得版本控管與稽核。
但
gitRepovolume 需要外部存取 Git 儲存庫,而它不是 Kubernetes 資源、可能位於叢集之外,必須另行監控與管理。複製與掛載發生在 Pod 啟動期間,本地複製的 repo 不會隨變更自動更新。
討論#
ConfigMap 與 Secret 讓組態資訊得以存放在專用資源物件中,易於透過 Kubernetes API 管理。
使用它們最重要的優點是:把組態資料的「定義」與「使用」解耦。這種解耦讓我們能獨立於組態之外去管理那些使用組態的物件。
另一個好處是它們是平台的內建功能,不需要像「不可變組態」那樣的自訂建構。
但這些組態資源也有限制:
- 大小上限。 Secret 有 1 MB 的大小限制,無法存放任意大的資料,也不適合放非組態的應用資料。Secret 雖可存二進位資料,但因為必須 Base64 編碼,實際只能放約 700 KB。
- 數量配額。 真實世界的 Kubernetes 叢集通常會對「每個命名空間或專案可用的 ConfigMap 數量」設定個別配額。
所以 ConfigMap 不是萬能鎚。接下來兩章會說明如何用「不可變組態」與「組態範本」處理大型組態資料。
更多資訊#
- Configuration Resource Example
- ConfigMap Documentation
- Secrets Documentation
- Encrypting Secret Data at Rest
- Distribute Credentials Securely Using Secrets
- gitRepo Volumes
- Size Restriction of a ConfigMap