上次線上發佈時,運維同事不小心把測試環境的數據庫密碼打包進了生產鏡像,導致服務啓動失敗。排查後發現,密碼直接硬編碼在配置文件裏,每次環境切換都要手動修改。後來用Kubernetes的Secret存儲密碼,ConfigMap管理普通配置,不僅解決了環境配置混亂的問題,還徹底杜絕了敏感信息泄露的風險。

在K8s集羣中,應用的配置管理是個繞不開的話題。ConfigMap和Secret是K8s提供的兩種配置管理機制,前者適合存儲普通配置(如端口、路徑),後者專門處理敏感信息(如密碼、令牌)。本文結合實際運維場景,詳解這兩種資源的使用方式、區別以及最佳實踐。

一、ConfigMap:非敏感配置的統一管理

ConfigMap用於存儲非敏感的配置數據,它可以將配置與鏡像解耦,讓同一個鏡像能在不同環境中運行。

1. 創建ConfigMap

ConfigMap有兩種創建方式:通過YAML文件聲明,或從文件/目錄直接生成。

方式一:YAML定義

創建app-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config  # ConfigMap名稱
data:
  # 鍵值對形式的配置
  app.port: "8080"
  app.log.level: "INFO"
  # 配置文件內容
  application.properties: |
    spring.datasource.url=jdbc:mysql://db:3306/appdb
    spring.cache.enabled=true

執行創建命令:

kubectl apply -f app-config.yaml

方式二:從文件生成

如果已有配置文件(如app.properties),可以直接生成ConfigMap:

# 從文件創建,鍵名為文件名,值為文件內容
kubectl create configmap app-config --from-file=app.properties

查看創建的ConfigMap:

kubectl get configmap app-config -o yaml

2. 在Pod中使用ConfigMap

ConfigMap可以通過環境變量或文件掛載兩種方式注入Pod。

方式一:作為環境變量

適合需要少量配置的場景:

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:v1
    env:
    - name: APP_PORT  # 環境變量名
      valueFrom:
        configMapKeyRef:
          name: app-config  # 引用的ConfigMap名稱
          key: app.port    # 引用的鍵
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: app.log.level

方式二:作為文件掛載

適合配置文件較多的場景(如Spring Boot的application.properties):

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:v1
    volumeMounts:
    - name: config-volume  # 掛載卷名稱
      mountPath: /app/config  # 容器內掛載路徑
  volumes:
  - name: config-volume
    configMap:
      name: app-config  # 關聯的ConfigMap

掛載後,ConfigMap中的application.properties會以文件形式出現在容器的/app/config目錄下,應用可以直接讀取。

二、Secret:敏感信息的安全存儲

Secret用於存儲敏感信息,它的實現機制與ConfigMap類似,但數據會經過Base64編碼(注意:這不是加密,只是防止明文泄露)。

1. 創建Secret

方式一:YAML定義

創建app-secret.yaml,注意值需要Base64編碼:

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque  # 通用類型
data:
  db.username: YWRtaW4=  # "admin"的Base64編碼
  db.password: cGFzc3dvcmQxMjM=  # "password123"的Base64編碼

生成Base64編碼的命令:

echo -n "admin" | base64  # 輸出 YWRtaW4=

方式二:從字面量創建

無需手動編碼,直接指定鍵值對:

kubectl create secret generic app-secret \
  --from-literal=db.username=admin \
  --from-literal=db.password=password123

查看Secret(默認隱藏值,需加-o yaml顯示):

kubectl get secret app-secret -o yaml

2. 在Pod中使用Secret

Secret的使用方式與ConfigMap類似,支持環境變量和文件掛載。

方式一:作為環境變量

數據庫密碼等配置常用這種方式:

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:v1
    env:
    - name: DB_USERNAME
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: db.username
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: db.password

方式二:作為文件掛載

適合證書類文件(如SSL證書):

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:v1
    volumeMounts:
    - name: secret-volume
      mountPath: /app/secret
      readOnly: true  # 敏感文件建議設為只讀
  volumes:
  - name: secret-volume
    secret:
      secretName: app-secret

掛載後,容器內/app/secret目錄下會生成db.usernamedb.password文件,內容為對應的值。

三、ConfigMap與Secret的核心區別

特性

ConfigMap

Secret

用途

存儲非敏感配置(端口、路徑)

存儲敏感信息(密碼、證書)

數據處理

明文存儲

Base64編碼(非加密)

大小限制

無明確限制(建議不超過1MB)

不超過1MB

訪問控制

無特殊權限控制

可通過RBAC嚴格控制訪問權限

加密支持

不支持

支持靜態加密(需配置加密配置)

四、最佳實踐與避坑指南

1. 合理拆分配置

  • 按環境拆分:app-config-devapp-config-prod,避免不同環境配置混雜;
  • 按功能拆分:db-configlog-config,便於單獨管理和複用。

2. 敏感信息處理

  • 不要把Secret的YAML文件提交到代碼倉庫(即使值是Base64編碼,也能輕易解碼);
  • 生產環境建議開啓K8s的靜態加密功能,確保Secret在etcd中存儲時是加密的:
# 啓用靜態加密(需在kube-apiserver配置)
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: ["secrets"]
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <base64-encoded-32-byte-key>
  - identity: {}

3. 配置更新策略

  • ConfigMap/Secret更新後,通過環境變量注入的配置不會自動生效,需要重啓Pod;
  • 通過文件掛載的配置會在約1分鐘內自動更新(應用需支持熱加載配置,如Spring Cloud Config的@RefreshScope)。

手動觸發更新的小技巧:

# 滾動更新Deployment,使配置生效
kubectl rollout restart deployment app-deploy

4. 權限控制

  • 限制Secret的訪問權限,通過RBAC只允許必要的Pod和用户訪問:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["app-secret"]
  verbs: ["get", "watch", "list"]

5. 避免大型配置

ConfigMap和Secret不宜存儲過大的數據(如超過1MB),否則會影響K8s API的性能。大型配置文件建議用單獨的存儲服務(如NFS、對象存儲),再通過ConfigMap存儲文件路徑。

五、適用場景總結

  • ConfigMap:應用端口、日誌級別、數據庫連接地址(不含密碼)、feature開關等非敏感配置;
  • Secret:數據庫密碼、API令牌、SSL證書、SSH密鑰等需要保密的信息。

兩者結合使用,可以實現配置的集中管理、環境隔離和安全存儲,是K8s應用部署的基礎實踐。

總結

ConfigMap和Secret是K8s配置管理的兩大基石,它們通過"配置與鏡像分離"的思想,解決了多環境部署的配置混亂問題。ConfigMap適合管理普通配置,Secret則專注于敏感信息,雖然Secret的Base64編碼不是加密,但配合RBAC權限控制和靜態加密,能有效保障敏感數據的安全。

實際使用中,要注意合理拆分配置、控制訪問權限、處理配置更新,避免將敏感信息放入ConfigMap或代碼倉庫。掌握這兩個資源的使用,能讓你的K8s應用部署更規範、更安全、更易於維護。