一、什么是 ConfigMap?
ConfigMap?是 Kubernetes 中用于存儲非敏感配置數據的 API 對象,支持以鍵值對(Key-Value)或文件的形式存儲配置,允許將配置與鏡像解耦,實現配置的集中管理和動態更新。
二、主要用途
- 存儲配置數據
- 應用的配置文件(如?
config.properties
、app.yaml
)。- 環境變量(如數據庫連接字符串、API 地址)。
- 命令行參數或啟動腳本。
- 解耦配置與鏡像
- 同一鏡像可通過不同 ConfigMap 適配不同環境(如開發環境使用本地數據庫,生產環境使用遠程數據庫)。
- 使用?ConfigMap 可以統一管理不同環境(開發、測試、生產)的配置差異。
- 解耦應用配置與鏡像,避免硬編碼配置到鏡像中。
- 動態更新配置
- 修改 ConfigMap 后,可通過重啟 Pod 或熱加載(依賴應用支持)使新配置生效。
三、局限性
- ConfigMap 并不提供保密或者加密功能。 如果你想存儲的數據是機密的,請使用 Secret。
- 在 ConfigMap 中保存的數據不可超過 1 MiB。如果你需要保存超出此尺寸限制的數據,你可能希望考慮掛載存儲卷 或者使用獨立的數據庫或者文件服務。
- ConfigMap 的熱加載依賴應用自己實現。
四、創建 ConfigMap 的方式
ConfigMap 可通過?kubectl 命令或?YAML 文件創建,支持三種數據源:文件、目錄、字面量。
4.1、通過 kubectl 命令創建
4.1.1、使用字面量創建
kubectl create configmap my-config --from-literal=username=admin --from-literal=password=123456
- ?--from-literal=key1=config1 --from-literal=key2=config2
- literal 字面量的意思
- configmap 可以簡寫為 cm
kubectl describe cm my-config
?
4.1.2、使用文件創建
# 單個文件
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt# 文件名 file1.txt 作為 key
kubectl create configmap my-config --from-file=/path/to/bar/file1.txt# 多個文件
kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
- ?單個文件
vim config.properties### 文件內容如下
server.port=8080
application.name=myapp
kubectl create configmap my-config --from-file=config=./config.properties
# 文件名作為 key
kubectl create cm my-config --from-file=config.properties
- ?多個文件
vim db.properties### 文件內容如下
datasource.username=root
datasource.password=123456
datasource.url=jdbc:mysql://localhost:3306/order
kubectl create configmap my-config --from-file=config.properties --from-file=db.properties
?
4.1.3、使用目錄創建
kubectl create configmap my-config --from-file=path/to/bar
mkdir conf
cd conf
vim application.yaml
### 文件內容如下
server:port: 8080spring:cloud:nacos:discovery:username: nacospassword: nacosgroup: DEFAULT_GROUPserver-addr: 127.0.0.1:8848application:name: order-service
###
vim db.properties
### 文件內容如下
datasource.username=root
datasource.password=123456
datasource.url=jdbc:mysql://localhost:3306/order
###
cd ..
?
kubectl create cm my-config --from-file=conf
?
4.2、通過 YAML 文件創建
configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:name: my-config
data:username: "admin"password: "123456"application.yaml: |server:port: 8080db.properties: |datasource.username=rootdatasource.password=123456
?| 表示下面的內容為多行。
kubectl apply -f configmap.yaml
?
五、在 Pod 中使用 ConfigMap
ConfigMap 可通過?環境變量?或?Volume 掛載?注入到容器中。
我們以 4.2 節創建的 my-config 為例,來講解如何在?Pod 中使用 ConfigMap。
5.1、作為環境變量注入 env
apiVersion: v1
kind: Pod
metadata:name: envcm-pod
spec:restartPolicy: Nevercontainers:- name: envcm-podimage: alpine:latest imagePullPolicy: IfNotPresentcommand: ["sleep", "3600"]env:- name: USERNAME # 定義容器中的環境變量valueFrom:configMapKeyRef:name: my-config # ConfigMap 的名字key: username # ConfigMap 中的 key - name: PASSWORDvalueFrom:configMapKeyRef:name: my-configkey: password
- ?像 Alpine 鏡像,或者基于?Alpine 制作的工具鏡像,容器內沒有運行服務,需要啟動后休眠一段時間,防止容器被 K8S 殺掉。
- restartPolicy: Never 休眠結束后容器退出就退出了,不需要?K8S 重啟該容器。默認是 Always 總是重啟。設為 Never 防止浪費系統資源。
- ?進入容器查看環境變量
kubectl exec -it envcm-pod -- /bin/sh
/# env
USERNAME=admin
PASSWORD=123456
?5.2、作為環境變量注入 envFrom
apiVersion: v1
kind: Pod
metadata:name: envfrom-pod
spec:restartPolicy: Nevercontainers:- name: envcm-podimage: alpine:latest imagePullPolicy: IfNotPresentcommand: ["sleep", "3600"]envFrom:- configMapRef:name: my-config
?以整個 ConfigMap 作為環境變量數據源。
- ??進入容器查看環境變量
kubectl exec -it envfrom-pod -- /bin/sh
/ # env
5.3、環境變量方式使用的 ConfigMap 數據不會被自動更新
以環境變量方式使用的 ConfigMap 數據不會被自動更新。 更新這些數據需要重新啟動 Pod。
# 編輯 ConfigMap
kubectl edit cm my-config
# 把 password 從 123456 -> 456789
# 像 vim 一樣 wq 保存退出
- ?進入容器查看環境變量
kubectl exec -it envcm-pod -- /bin/sh
/# env
USERNAME=admin
# 還是 123456
PASSWORD=123456 kubectl exec -it envfrom-pod -- /bin/sh
# 還是 123456
password=123456
?5.4、通過 Volume 掛載為文件
apiVersion: v1
kind: Pod
metadata:name: volumes-pod
spec:restartPolicy: Nevervolumes:- name: volumes-name # 卷的名字configMap:name: my-config # ConfigMap 的名字containers:- name: volumes-podimage: alpine:latest imagePullPolicy: IfNotPresentcommand: ["sleep", "3600"]volumeMounts:- name: volumes-namemountPath: /data/conf # 掛載到容器哪個目錄
- ??進入容器查看文件
kubectl exec -it volumes-pod -- /bin/sh
以 Volume 形式掛載 ConfigMap,ConfigMap 每一個 key 都會生成一個文件。??
- ???進入容器查看環境變量
kubectl exec -it volumes-pod -- /bin/sh
/# env
環境變量中不會有配置信息
?5.5、熱加載
# 編輯 ConfigMap
kubectl edit cm my-config
# 把 password 從 456789 -> 111111
# 像 vim 一樣 wq 保存退出
- ????進入容器查看文件
kubectl exec -it volumes-pod -- /bin/sh
容器內文件的值被更新了。但是會有一定的延遲。具體延遲多少,官方介紹取決于高速緩存類型。
5.6、items 選取 key
我們知道,以 Volume 形式掛載 ConfigMap,ConfigMap 的每一個 key 都會生成一個文件。
對于 4.2 的 ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:name: my-config
data:username: "admin"password: "123456"application.yaml: |server:port: 8080db.properties: |datasource.username=rootdatasource.password=123456
會生成 username、password、application.yaml、db.properties 這四個文件。
那么,如果我們希望普通的屬性,像 username、password 注入到環境變量,而?application.yaml、db.properties 這種,生成文件,要怎么做呢?
apiVersion: v1
kind: Pod
metadata:name: volumes-items-pod
spec:restartPolicy: Nevervolumes:- name: volumes-name # 卷的名字configMap:name: my-config # ConfigMap 的名字items:- key: "application.yaml" # ConfigMap 的 keypath: "application.yaml" # key 映射成的文件- key: "db.properties"path: "db.properties" containers:- name: volumes-podimage: alpine:latest imagePullPolicy: IfNotPresentcommand: ["sleep", "3600"]env:- name: USERNAME # 定義容器中的環境變量valueFrom:configMapKeyRef:name: my-config # ConfigMap 的名字key: username # ConfigMap 中的 key - name: PASSWORDvalueFrom:configMapKeyRef:name: my-configkey: password volumeMounts:- name: volumes-namemountPath: /data/conf
通過 .volumes.configMap.items 選取需要做成卷的 ConfigMap key-value。
kubectl exec -it volumes-items-pod -c volumes-pod -- /bin/sh
/ # env
USERNAME=admin
PASSWORD=111111
5.7、名稱空間限定
ConfigMap 是一種名稱空間限定的資源。某一名稱空間下的 Pod,只能引用同一名稱空間下的?ConfigMap。
對于?4.2 的 ConfigMap,我們沒有寫,就是默認 default 名稱空間下。現在我們 dev 名稱空間下的一個 Pod:
apiVersion: v1
kind: Pod
metadata:name: cmns-podnamespace: dev
spec:restartPolicy: Nevercontainers:- name: cmns-podimage: alpine:latest imagePullPolicy: IfNotPresentcommand: ["sleep", "3600"]env:- name: USERNAME # 定義容器中的環境變量valueFrom:configMapKeyRef:name: my-config # ConfigMap 的名字key: username # ConfigMap 中的 key - name: PASSWORDvalueFrom:configMapKeyRef:name: my-configkey: password
容器會報?CreateContainerConfigError 起不來。
5.8、多環境配置
ConfigMap 是名稱空間限定的資源,所以在多名稱空間環境下(比如 dev、prod),我們可以給每個名稱空間創建同名的配置,然后在不同名稱空間下的 Pod 引用這些配置。
# 創建名稱空間
kubectl create ns dev
kubectl create ns prod
# 創建 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:name: app-confignamespace: dev
data:username: "dev"password: "123456"
###
apiVersion: v1
kind: ConfigMap
metadata:name: app-confignamespace: prod
data:username: "prod"password: "123456"
- ?dev 下啟動 Pod:
apiVersion: v1
kind: Pod
metadata:name: cmns-podnamespace: dev
spec:restartPolicy: Nevercontainers:- name: cmns-podimage: alpine:latest imagePullPolicy: IfNotPresentcommand: ["env"]env:- name: USERNAME # 定義容器中的環境變量valueFrom:configMapKeyRef:name: app-config # ConfigMap 的名字key: username # ConfigMap 中的 key - name: PASSWORDvalueFrom:configMapKeyRef:name: app-configkey: password
- prod 下啟動 Pod:
apiVersion: v1
kind: Pod
metadata:name: cmns-podnamespace: prod
spec:restartPolicy: Nevercontainers:- name: cmns-podimage: alpine:latest imagePullPolicy: IfNotPresentcommand: ["env"]env:- name: USERNAME # 定義容器中的環境變量valueFrom:configMapKeyRef:name: app-config # ConfigMap 的名字key: username # ConfigMap 中的 key - name: PASSWORDvalueFrom:configMapKeyRef:name: app-configkey: password
六、Java 項目使用 ConfigMap 熱加載配置
到此,我們知道了 ConfigMap 如果作為 Spring Boot 項目的配置的話,存在一些不足:
1、時效性不高。ConfigMap 可以作為配置文件掛載進容器文件系統,但是這中間會有一些延遲。而且,Spring Boot 項目在啟動的時候加載了一次 application.yml 之類的配置文件后,就不會再加載了。這個時候?ConfigMap 再更新配置文件其實沒什么意義。
2、時效性更好的環境變量的方式,ConfigMap 卻無法更新。
所以,Spring Boot?項目需要自己監聽 ConfigMap 變化,然后更新 Environment。