Kubernetes 0-1 瞭解ConfigMap
幾乎所有的應用都需要配置資訊,在K8S部署應用,最佳實踐是將應用的配置資訊(環境變數或者配置檔案)和程式本身分離,這樣配置資訊的更新和複用都可以更簡單,也使得程式更加靈活。
Kubernetes允許將配置選項分離到單獨的資源物件ConfigMap中,本質上是一個鍵值對對映,值可以是一個短string串,也可以是一個完整的配置檔案。
本篇主要介紹ConfigMap資源的建立和使用。
ConfigMap的建立
可以直接通過kubectl create configmap
命令建立,也可以先編寫configmap的yaml檔案再使用kubectl apply -f <filename>
建立,推薦使用後者。
單行命令建立ConfigMap
- 建立一個鍵值對的ConfigMap:
kubectl create configmap first-config --from-literal=user=admin
建立完成之後,使用kubectl describe configmap first-config
檢視,可以看到這個configmap的鍵值內容。
可以使用多組
--from-literal=<key>=<value>
引數,在configmap中定義多組鍵值對。
- 建立一個檔案內容的ConfigMap
假如我當前有一個配置檔案app.json,檔案內容如下:
{ "App": "MyApp", "Version": "v1.0" }
使用以下命令建立ConfigMap:
kubectl create configmap second-config --from-file=app.json
建立完成之後,使用kubectl describe configmap second-config
檢視configmap的鍵值內容:
預設使用檔名稱app.json作為鍵值對的key,也可以通過
--from-file=app_config=app.json
指定key為app_config
;可以使用多組
--from-file=<key>=<filename>
引數,在configmap中定義多組檔案;
--from-file=
後面可以直接跟某個檔案路徑,這樣會將目錄下的所有檔案引入到ConfigMap;
--from-literal
和--from-file
可以共同使用,鍵值合併。
刪除建立的first-config
和second-config
:
kubectl delete configmap first-config
kubectl delete configmap second-config
基於資源清單檔案建立ConfigMap
- 建立一個鍵值對的ConfigMap:
首先定義ConfigMap的資原始檔first-config.yaml,定義如下:
vim first-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: first-config
data:
user: "admin"
使用kubectl apply
命令建立ConfigMap資源:
kubectl apply -f first-config.yaml
建立完成之後,使用kubectl describe configmap first-config
檢視,可以看到這個configmap的鍵值內容,結果與上文第一次建立的first-configmap
是一致的。
可以在
data
下定義多組鍵值對。
- 建立一個檔案內容的ConfigMap
首先定義ConfigMap的資原始檔second-config.yaml,定義如下:
vim second-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: second-config
data:
app.json: |
{
"App": "MyApp",
"Version": "v1.0"
}
使用kubectl apply
命令建立ConfigMap資源:
kubectl apply -f second-config.yaml
建立完成之後,使用kubectl describe configmap second-config
檢視,可以看到這個configmap的鍵值內容,結果與上文第一次建立的second-configmap
是一致的。
可以在
data
下定義多組檔案,也可以和鍵值對一起定義;其本質也是鍵值對,只是value為多行格式的文字內容;
對value有格式要求,”|“接換行並且檔案內容的每行按照key都往後退格。
刪除建立的first-config
和second-config
:
kubectl delete configmap first-config
kubectl delete configmap second-config
ConfigMap的使用
我們建立了ConfigMap後,我們的Pod資源就可以利用了。主要有兩種方式使用ConfigMap:
- 使用ConfigMap作為容器的環境變數
- 使用ConfigMap作為Volume向容器提供檔案
使用ConfigMap作為容器的環境變數
假如有一個名為first-config
的ConfigMap,裡面包含了一個鍵為user
,我想將這個ConfigMap中user
鍵用到我的環境變數USER_NAME
中,可以使用如下方式:
...
env:
- name: USER_NAME
valueFrom:
configMapKeyRef:
name: first-config
key: user
...
如果有一個名為second-config
ConfigMap中包含多個鍵如HOST
,PORT
,USER_NAME
,PASSWORD
,我想將這個ConfigMap中所有的鍵都用到我的環境變數中,可以使用如下方式:
...
spec:
container:
- image: <some-image>
envFrom:
- prefix: DB_
configMapRef:
name: second-config
...
容器將會生成DB_HOST
,DB_PORT
,DB_USER_NAME
,DB_PASSWORD
四個環境變數,prefix
也可以不配置,則直接使用ConfigMap的鍵。
注意:
configMapRef
與上面configMapKeyRef
的區別;- 如果ConfigMap中有一個為
USER-NAME
鍵,那麼將不會生成DB_USER-NAME
的環境變數,因為DB_USER-NAME
不是一個合法的環境變數名稱。
使用ConfigMap作為Volume向容器提供檔案
從這裡開始,結合實際演練可能效果會好一點。
我仍然使用med1tator/helloweb:v1
映象執行模擬應用程式,程式的程式碼在這:https://github.com/Med1tator/for-docker
這個應用程式根目錄下存在mysettings/app.json
和mysettings/secret.json
兩個配置檔案,需要提前說明的是這個映象中已經存在了這兩個檔案,並且檔案內容如下:
我現在將這兩個配置檔案放在我的ConfigMap中,並且內容與映象中略微區別,用於區分程式讀取配置源自ConfigMap,然後使用Volume的形式將檔案掛載到應用中去。
首先,定義ConfigMap檔案如下:
vim helloweb-mysettings.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: helloweb-mysettings
data:
app.json: |
{
"App":"Hello Web [From ConfigMap]",
"Version":"v1 [From ConfigMap]"
}
secret.json: |
{
"UserName":"admin [From ConfigMap]",
"Password":"123456 [From ConfigMap]"
}
定義Pod檔案如下:
vim helloweb-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: helloweb
spec:
containers:
- name: helloweb
image: med1tator/helloweb:v1
ports:
- containerPort: 80
volumeMounts:
- mountPath: /app/mysettings
name: helloweb-mysettings
volumes:
- name: helloweb-mysettings
configMap:
name: helloweb-mysettings
Apply資源:
kubectl apply -f helloweb-mysettings.yaml
kubectl apply -f helloweb-pod.yaml
等待helloweb的Pod起來之後,我們呼叫http://<pod-ip>/configuration/mysettings
檢視掛載的配置檔案是否生效:
helloweb應用訪問
/configuration/mysettings
會獲取app.json和secret.json裡面的總共四個配置項,然後輸出到客戶端。
可以看到,已經獲取到了ConfigMap裡面的配置,進入容器也可以看到裡面的問題件內容:
修改ConfigMap自動更新掛載檔案
現在,如果我想要修改我的配置,比如我的密碼修改成了abcdefg
,我不用重新啟動Pod,我只需要修改ConfigMap檔案:
apiVersion: v1
kind: ConfigMap
metadata:
name: helloweb-mysettings
data:
app.json: |
{
"App":"Hello Web [From ConfigMap]",
"Version":"v1 [From ConfigMap]"
}
secret.json: |
{
"UserName":"admin [From ConfigMap]",
"Password":"abcdefg [From ConfigMap]"
}
然後重新Apply資源:
kubectl apply -f helloweb-mysettings.yaml
配置檔案的更新需要1-2分鐘的時間,我們可以連續觀察檔案的更新情況:
可以看到,過段時間後配置檔案更新了。
這裡遇到了一個小問題,繼續訪問
/configuration/mysettings
,應用程式並沒有熱更新,但是我使用hostPath的Volume形式掛載時,修改配置檔案是可以熱更新的,希望有緣人能給我解答吧。
多檔案目錄下掛載單個檔案
在實際的應用中,可能secret.json
的變動更為頻繁,而app.json
檔案幾乎不會變動,我現在只想使用ConfigMap傳遞secret.json
檔案,而不再傳遞app.json
,這時,修改ConfigMap檔案如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: helloweb-mysettings
data:
secret.json: |
{
"UserName":"admin [From ConfigMap]",
"Password":"123456 [From ConfigMap]"
}
然後,重新Apply資源:
kubectl apply -f helloweb-mysettings.yaml
這時候,我們繼續訪問/configuration/mysettings
:
很遺憾的發現,我們的app.json
的配置項都失效了,我們接著去容器中一探究竟:
原來,app.json檔案已經不存在了。
大概推測一下可以知道,如果使用ConfigMap掛載到容器的一個目錄,那麼該目錄會被ConfigMap所覆蓋。那麼如果只掛載單個目錄呢?使用subPath!
修改Pod檔案如下:
apiVersion: v1
kind: Pod
metadata:
name: helloweb
spec:
containers:
- name: helloweb
image: med1tator/helloweb:v1
ports:
- containerPort: 80
volumeMounts:
- mountPath: /app/mysettings/secret.json
name: helloweb-mysettings
subPath: secret.json
volumes:
- name: helloweb-mysettings
configMap:
name: helloweb-mysettings
mountPath
是容器中目標檔案路徑;
subPath
是ConfgMap檔案的Key值。
然後,重新Apply資源:
kubectl delete -f helloweb-pod.yaml
kubectl apply -f helloweb-pod.yaml
等待Pod執行後,我們訪問/configuration/mysettings
,並檢視mysettings目錄下檔案:
可以看到成功的掛載secret.json
檔案而沒有掛載app.json
檔案,[From ConfigMap]就是證明。
需要額外注意的是,在使用過程中發現,使用subPath
掛載單檔案的話,ConfigMap的更新不會同步更新到容器對應檔案中。這時候的解決辦法是一個目錄只存放一個配置檔案,然後ConfigMap掛載到目錄。
如果一個ConfigMap(app-config)中定義了多個檔案(app1.json、app2.json),但是app1-pod中只會使用到app1.json
,可以使用如下方式:
...
volumeMounts:
- mountPath: /config/path
name: helloweb-mysettings
volumes:
- name: app-config
configMap:
name: app-config
items:
- key: app1.json
path: app.json
items的key用於指定ConfigMap的key,path則可以定義為程式中的檔名。