前言
在 Kubernetes 環境中,應用程式的配置管理是一個重要的課題。我們經常需要將配置資訊與容器映像檔分離,以實現更靈活的部署和管理。Kubernetes 提供了 ConfigMap 和 Secret 兩種資源來處理不同類型的配置資料。本文將深入介紹這兩種資源的建立、使用方式以及最佳實務。
ConfigMap 簡介
ConfigMap 是 Kubernetes 中用於儲存非機密配置資料的物件。它可以儲存環境變數、設定檔內容或其他配置資訊,讓我們能夠將配置與容器映像檔解耦。
ConfigMap 的優點
- 配置與映像檔分離:無需重新建構映像檔即可更改配置
- 環境區隔:不同環境(開發、測試、生產)可使用不同的 ConfigMap
- 集中管理:配置資訊集中在 Kubernetes 中管理
- 版本控制:可透過 GitOps 進行版本控制
ConfigMap 建立與使用
使用 kubectl 建立 ConfigMap
從字面值建立
1
2
3
4
5
6
7
8
| # 建立包含單一鍵值對的 ConfigMap
kubectl create configmap app-config --from-literal=APP_ENV=production
# 建立包含多個鍵值對的 ConfigMap
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--from-literal=LOG_LEVEL=info \
--from-literal=MAX_CONNECTIONS=100
|
從檔案建立
1
2
3
4
5
6
7
8
| # 從單一檔案建立 ConfigMap
kubectl create configmap nginx-config --from-file=nginx.conf
# 從目錄建立 ConfigMap(目錄中所有檔案都會被包含)
kubectl create configmap config-files --from-file=./config/
# 指定鍵名從檔案建立
kubectl create configmap app-config --from-file=app.properties=./application.properties
|
使用 YAML 定義 ConfigMap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data:
# 簡單的鍵值對
APP_ENV: "production"
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
# 多行配置檔內容
app.properties: |
server.port=8080
server.host=0.0.0.0
database.pool.size=10
# JSON 格式配置
config.json: |
{
"apiVersion": "v1",
"features": {
"enableCache": true,
"enableMetrics": true
}
}
|
1
2
3
4
5
| # 套用 ConfigMap 定義
kubectl apply -f configmap.yaml
# 查看 ConfigMap
kubectl get configmap app-config -o yaml
|
Secret 類型與建立
Secret 用於儲存敏感資訊,如密碼、OAuth Token、SSH 金鑰等。與 ConfigMap 不同,Secret 中的資料會以 Base64 編碼儲存,並且 Kubernetes 提供了額外的存取控制機制。
Secret 類型
Kubernetes 支援多種 Secret 類型:
| 類型 | 用途說明 |
|---|
Opaque | 通用型 Secret,預設類型 |
kubernetes.io/service-account-token | ServiceAccount Token |
kubernetes.io/dockerconfigjson | Docker Registry 認證資訊 |
kubernetes.io/basic-auth | 基本認證憑證 |
kubernetes.io/ssh-auth | SSH 認證憑證 |
kubernetes.io/tls | TLS 憑證 |
建立 Opaque Secret
使用 kubectl 建立
1
2
3
4
5
6
7
8
9
10
| # 從字面值建立 Secret
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=secretpassword123
# 從檔案建立 Secret
kubectl create secret generic ssh-key --from-file=id_rsa=./ssh/id_rsa
# 查看 Secret(Base64 編碼)
kubectl get secret db-credentials -o yaml
|
使用 YAML 定義 Secret
1
2
3
4
5
6
7
8
9
10
11
| apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: default
type: Opaque
# 使用 stringData 可直接寫入明文(Kubernetes 會自動編碼)
stringData:
username: admin
password: secretpassword123
connection-string: "postgresql://admin:secretpassword123@db:5432/mydb"
|
或使用預先編碼的 data 欄位:
1
2
3
4
5
6
7
8
9
10
11
| apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
# 值需為 Base64 編碼
# echo -n 'admin' | base64 -> YWRtaW4=
username: YWRtaW4=
# echo -n 'secretpassword123' | base64 -> c2VjcmV0cGFzc3dvcmQxMjM=
password: c2VjcmV0cGFzc3dvcmQxMjM=
|
建立 TLS Secret
1
2
3
4
| # 從憑證檔案建立 TLS Secret
kubectl create secret tls tls-secret \
--cert=./tls.crt \
--key=./tls.key
|
1
2
3
4
5
6
7
8
| apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: <base64-encoded-cert>
tls.key: <base64-encoded-key>
|
建立 Docker Registry Secret
1
2
3
4
5
6
| # 建立 Docker Registry 認證 Secret
kubectl create secret docker-registry regcred \
--docker-server=https://registry.example.com \
--docker-username=user \
--docker-password=password \
--docker-email=user@example.com
|
掛載方式
ConfigMap 和 Secret 可以透過兩種主要方式提供給 Pod:Volume 掛載和環境變數注入。
Volume 掛載
將 ConfigMap 掛載為 Volume
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
# 可選:指定掛載的項目
items:
- key: app.properties
path: application.properties
- key: config.json
path: config.json
|
將 Secret 掛載為 Volume
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-credentials
# 設定檔案權限(選填)
defaultMode: 0400
|
掛載特定項目到指定路徑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.24
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
- name: tls-certs
mountPath: /etc/nginx/ssl
readOnly: true
volumes:
- name: nginx-config
configMap:
name: nginx-config
- name: tls-certs
secret:
secretName: tls-secret
|
環境變數注入
從 ConfigMap 注入環境變數
注入單一鍵值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: APP_ENVIRONMENT
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
|
注入整個 ConfigMap
1
2
3
4
5
6
7
8
9
10
11
12
13
| apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
envFrom:
- configMapRef:
name: app-config
# 可選:為所有鍵加上前綴
prefix: CONFIG_
|
從 Secret 注入環境變數
注入單一鍵值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
|
注入整個 Secret
1
2
3
4
5
6
7
8
9
10
11
| apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
envFrom:
- secretRef:
name: db-credentials
|
完整範例:Deployment 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: myapp:1.0
ports:
- containerPort: 8080
# 環境變數注入
envFrom:
- configMapRef:
name: app-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# Volume 掛載
volumeMounts:
- name: config-files
mountPath: /app/config
- name: tls-certs
mountPath: /app/certs
readOnly: true
volumes:
- name: config-files
configMap:
name: app-config
- name: tls-certs
secret:
secretName: tls-secret
|
最佳實務
1. Secret 安全性管理
啟用 Encryption at Rest
在 API Server 中啟用 Secret 加密:
1
2
3
4
5
6
7
8
9
10
11
12
| # /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
|
使用 RBAC 控制存取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["db-credentials"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-secrets
namespace: production
subjects:
- kind: ServiceAccount
name: app-service-account
namespace: production
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
|
2. 使用外部 Secret 管理工具
考慮整合外部密鑰管理系統:
- HashiCorp Vault:企業級密鑰管理
- AWS Secrets Manager:AWS 原生密鑰服務
- Azure Key Vault:Azure 原生密鑰服務
- External Secrets Operator:同步外部密鑰到 Kubernetes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # External Secrets Operator 範例
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: db-credentials
data:
- secretKey: username
remoteRef:
key: database/credentials
property: username
- secretKey: password
remoteRef:
key: database/credentials
property: password
|
3. ConfigMap 和 Secret 更新策略
使用 Immutable ConfigMap/Secret
1
2
3
4
5
6
7
| apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-v1
data:
APP_ENV: production
immutable: true
|
不可變的 ConfigMap/Secret 優點:
- 防止意外修改
- 提升叢集效能(kubelet 不需要持續監控變更)
- 明確的版本控制
觸發 Pod 重新部署
ConfigMap/Secret 更新時,需要重啟 Pod 才能載入新配置。可透過以下方式:
1
2
3
4
5
6
7
8
9
10
11
| # 在 Deployment 中加入 annotation
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
template:
metadata:
annotations:
# 更新此值以觸發重新部署
configmap-version: "v2"
|
或使用工具如 Reloader 自動監控變更並重啟 Pod。
4. 命名與組織規範
1
2
3
4
5
6
7
| # 建議的命名規範
<application>-<type>-<environment>
# 範例
webapp-config-prod
webapp-secrets-prod
nginx-config-staging
|
5. 避免在 Git 中儲存明文 Secret
- 使用 Sealed Secrets 加密後再提交
- 使用 SOPS 加密 YAML 檔案
- 使用 GitOps 工具的 Secret 管理功能
1
2
| # 使用 kubeseal 建立 Sealed Secret
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
|
6. 定期輪換 Secret
建立 Secret 輪換機制:
1
2
3
4
5
6
7
8
9
10
| # 建立新版本的 Secret
kubectl create secret generic db-credentials-v2 \
--from-literal=username=admin \
--from-literal=password=newpassword456
# 更新 Deployment 使用新 Secret
kubectl set env deployment/web-app --from=secret/db-credentials-v2
# 確認應用正常後,刪除舊 Secret
kubectl delete secret db-credentials-v1
|
常見問題排解
查看 ConfigMap/Secret 內容
1
2
3
4
5
6
7
8
9
| # 查看 ConfigMap
kubectl describe configmap app-config
kubectl get configmap app-config -o yaml
# 查看 Secret(Base64 編碼)
kubectl get secret db-credentials -o yaml
# 解碼 Secret 值
kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d
|
驗證 Pod 中的配置
1
2
3
4
5
6
| # 檢查環境變數
kubectl exec -it <pod-name> -- env | grep APP
# 檢查掛載的檔案
kubectl exec -it <pod-name> -- ls -la /etc/config
kubectl exec -it <pod-name> -- cat /etc/config/app.properties
|
總結
本文介紹了 Kubernetes ConfigMap 與 Secret 的管理方式:
- ConfigMap 建立:從字面值、檔案或 YAML 定義建立配置
- Secret 類型:Opaque、TLS、Docker Registry 等不同類型的 Secret
- 掛載方式:Volume 掛載和環境變數注入兩種主要方式
- 最佳實務:安全性管理、更新策略、命名規範等建議
正確管理 ConfigMap 和 Secret 是維護 Kubernetes 應用程式的重要技能。建議根據應用需求選擇適合的配置方式,並遵循安全最佳實務來保護敏感資訊。
參考資源