1. 程式人生 > 實用技巧 >Kubernetes 0-1 瞭解ConfigMap

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-configsecond-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-configsecond-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-configConfigMap中包含多個鍵如HOSTPORTUSER_NAMEPASSWORD,我想將這個ConfigMap中所有的鍵都用到我的環境變數中,可以使用如下方式:

...
spec:
  container:
  - image: <some-image>
    envFrom:
    - prefix: DB_
      configMapRef:
        name: second-config
...

容器將會生成DB_HOSTDB_PORTDB_USER_NAMEDB_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.jsonmysettings/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則可以定義為程式中的檔名。