【原創】Kuberneters-ConfigMap的實踐

lightinglei發表於2020-08-27

一、什麼是ConfigMap

       ConfigMap翻譯過來即為“配置字典”,在實際的生產環境中,應用程式配置經常需要且又較為複雜,引數、config檔案、變數等如果直接打包到映象中,將會降低映象的可移植性,因此期望有一種方式可以將配置從應用程式中解耦出來,ConfigMap正是在此背景下誕生的,它用於儲存配置資料的鍵值(key-value)對,可以用來儲存單個屬性,也可以用來儲存配置檔案。ConfigMap 跟 secret 很類似,但它可以更方便地處理不包含敏感資訊的字串。

二、適用場景?

     適用於儲存不包含敏感資訊的變數、屬性或檔案。

     比如在一個叢集中,可將應用程式所需的引數、變數、配置檔案存放到ConfigMap中,在開發、測試和生產環境將同1個ConfigMap(前提是同1個namespace)掛載到Pod中,這樣既可以實現配置和容器映象的分離,也可方便的實現統一管理,比如可以利用其熱更新的機制,修改完成後會同步到掛載了此ConfigMap的所有Pod中。

三、ConfigMap的建立

1、檔案目錄建立

支援以目錄的方式建立ConfigMap,其中檔名將作為key,檔案內容作為value,有幾個檔案將會存在幾個鍵值對,如下圖,先建立1個目錄,此目錄下存在兩個檔案

[root@k8s-master confdirtest]# ls
conftest1.txt  conftest.txt
[root@k8s-master consecret]# kubectl create configmap con-dir-test --from-file=confdirtest/
configmap/con-dir-test created

其格式為kubectl creat configmap "configmap的名字" --from-file="目錄"/,這種適用於將某個目錄下的所有檔案作為key,檔案內容作為value進行建立。

[root@k8s-master consecret]# kubectl get cm | grep con-dir-test
con-dir-test          2      20s
[root@k8s-master consecret]# kubectl describe cm con-dir-test 
Name:         con-dir-test
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
conftest.txt:
----
name=this is test                #檔案conftest.txt的內容

conftest1.txt:
----
name=this is test1               #檔案conftest1.txt的內容

Events:  <none>

2、檔案方式建立

     --from-file的方式除了用於目錄的方式之外,同樣還適用於指定檔案的方式進行建立,其中檔名稱將作為key名稱,檔案內容作為value,如下所示,先建立一個配置檔案testconf.cfg

[root@k8s-master consecret]# cat testconf.cfg 
listenport=8080
name=testconf
serverip=10.0.0.1

接下里將其生成1個configmap檔案,如下所示,其格式為:kubectl create configmap "configmap名稱" --from-file=“檔名”

[root@k8s-master consecret]# kubectl create configmap conf-file-test --from-file=testconf.cfg 
configmap/conf-file-test created
[root@k8s-master consecret]# kubectl describe cm conf-file-test 
Name:         conf-file-test
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
testconf.cfg:
----
listenport=8080
name=testconf
serverip=10.0.0.1

Events:  <none>

此方式適用於將某個或多個配置檔案生成同一個configmap檔案的場景

3、直接建立key-value 

 可直接指定需要data的key-value鍵值對進行建立,如下所示,使用"--from-literal"選項可在命令列直接建立configmap物件,若是建立多個,可重複多次進行建立,但是注意其key的名稱不可重複,這種方式適用於直接指定key-value的方式進行建立。

[root@k8s-master consecret]# kubectl create configmap con-key-value --from-literal=key1=name1
configmap/con-key-value created
[root@k8s-master consecret]# kubectl describe cm con-key-value 
Name:         con-key-value
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
key1:
----
name1
Events:  <none>
[root@k8s-master consecret]# kubectl create configmap con-key-value-test --from-literal=class.1=202 --from-literal=class.2=502
configmap/con-key-value-test created
[root@k8s-master consecret]# kubectl describe cm con-key-value-test 
Name:         con-key-value-test
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
class.1:
----
202
class.2:
----
502
Events:  <none>

4、匯入環境變數建立

 可將環境變數以--from-env-file的方式進行建立,其格式為:kubectl crete configmap "configmap的名稱" --from-env=file=環境變數檔案.env

[root@k8s-master consecret]# echo -e "testenv1=1\testenv2=2" | tee configtest.env
testenv1=1    estenv2=2
[root@k8s-master consecret]# kubectl create configmap conf-env-test --from-env-file=configtest.env 
configmap/conf-env-test created
[root@k8s-master consecret]# kubectl describe cm conf-env-test
Name:         conf-env-test
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
testenv1:
----
1        estenv2=2
Events:  <none>

四、ConfigMap的使用

1、熱更新(目錄形式掛載)

首先先成功建立一個ConfigMap

[root@k8s-master consecret]# cat conf-delete-test.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: zltest-conf-delete
  namespace: default
data:
  zltest.show: delete-test
[root@k8s-master consecret]# kubectl delete deployment dep-deleye-conf-test 
deployment.apps "dep-deleye-conf-test" deleted
[root@k8s-master consecret]# kubectl create -f conf-delete-test.yaml 
configmap/zltest-conf-delete created
[root@k8s-master consecret]# kubectl get cm | grep zltest-conf-delete
zltest-conf-delete    1      44s

將其以卷目錄形式掛載到Pod容器中,建立一個deployment

[root@k8s-master zhanglei]# cat dep-delete-con.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dep-deleye-conf-test
  namespace: default
  labels:
    app: nginx-delete-conf-test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deployment-delete
  template:
    metadata:
      labels:
        app: nginx-deployment-delete
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - name: testconf
          containerPort: 80
        volumeMounts:
        - name: nginxconf
          mountPath: /data/deletetest
      volumes:
      - name: nginxconf  
        configMap:
          name: zltest-conf-delete
[root@k8s-master zhanglei]# kubectl create -f dep-delete-con.yaml 
deployment.apps/dep-deleye-conf-test created
[root@k8s-master zhanglei]# kubectl get deployment |grep dep-deleye-conf-test
dep-deleye-conf-test   2/2     2            2           56s

執行以上的步驟後,名為zltest-conf-delete的ConfigMap已被成功掛載到Pod的容器中,如果在執行的過程中,修改下ConfigMap的檔案,會出現怎樣的情況呢?先edit下ConfigMap,增加一個鍵值對

[root@k8s-master zhanglei]# kubectl describe cm zltest-conf-delete 
Name:         zltest-conf-delete
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
zltest.show:
----
delete-test
Events:  <none>
[root@k8s-master consecret]# kubectl edit cm zltest-conf-delete 

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  zltest.show: delete-test
  addkey: addvalue                      # 新增的鍵值對
kind: ConfigMap
metadata:
  creationTimestamp: "2020-07-23T11:29:11Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:zltest.show: {}
    manager: kubectl
    operation: Update
    time: "2020-07-23T11:29:11Z"
  name: zltest-conf-delete
  namespace: default

[root@k8s-master consecret]# kubectl edit cm zltest-conf-delete
configmap/zltest-conf-delete edited

驗證下新增的鍵值對是否會同步熱更新到Pod的容器中,通過exec的方式登入到容器中進行檢視,新新增的鍵值對以同步更新到Pod的容器中,

不需要以容器進行額外的操作,這是卷目錄的形式掛載的熱更新,但是若是通過環境變數env或者通過檔案的形式掛載到容器中,是不會支援熱更新的,這裡需要注意下。

[root@k8s-master consecret]# kubectl exec -it dep-deleye-conf-test-869747b77f-67w9h -- bash
root@dep-deleye-conf-test-869747b77f-67w9h:/# cd data
root@dep-deleye-conf-test-869747b77f-67w9h:/data# ls
deletetest
root@dep-deleye-conf-test-869747b77f-67w9h:/data# cd deletetest/
root@dep-deleye-conf-test-869747b77f-67w9h:/data/deletetest# ls
addkey    zltest.show

如果刪除已將掛載到Pod中的容器的ConfigMap會出現怎樣的情況呢,先刪除ConfigMap,然後再次登入到容器中進行驗證

[root@k8s-master consecret]# kubectl delete cm zltest-conf-delete 
configmap "zltest-conf-delete" deleted
[root@k8s-master consecret]# kubectl exec -it dep-deleye-conf-test-869747b77f-67w9h -- bash
root@dep-deleye-conf-test-869747b77f-67w9h:/data/deletetest# ls
addkey    zltest.show

若未對Pod進行刪除的操作,刪除ConfigMap成功,但是掛載到容器的目錄依然會存在,並不會一起被刪除,此時若刪除Pod,副本控制器會重新拉

起1個Pod,會建立成功嗎?接下來驗證下

[root@k8s-master consecret]# kubectl get pod | grep dep-deleye-conf-test
dep-deleye-conf-test-869747b77f-kgzqt   1/1     Running             0          134m
dep-deleye-conf-test-869747b77f-mf6vc   0/1     ContainerCreating   0          2m13s

重新拉起Pod一直會是ContainerCreating狀態,詳細檢視下原因

[root@k8s-master consecret]# kubectl describe pod dep-deleye-conf-test-869747b77f-mf6vc
Name:           dep-deleye-conf-test-869747b77f-mf6vc
Namespace:      default
Priority:       0
Node:           k8s-master/192.168.126.129
Start Time:     Thu, 23 Jul 2020 21:47:00 +0800
Labels:         app=nginx-deployment-delete
                pod-template-hash=869747b77f
Annotations:    <none>
Status:         Pending
IP:             
IPs:            <none>
Controlled By:  ReplicaSet/dep-deleye-conf-test-869747b77f
Containers:
  nginx:
    Container ID:   
    Image:          nginx:latest
    Image ID:       
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       ContainerCreating
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /data/deletetest from nginxconf (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  nginxconf:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      zltest-conf-delete
    Optional:  false
  default-token-74s86:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-74s86
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason       Age                From                 Message
  ----     ------       ----               ----                 -------
  Normal   Scheduled    <unknown>          default-scheduler    Successfully assigned default/dep-deleye-conf-test-869747b77f-mf6vc to k8s-master
  Warning  FailedMount  11s (x8 over 75s)  kubelet, k8s-master  MountVolume.SetUp failed for volume "nginxconf" : configmap "zltest-conf-delete" not found

可以看到是FailedMount,volume異常了,K8S中刪除的時候是不會判斷這個依賴關係的,因此在生產的實際使用中,這點還是需要注意。

2、通過環境變數引入

    除了通過volume的方式掛載到容器中使用之外,還可將configmap作為環境變數的方式引入到容器中,這裡以con-key-value-test作為例子

[root@k8s-master consecret]# kubectl get cm |grep con-key-value-test
con-key-value-test    2      34m
[root@k8s-master zhanglei]# cat dep-conf-test.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-conf-env-test
  namespace: default
  labels:
    app: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-deployment
  template:
    metadata:
      labels:
        app: nginx-deployment
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        #  command: [ "/bin/bash","-c","env" ]
        ports:
        - containerPort: 80
        env:
        - name: test-env1-conf                        # 環境變數名稱1
          valueFrom:
            configMapKeyRef:
              name: con-key-value-test 
              key: class.1                            # 指定key名稱即可
        - name: test-env2-conf                        # 環境變數名稱2
          valueFrom:
            configMapKeyRef:
              name: con-key-value-test                # 引入configmap
              key: class.2
[root@k8s-master zhanglei]# kubectl create -f dep-conf-test.yaml 
deployment.apps/nginx-conf-env-test created
[root@k8s-master zhanglei]# kubectl get pod |grep env-test
nginx-conf-env-test-56f5c9b88-xt86x        1/1     Running            0          34s

 可以看到Pod處於running的狀態,登入到容器驗證下以存在環境變數,如下所示,驗證成功,值得注意的是,這種方式相當於新生成的環境變數指向configmap中的key所對應的value

root@nginx-conf-env-test-56f5c9b88-xt86x:/# ls
bin   docker-entrypoint.d   home   media  proc    sbin  tmp
boot  docker-entrypoint.sh  lib    mnt      root    srv   usr
dev   etc            lib64  opt      run    sys   var
root@nginx-conf-env-test-56f5c9b88-xt86x:/# env
test-env2-conf=502                   # 環境變數=原class.1的value
test-env1-conf=202

 

五、總結

 configmap是K8s中重要的配置管理方式,本文介紹了configmap的概念、使用場景、多種建立的方式、最後介紹瞭如何進行使用,希望能給大家的學習帶來一點幫助。

 

 作者簡介:雲端計算容器\Docker\K8s\Serverless方向產品經理,學點技術,為更好地設計產品。

相關文章