應(yīng)用部署的一個最佳實踐是將應(yīng)用所需的配置信息與程序進行分離,這樣可以使得應(yīng)用程序被更好地復(fù)用,通過不同的配置也能實現(xiàn)更靈活的功能。
將應(yīng)用打包為容器鏡像后,可以通過環(huán)境變量或者外掛文件的方式在創(chuàng)建容器時進行配置注入,但在大規(guī)模容器集群的環(huán)境中,對多個容器進行不同的配置將變得非常復(fù)雜。
從Kubernetes v1.2開始提供了一種統(tǒng)一的應(yīng)用配置管理方案——ConfigMap。本節(jié)對ConfigMap的概念和用法進行詳細描述。
1. ConfigMap概述
ConfigMap供容器使用的典型用法如下:
- 生成為容器內(nèi)的環(huán)境變量;
- 設(shè)置容器啟動命令的啟動參數(shù)(需設(shè)置為環(huán)境變量);
- 以Volume的形式掛載為容器內(nèi)部的文件或目錄。
2. 創(chuàng)建ConfigMap資源對象
2.1 通過yaml配置文件方式創(chuàng)建
下面的例子cm-appvars.yaml描述了將幾個應(yīng)用所需的變量定義為ConfigMap的用法:
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-appvars
data:
apploglevel: info
appdatadir: /var/data
執(zhí)行kubectl create命令創(chuàng)建該ConfigMap:
kubectl create -f cm-appvars.yaml
查看創(chuàng)建好的ConfigMap:
# 查看ConfigMap列表
kubectl get configmap
# 查看ConfigMap cm-appvars
kubectl describe configmap cm-appvars
# 以yaml的形式輸出cm-appvars
kubectl get configmap cm-appvars -o yaml
2.2 通過kubectl命令行方式創(chuàng)建
不使用yaml文件,直接通過kubectl create configmap也可以創(chuàng)建ConfigMap,可以使用參數(shù)--from-file或--from-literal指定內(nèi)容,并且可以在一行命令中指定多個參數(shù)。
(1)通過--from-file參數(shù)從文件中進行創(chuàng)建,可以指定key的名稱,也可以在一個命令行中創(chuàng)建包含多個key的ConfigMap,語法為:
kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source
(2)通過--from-file參數(shù)從目錄中進行創(chuàng)建,該目錄下的每個配置文件名稱都被設(shè)置為key,文件的內(nèi)容被設(shè)置為value,語法為:
kubectl create configmap NAME --from-file=config-files-dir
(3)--from-literal從文本中進行創(chuàng)建,直接將指定的key-value對創(chuàng)建為ConfigMap的內(nèi)容,語法為:
kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2
3. 使用ConfigMap
容器應(yīng)用對ConfigMap的使用有以下兩種方法:
- 通過環(huán)境變量獲取ConfigMap
- 通過Volume掛載的方式將ConfigMap中的內(nèi)容掛載為容器內(nèi)部的文件或目錄
3.1 在Pod中使用ConfigMap
(1)通過環(huán)境變量方式使用ConfigMap
以前面創(chuàng)建的ConfigMap “cm-appvars” 為例:
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-appvars
data:
apploglevel: info
appdatadir: /var/data
在Pod “cm-test-pod” 的定義中,將ConfigMap “cm-appvars” 中的內(nèi)容以環(huán)境變量(APPLOGLEVEL和APPDATADIR)設(shè)置為容器內(nèi)部的環(huán)境變量,容器的啟動命令將顯示這兩個環(huán)境變量的值("env | grep APP"):
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: cm-test
image: busybox
command: ["/bin/sh", "-c", "env | grep APP"]
env:
- name: APPLOGLEVEL
valueFrom:
configMapKeyRef:
name: cm-appvars
key: apploglevel
- name: APPDATADIR
valueFrom:
configMapKeyRef:
name: cm-appvars
key: appdatadir
restartPolicy: Never
使用kubectl create -f命令創(chuàng)建該Pod,由于是測試Pod,所以該Pod在執(zhí)行完啟動命令后將會退出,并且不會被系統(tǒng)自動重啟(restartPolicy: Never):
kubectl create -f cm-test-pod.yaml
使用kubectl get pods --show-all 查看已經(jīng)停止的Pod
查看該Pod的日志,可以看到啟動命令“env | grep APP”的執(zhí)行結(jié)果如下:
$ kubectl logs cm-test-pod
APPDATADIR=/var/data
APPLOGLEVEL=info
從Kubernetes v1.6開始,引入了一個新的字段 envFrom ,實現(xiàn)在Pod環(huán)境內(nèi)將ConfigMap(也可用于Secret資源對象)中所定義的key=value自動生成為環(huán)境變量:
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: test-container
image: busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: cm-appvars
restartPolicy: Never
通過這個定義,在容器內(nèi)部將生成如下環(huán)境變量:
apploglevel=info
appdatadir=/var/data
需要說明的是,環(huán)境變量的名稱受POSIX命名規(guī)范([a-zA-Z_][a-zA-Z0-9_]*)約束,不能以數(shù)字開頭。
如果包含非法字符,則系統(tǒng)將跳過該條環(huán)境變量的創(chuàng)建,并記錄一個Event來描述環(huán)境變量無法生成,但不會阻止Pod的啟動。
3.2 在 Pod 命令里使用 ConfigMap 定義的環(huán)境變量
我們可以利用$(VAR_NAME)這個 Kubernetes 替換變量,在 Pod 的配置文件的command段使用 ConfigMap 定義的環(huán)境變量。
例子如下:
下面的 Pod 配置
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: test-container
image: busybox
command: [ "/bin/sh", "-c", "echo $(APPLOGLEVEL) $(APPDATADIR)" ]
env:
- name: APPLOGLEVEL
valueFrom:
configMapKeyRef:
name: cm-appvars
key: apploglevel
- name: APPDATADIR
valueFrom:
configMapKeyRef:
name: cm-appvars
key: appdatadir
restartPolicy: Never
3.3 通過volumeMount使用ConfigMap
當(dāng)您使用 --from-file 創(chuàng)建 ConfigMap 時, 文件名將作為鍵名保存在 ConfigMap 的 data 段,文件的內(nèi)容變成鍵值。
從 ConfigMap 里的數(shù)據(jù)生成一個卷
下面的例子展示了一個名為 special-config 的 ConfigMap 的配置:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.level: very
special.type: charm
在 Pod 的配置文件里的 volumes 段添加 ConfigMap 的名字。 這會將 ConfigMap 數(shù)據(jù)添加到 volumeMounts.mountPath 指定的目錄里面(在這個例子里是 /etc/config)。 command 段引用了 ConfigMap 里的 special.level.
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
# Provide the name of the ConfigMap containing the files you want
# to add to the container
name: special-config
restartPolicy: Never
Pod 運行起來后, 執(zhí)行這個命令 ("ls /etc/config/") 將產(chǎn)生如下的輸出:
special.level
special.type
添加 ConfigMap 數(shù)據(jù)到卷里指定路徑
使用 path 變量定義 ConfigMap 數(shù)據(jù)的文件路徑。 在我們這個例子里,special.level 將會被掛載在 config-volume 的文件 /etc/config/keys 下.
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh","-c","cat /etc/config/keys" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: special.level
path: keys
restartPolicy: Never
Pod 運行起來后,執(zhí)行命令("cat /etc/config/keys")將產(chǎn)生下面的結(jié)果:
very
3.4 使用ConfigMap的限制條件
使用ConfigMap的限制條件如下:
-
ConfigMap必須在Pod之前創(chuàng)建(除非您把 ConfigMap 標(biāo)志成”optional”)。如果您引用了一個不存在的 ConfigMap, 那這個Pod是無法啟動的。就像引用了不存在的 Key 會導(dǎo)致 Pod 無法啟動一樣。 -
ConfigMap受Namespace限制,只有處于相同的Namespace中的Pod可以引用它; - ConfigMap中的配額管理還未能實現(xiàn);
- kubelet值支持可以被API Server管理的Pod使用ConfigMap。kubelet在當(dāng)前Node上通過
--manifest-url或--config自動創(chuàng)建的靜態(tài)Pod將無法引用ConfigMap; - 在Pod對ConfigMap進行掛載(volumeMount)操作是,容器內(nèi)部
只能掛載為目錄,無法掛載為文件。 - 在掛載到容器內(nèi)部后,目錄中將包含ConfigMap定義的每個item,
如果該目錄下原理還有其他文件,則容器內(nèi)的該目錄會被掛載的ConfigMap覆蓋。