Kubernetes ConfigMap 與 Secret 配置管理
根據 12-Factor App 的原則,應用程式的 設定 (Config) 應該與 程式碼 (Code) 分離。 在 Kubernetes 中,我們使用 ConfigMap 儲存一般設定,使用 Secret 儲存敏感資料(如密碼、金鑰)。
ConfigMap (一般配置)
ConfigMap 用於儲存非機密的 key-value 鍵值對。
建立 ConfigMap
可以用宣告式 YAML 或指令式建立。
A. 指令式 (Imperative):
# 從 literal 建立
kubectl create configmap game-config \
--from-literal=player_lives=3 \
--from-literal=level=easy
# 從檔案建立 (檔名作為 key,內容作為 value)
kubectl create configmap game-config-file --from-file=./config/game.properties
B. 宣告式 YAML (Declarative):
game-config.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: game-config
data:
player_lives: '3'
level: 'easy'
# 也可以放整個設定檔內容
ui.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
建立或更新 ConfigMap:
kubectl apply -f game-config.yaml
刪除 ConfigMap:
kubectl delete -f game-config.yaml
# 或指定名稱刪除
kubectl delete configmap game-config
在 Pod 中使用 ConfigMap
方式 A: 注入為特定環境變數 (valueFrom)
spec:
containers:
- name: game
image: my-game
env:
- name: PLAYER_LIVES
valueFrom:
configMapKeyRef:
name: game-config
key: player_lives
方式 B: 注入所有 Key 為環境變數 (envFrom)
這會將 ConfigMap 中所有的 key 直接轉為環境變數 (例如 PLAYER_LIVES=3, LEVEL=easy)。
spec:
containers:
- name: game
image: my-game
envFrom:
- configMapRef:
name: game-config
方式 C: 掛載為檔案 (Volume Mount)
這會將 ConfigMap 中的每個 key 變成一個檔案。適合設定檔 (config file)。
spec:
volumes:
- name: config-volume
configMap:
name: game-config
containers:
- name: game
volumeMounts:
- name: config-volume
mountPath: /etc/config # 檔案會出現在這裡
ConfigMap 更新與熱重載 (Hot Reload)
這是一個常見的面試題與實務坑點:
- 環境變數 (Environment Variables): Pod 啟動時讀取一次就固定了。如果修改了 ConfigMap,Pod 不會自動更新。必須重啟 Pod (刪除 Pod 讓 Deployment 重建) 才能生效。
- 掛載檔案 (Volume Mount): Kubernetes 會定期同步 ConfigMap 的變更有已掛載的 Volume。應用程式會看到檔案內容改變(通常有延遲,約 1 分鐘內)。前提是應用程式要有邏輯去監聽或重新讀取設定檔。
Secret (敏感資料)
Secret 與 ConfigMap 類似,但專門用於存放敏感資訊。Secret 預設會以 Base64 編碼儲存。
建立 Secret
A. 指令式:
kubectl create secret generic db-user-pass \
--from-literal=username=admin \
--from-literal=password=123456
B. 宣告式 YAML:
資料必須先手動轉 Base64。
echo -n 'admin' | base64 # YWRtaW4=
echo -n '123456' | base64 # MTIzNDU2
secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: db-user-pass
type: Opaque # 預設類型,表示任意資料
data:
username: YWRtaW4=
password: MTIzNDU2
建立 Secret:
kubectl apply -f secret.yaml
刪除 Secret:
kubectl delete -f secret.yaml
# 或指定名稱刪除
kubectl delete secret db-user-pass
在 Pod 中使用 Secret
用法與 ConfigMap 幾乎完全相同 (env, envFrom, volume),只是關鍵字改為 secret 相關。
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-user-pass
key: password
特殊類型的 Secret
除了預設的 Opaque,還有幾種常用類型:
kubernetes.io/dockerconfigjson: 用於拉取 Private Registry 影像 (Private Image Pull Secret)。kubernetes.io/tls: 用於存放 TLS/SSL 憑證 (tls.crt,tls.key),常用於 Ingress HTTPS 設定。
建立 TLS Secret 範例:
kubectl create secret tls my-tls-secret --cert=path/to/cert.crt --key=path/to/key.key
常用操作指令 (Cheat Sheet)
這裡整理了管理 ConfigMap (cm) 與 Secret 的常用 kubectl 指令。
查詢與檢視
# 列出所有 ConfigMap
kubectl get cm
# 列出所有 Secret
kubectl get secret
# 查看詳細資訊 (除錯用)
kubectl describe cm game-config
kubectl describe secret db-user-pass
# 查看 YAML 內容 (會顯示 Base64 編碼後的 Secret)
kubectl get secret db-user-pass -o yaml
解碼 Secret (Decoding)
當你在 debug 時想看 Secret 裡面的真實內容,可以使用以下技巧:
# 取得 Secret 並用 jsonpath 提取特定欄位,再用 base64 解碼
kubectl get secret db-user-pass -o jsonpath='{.data.password}' | base64 --decode
# 或是直接安裝好用的插件 (如果有的話),例如 ksd (kubernetes-secret-decode)
編輯與刪除
# 直接編輯 (類似 vim 編輯遠端資源,存檔後即時更新 Kubernetes 物件)
kubectl edit cm game-config
kubectl edit secret db-user-pass
# 刪除
kubectl delete cm game-config
kubectl delete secret db-user-pass
安全性注意事項
- Etcd 加密: 預設 Secret 在 Etcd 資料庫中是明文儲存的。建議開啟 Kubernetes 的 Encryption at Rest 功能,確保資料落地時是加密的。
- RBAC 權限: 嚴格限制誰可以
get或watchSecret。 - GitOps 風險: 含有真實 Secret 的 YAML 絕對不能直接 commit 到 Git Repo。
- 解決方案: 使用 Sealed Secrets、External Secrets Operator (整合 AWS Secrets Manager, HashiCorp Vault 等),或是 Helm Secrets。
總結
透過 ConfigMap 與 Secret,我們可以讓同一個 Image 在不同環境 (Dev/Test/Prod) 讀取不同的配置,實現真正的 Build once, Deploy anywhere。