1. 程式人生 > 實用技巧 >Kubernetes之ConfigMap詳解及實踐

Kubernetes之ConfigMap詳解及實踐

ConfigMap和Secret是Kubernetes系統上兩種特殊型別的儲存卷,ConfigMap物件用於為容器中的應用提供配置檔案等資訊。但是比較敏感的資料,例如金鑰、證書等由Secret物件來進行配置。它們將相應的配置資訊保存於物件中,而後在Pod資源上以儲存卷的形式掛載並獲取相關的配置,以實現配置與映象檔案的解耦。

容器化應用配置方式

每個應用程式都是可執行程式檔案,例如Nginx、Tomcat、MySQL等,但我們使用中,通常不會通過預設的配置引數來執行應用,一般都需要自定義符合我們場景的配置,那麼就需要定義配置檔案來完成。那我們的應用執行在容器中,應該如何定義配置資訊呢?例如為Tomcat的JVM配置堆記憶體大小等,在容器中啟動時,我們可以向容器命令傳遞引數,將定義好的配置檔案嵌入映象檔案中、通過環境變數(Environment Variables)傳遞配置資料,以及基於Docker卷傳送配置檔案等。

以下將介紹向容器提供配置資訊的幾種方法。

通過命令列引數進行配置

在製作Docker映象時,Dockerfile中的ENTRYPOINT和CMD指令可用於指定容器啟動時要執行的程式及相關引數。CMD指令以列表的形式指定要執行的程式和相關引數,但是如果同時存在ENTRYPOINT指令,則CMD指令中列表的所有元素都將被作為由ENTRYPOINT指定程式的命令列引數。另外在基於某映象使用Docker命令建立容器時,可以在命令列向ENTRYPOINT中的程式傳遞額外的自定義引數,甚至還可以修改要執行的應用程式本身,例如以下命令使用docker run建立並啟動容器的格式為:
docker run [OPTINS] IMAGE [COMMAND] [ARG]

COMMAND為自定義執行的程式,ARG為傳遞給程式的引數,假如定義相關映象檔案時使用了ENTRYPOINT指令,則COMMANDARG都會被當作命令列引數傳遞給ENTRYPOINT指令中指定的程式,除非執行docker run命令時額外使用--entrypoint選項來覆蓋映象檔案中的ENTRYPOINT指定的程式。

在Kubernetes系統上建立Pod資源時,也能夠向容器化應用傳遞命令列引數,甚至指定執行其它應用程式,相關的欄位分別為pods.spec.containers.commandpods.spec.containers.args

將配置檔案載入映象檔案

在通過Dockerfile製作映象時,可以使用COPY或者ADD指定將定義好的配置檔案直接複製到映象檔案系統上的相應位置,或者使用RUN指令呼叫sed或echo一類的命令修改配置檔案從而達到為容器化應用提供自定義配置檔案之目的。使用Docker Hub上的某映象檔案額外新增配置檔案即能符合需要,則克隆其Dockerfile檔案修改至符合需求之後再將之推送至GitHub,並由Docker Hub自動構建出映象檔案即可。

通過環境變數向容器注入配置資訊

通過環境變數為容器提供配置資訊是Docker Hub上最常見的使用方式,例如,使用MySQL官方提供的映象檔案啟動MySQL容器時使用的MYSQL_ROOT_PASSWORD環境變數,它用於為MYSQL伺服器的root使用者設定登陸密碼。

在基於此類映象啟動容器時,使用者為 docker run 命令通過 -e 選項向環境變數傳值即能實現應用配置,命令的使用格式為 docker run -e SETTING1=foo -e SETTING2=bar ... <image name>。啟動時,容器的ENTRYPOINT啟動指令碼會抓取到這些環境變數,並在啟動容器應用之前,通過sed或echo等一類的命令將變數值替換到配置檔案中。

通過儲存卷向容器注入配置資訊

Docker儲存卷(volumes)能夠將宿主機之上的任何檔案或目錄對映到容器檔案系統之上,因此,可以事先將配置檔案放置於宿主機之上的某個路徑中,而後在啟動容器時進行載入。這種方式靈活易用,但也依賴於使用者需要事先將配置資料提供在宿主機上的特定路徑下,而且在多主機模型中,若容器存在被排程至任一主機執行的可能性時,使用者還需要將配置共享到任一宿主機來確保容器能夠正常地獲取到它們。

藉助Docker config進行容器配置

Docker swarm service自1.13版本起支援使用secret於容器之外儲存二進位制資料,包括口令、SSH私鑰、SSL證書以及其它不建議通過網路傳輸或不應該在Dockerfile及程式原始碼中載入儲存的機密資料,使用者可使用secret叢集化管理這類資料並將其關聯至那些需要訪問這些資料的容器中。

另外,Docker自17.06版本起為swarm service引入了允許使用者容器之外儲存非敏感資訊(如配置檔案)的元件service config,從而支援使用者建立通過目的映象檔案,並且不再需要通過掛載儲存卷或使用環境變數為容器提供配置檔案。

Docker swarm service secret和config為容器化應用的配置提供了極大的靈活性,不過,它們也只能應用於Docker swarm service環境中,而不能應用於單獨執行的容器之上。

Kubernetes系統也有類似的元件,它們被稱為Secret和ConfigMap,而且是Kubernetes系統上一等類別的資源物件,它們要麼被Pod資源以儲存卷的形式載入,要麼由容器通過envFrom欄位以變數的形式載入。

1. 通過命令列引數配置容器應用

建立Pod資源時,可以在容器中自定義要執行的命令以及選項和引數。
在容器的配置上下文中,使用command欄位指定要執行的程式,而args欄位則可用於指定傳遞給程式的選項和引數。在配置檔案中定義command和args會覆蓋映象檔案中相關的預設設定,這類程式會被直接執行,而不會由shell直譯器解釋執行,因此與sehll相關的特性均不被支援,如命令列展開符號 {}、重定向等操作。

下面是定義在 command-demo.yaml 檔案中的Pod資源示例,它在容器 command-demo-container中將busybox映象檔案中預設執行的命令 ["/bin/sh", "-c"]修改為["httpd"],併為其額外傳遞了["-f"]選項。

cat command-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: command-demo
  labels:
    purpose: demonstrate-commdn
spec:
  containers:
  - name: command-demo-container
    image: busybox
    command: ["httpd"]
    args: ["-f"]
    ports:
    - containerPort: 80

資源清單編輯之後建立Pod物件,然後檢視容器所執行的程式,結果如下父程序為 httpd -f

kubectl exec -it pods/command-demo -- ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 httpd -f
   22 root      0:00 ps aux

事實上,我們也可以只在容器配置的上下文提供 args 欄位,以實現向預設執行的程式提供額外的引數,如果預設的命令為Shell解析器或 entrypoint 啟動指令碼,那麼這些引數本身甚至還可以是要執行的命令及其引數,例如,下面的容器配置,表示要執行的程式為/bin/sh -c httpd -f,實現了shell直譯器解釋執行執行的程式之目的。

cat command-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: command-demo
  labels:
    purpose: demonstrate-commdn
spec:
  containers:
  - name: command-demo-container
    image: busybox
    args: ["httpd","-f"]
    ports:
    - containerPort: 80

建立Pod物件,並檢視容器的父程序

kubectl exec -it pods/command-demo -- ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 httpd -f
    8 root      0:00 ps aux

由上述的示例可見,Kubernetes配置檔案中的command對應於Dockerfile中的ENTRYPOINT,而配置檔案的args則對應於Dockerfile中的CMD。在Kubernetes中只給出command欄位時,他會覆蓋Dockerfile中的ENTRYPOINT和CMD,只給出args欄位時,它僅覆蓋CMD,而同時給出command和args時,它會對應覆蓋ENTRYPOINT和CMD。

2. 利用環境變數配置容器應用

在Kubernetes中使用映象啟動容器時,可以在Pod資源或Pod模版資源為容器配置使用env引數來定義所使用的環境變數列表,即便容器中的應用本身不處於環境變數,也一樣可以向容器傳遞環境變數,只不過它不被使用罷了。

環境變數配置容器化應用時,需要在容器配置段中巢狀使用env欄位,它的值是一個由環境變數構建的列表。環境變數由name和value(或valueFrom)欄位構成。

  • name<string>:環境變數的名稱,必須欄位。
  • value<string>:環境變數的值,通過 ${VAR_NAME} 引用,預設值為空。
  • valueFrom<Object>:環境變數值的引用源,例如,當前Pod資源的名稱、名稱空間、標籤等,不能與非空值的value欄位同時使用,即環境變數的值要麼源於value欄位,要麼源於valueFrom欄位,二者不可同時提供資料。valueFrom欄位可引用的值有多種來源,包括當前Pod資源的屬性值,容器相關的系統資源配置、ConfigMap物件中的Key以及Secret物件中的Key,它們應分別使用不同的巢狀欄位進行定義。
  • fieldRef<Object>:當前Pod資源的指定欄位,目前支援使用的欄位包括 metadata.name、metadata.namespace、metadata.labels、metadata.annotations、spec.nodeName、spec.serviceAccountName、status.hostIP和status.podIP。
  • configMapKeyRef<Object>:ConfigMap物件中的特定Key。
  • secretKeyRef<Object>:Secret物件中的特定Key。
  • resourceFieldRef<Object>:當前容器的特定系統資源的最小值(配額)或最大值(限額),目前支援的引用包括limits.cpu、limts.ephemeral-storage、requests、cpu、requests.memory、requests.ephemeral-storage。

下面是定義在配置檔案 env-demo.yaml 中的Pod資源,其通過環境變數引用當前Pod資源及其所在節點的相關屬性值配置容器,fieldRef欄位的值是一個物件,它一般由apiVersion(建立當前Pod資源的API版本)或fidldPath巢狀欄位所定義:

cat env-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: env-demo
  labels:
    purpose: demonstrate-environment-variables
spec:
  containers:
  - name: env-demo-container
    image: busybox
    command: [ "httpd" ]
    args: [ "-f" ]
    env:
    - name: HELLO_WORLD
      value: just a demo
    - name: MY_NODE_NAME
      valueFrom:
        fieldRef:
          fieldPath: spec.nodeName
    - name: MY_NODE_IP
      valueFrom:
        fieldRef:
          fieldPath: status.hostIP
    - name: MY_POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
  restartPolicy: OnFailure

建立Pod物件

kubectl apply -f env-demo.yaml

然後列印它的環境變數列表

kubectl exec -it pods/env-demo -- printenv
HELLO_WORLD=just a demo							#在清單中定義的HELLO_WORLD變數與值
MY_NODE_NAME=k8s-node03							#在清單中定義的MY_NODE_NAME變數與從spec.nodeName獲取到的值
MY_NODE_IP=192.168.31.233						  #在清單中定義的MY_NODE_IP變數與從status.hostIP獲取的值
MY_POD_NAMESPACE=default						   #在清單中定義的MY_POD_NAMESPACE變數與從metadata.namespec獲取到的值

容器的啟動指令碼或應用程式呼叫或處理這些環境變數、即可實現容器化應用的配置。相較於命令列引數的方式來說,使用環境變數的配置方式更清晰、易懂,尤其是對於首次使用相關容器的使用者來說,這種方式能夠快速瞭解容器的配置方式,不過這兩種配置方式有一個共同缺陷:無法在容器應用執行過程中更新環境變數從而達到更新應用目的。這通常意味著使用者不得不為production、development和qa等不同的環境分別配置Pod資源。好在,使用者還有ConfigMap資源可用。

3. ConfigMap介紹之各姿勢建立ConfigMap

ConfigMap誕生的原因

分散式環境中,基於負載、容錯性等需求的考慮,幾乎所有的服務都需要在不同的機器節點上部署不止一個例項。隨著程式功能的日益複雜,程式的配置日益增多,而且配置檔案的修改頻率通常遠遠大於程式碼本身,這種情況下,有時僅僅是一個配置內容的修改,就不得不重新將程式碼提交到SVN/Git、打包、分發上線的流程。部署規則較大的場景中,分發上線工作即繁雜又沉重。

究其根本,所有的這些麻煩都是由於配置和程式碼在管理和釋出的過程中不加區分所致。配置本身源於程式碼,是為了提高程式碼的靈活性而提取出來的一些經常變化的或需要定製的內容,而正是配置的這種天生變化特性為部署過程中帶來了不小的麻煩,也最終催生了分散式系統配置管理系統,將配置內容從程式碼中完全分離出來,及時可靠高效地提供配置訪問和更新服務。

提示:國內分散式配置中心相關的開源專案有 Diamond(阿里)、Apollo(攜程)、Qconf(奇虎360)和disconf(百度)等。

作為分散式系統的Kubernetes也提供了統一配置管理方案——ConfigMap。Kubernetes基於ConfigMap物件實現了將配置檔案從容器映象中解耦,從而增強了容器應用的可移植性。簡單來說,一個ConfigMap物件就是一系列配置資料的集合,這些資料可“注入”到Pod物件中,併為容器應用所使用,注入方式有掛載為儲存卷和傳遞為環境變數兩種。

ConfigMap介紹

ConfigMap物件將配置資料以鍵值對的形式進行儲存,這些資料可以在Pod物件中使用或者為系統元件提供配置,例如控制器物件等。不過無論應用程式如何使用ConfigMap物件中的資料,使用者都完全可以通過在不同的環境中建立名稱相同但內容不同的ConfigMap物件,從而為不同環境中同一功能的Pod資源提供不同的配置資訊,實現應用與配置的靈活勾兌。

ConfigMap物件建立

ConfigMap建立的方式與其它資源一樣有兩種:

  • kubectl create configmap 命令直接建立
  • 通過資源配置清單建立
    以上兩種對於ConfigMap都算是比較常用的建立方式,通過kubectl create configmap命令,使用者可以根據目錄、檔案或者直接建立ConfigMap物件,命令的語法格式如下:
    kubectl create configmap <map-name> <data-source>

<map-name>為ConfigMap物件的名稱,<data-source>是資料來源,資料來源可以直接給定K/V型別的資料,也可以指定檔案以及目錄來獲取,無論是哪一種資料來源,它都要轉換為ConfigMap物件中的Key-Value資料,其中Key由使用者在命令列給出或是檔案資料來源的檔名,它僅能由字母、數字、連線號和點號組成,而Value則是直接值或檔案資料來源的內容。

通過鍵值建立ConfigMap

利用kubectl create configmap命令使用--from-literal選項可在命令列直接給出鍵值對來建立ConfigMap物件,重複使用此選項則可以傳遞多個鍵值對,命令格式如下:
kubectl create configmap configmap_name --from-literal=key-name01=value-1

例如下面用命令建立special-config configmap時傳遞來兩個鍵值對:
鍵值對第一個key為mysql_ip值為172.16.0.3
鍵值對第二個key為mysql_port值為3306

kubectl create configmap special-config \
--from-literal=mysql_ip=172.16.0.3 --from-literal=mysql_port=3306

檢視建立的ConfigMap

kubectl get configmap
NAME             DATA   AGE
special-config   2      55s


#使用kubectl describe可以看到configmap中的原始資料
kubectl describe configmap/special-config
Name:         special-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
mysql_ip:
----
172.16.0.3
mysql_port:
----
3306
Events:  <none>

此類方式提供的資料量有限,一般是在僅通過有限的幾個資料項即可為Pod資源提供足夠的配置資訊時使用。

通過檔案建立ConfigMap

利用kubectl create configmap命令使用--from-file選項可基於檔案內容來建立ConfigMap物件,它的命令格式如下:
kubectl create configmap <configmap_name> --from-file=<[key=]source>

1.準備配置檔案
我們先準備好要載入容器的配置檔案,等下通過kubectl create configmap config_name --from-file 來指定我們的配置檔案即可建立configmap,以下準備了一個elasticsearch.yaml的配置檔案

cat elasticsearch.yaml
cluster.name: elasticsearch
node.name: elastic
path.data: /usr/local/elastic7.4/data
path.logs: /usr/local/elastic7.4/logs
bootstrap.memory_lock: true
network.host: 0.0.0.0
network.tcp.no_delay: true
network.tcp.keep_alive: true
network.tcp.reuse_address: true
network.tcp.send_buffer_size: 256mb
network.tcp.receive_buffer_size: 256mb
transport.tcp.port: 9300
transport.tcp.compress: true
http.max_content_length: 200mb
http.cors.enabled: true
http.cors.allow-origin: "*"
http.port: 9200
cluster.initial_master_nodes: ["127.0.0.1:9300"]
xpack.security.enabled: true
xpack.license.self_generated.type: basic
xpack.security.transport.ssl.enabled: true
xpack.monitoring.collection.enabled: true

2.通過檔案建立configMap
如果指定檔案建立configmap的時候沒有指定key,那麼kubernetes則以檔名稱為key

kubectl create configmap elastic-configmap --from-file=./elasticsearch.yaml

3.檢視建立的ConfigMap

kubectl describe configmap elastic-configmap
Name:         elastic-configmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
elasticsearch.yaml:								#我們沒有指定key,預設以檔名稱為key
----
cluster.name: elasticsearch
node.name: elastic
path.data: /usr/local/elastic7.4/data
path.logs: /usr/local/elastic7.4/logs
bootstrap.memory_lock: true
network.host: 0.0.0.0
network.tcp.no_delay: true
network.tcp.keep_alive: true
network.tcp.reuse_address: true
network.tcp.send_buffer_size: 256mb
network.tcp.receive_buffer_size: 256mb
transport.tcp.port: 9300
transport.tcp.compress: true
http.max_content_length: 200mb
http.cors.enabled: true
http.cors.allow-origin: "*"
http.port: 9200
cluster.initial_master_nodes: ["127.0.0.1:9300"]
xpack.security.enabled: true
xpack.license.self_generated.type: basic
xpack.security.transport.ssl.enabled: true
xpack.monitoring.collection.enabled: true

Events:  <none>

也可以以yaml格式顯示configmap資訊

kubectl get configmap elastic-configmap -o yaml

如果需要指定鍵名稱,如下在檔案前面寫入key名稱即可

kubectl create configmap elastic-configmap --from-file=elastic=./elasticsearch.yaml

如下再檢視key名稱則變為了我們所指定的elastic

kubectl get configmap elastic-configmap -o yaml
apiVersion: v1
data:
  elastic: |
    cluster.name: elasticsearch
    node.name: elastic
    path.data: /usr/local/elastic7.4/data
    path.logs: /usr/local/elastic7.4/logs
    bootstrap.memory_lock: true
    network.host: 0.0.0.0
    network.tcp.no_delay: true
    network.tcp.keep_alive: true
    network.tcp.reuse_address: true
    network.tcp.send_buffer_size: 256mb
    network.tcp.receive_buffer_size: 256mb
    transport.tcp.port: 9300
    transport.tcp.compress: true
    http.max_content_length: 200mb
    http.cors.enabled: true
    http.cors.allow-origin: "*"
    http.port: 9200
    cluster.initial_master_nodes: ["127.0.0.1:9300"]
    xpack.security.enabled: true
    xpack.license.self_generated.type: basic
    xpack.security.transport.ssl.enabled: true
    xpack.monitoring.collection.enabled: true
kind: ConfigMap
metadata:
  creationTimestamp: "2020-06-05T07:00:45Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:elastic: {}
    manager: kubectl
    operation: Update
    time: "2020-06-05T07:00:45Z"
  name: elastic-configmap
  namespace: default
  resourceVersion: "418525"
  selfLink: /api/v1/namespaces/default/configmaps/elastic-configmap
  uid: 16e8074a-4d4e-4e6e-b704-339876357951

通過目錄建立ConfigMap

如果配置檔案數量較多時,kubectl還提供了基於目錄直接將多個檔案分別收納為鍵值資料的ConfigMap資源建立方式,將--from-file選項後所跟的路徑指向一個目錄路徑就能把目錄下的所有檔案一同建立同一哥個 ConfigMap 資源中,命令格式如下:
kubectl create configmap <configmap_name> --from-file=<path-to-directory>

如下命令所示,將/data/configs/nginx/conf.d目錄下的所有檔案都保存於nginx-config-files物件中

ls /data/configs/nginx/conf.d/
myserver.conf  myserver-gzip.cfg  myserver-status.cfg
kubectl create configmap nginx-config-files --from-file=/data/configs/nginx/conf.d/

檢視建立的configmap物件

注意:kubectl describe 和 kubectl get -o yaml 命令都可以顯示由檔案建立的鍵值,不過兩者使用的鍵和值之間的分隔符不同

kubectl describe configmap nginx-config-files
Name:         nginx-config-files
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
myserver-gzip.cfg:
----
gzip on;
gzip_comp_level 5;

myserver-status.cfg:
----
     location /ngx_status     {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
    }

myserver.conf:
----
server {
  listen 8080;
  server_name www.k8sops.cn;

  include /etc/nginx/conf.d/myserver-*.cfg;
  location / {
      root /usr/lshare/nginx/html;
  }
}

Events:  <none>
kubectl get configmap nginx-config-files -o yaml
apiVersion: v1
data:
  myserver-gzip.cfg: |
    gzip on;
    gzip_comp_level 5;
  myserver-status.cfg: "     location /ngx_status     {\n  \tstub_status on;\n  \taccess_log
    off;\n\tallow 127.0.0.1;\n \tdeny all;\n \t}\n"
  myserver.conf: "server {\n\tlisten 8080;\n\tserver_name www.k8sops.cn;\n\n\tinclude
    /etc/nginx/conf.d/myserver-*.cfg;\n\tlocation / {\n\t    root /usr/lshare/nginx/html;\n\t}\n}\n"
kind: ConfigMap
metadata:
  creationTimestamp: "2020-06-05T07:44:16Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:myserver-gzip.cfg: {}
        f:myserver-status.cfg: {}
        f:myserver.conf: {}
    manager: kubectl
    operation: Update
    time: "2020-06-05T07:44:16Z"
  name: nginx-config-files
  namespace: default
  resourceVersion: "426082"
  selfLink: /api/v1/namespaces/default/configmaps/nginx-config-files
  uid: d83d033c-c478-495f-b9c6-6fba829ab52a

通過資源配置清單建立

基於配置檔案建立ConfigMap時,它所使用的欄位通常包括apiVersionkind和metadata欄位,以及用於儲存資料的關鍵欄位data
下面就使用配置清單建立一個ConfigMap

cat configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-demo
data:
  log_level: INFO
  log_file: /var/log/test.log
kubectl describe configmap configmap-demo
Name:         configmap-demo
Namespace:    default
Labels:       <none>
Annotations:
Data
====
log_file:
----
/var/log/test.log
log_level:
----
INFO
Events:  <none>

如果配置資訊來自檔案內容時,則使用配置清單建立ConfigMap資源的便捷性還不如直接通過命令列的方式,因此建議直接使用命令列載入檔案或目錄的方式進行建立,為了便於配置留存,可以在建立完成後使用 get -o yaml命令獲取到相關資訊後在進行編輯留存。

4. ConfigMap載入Pod方式之環境變數

在Pod中,獲取環境變數值的方式之一就包括ConfigMap物件中的資料,這一點通過在env欄位中為valueFrom內嵌configMapKeyRef物件即可實現,格式如下:

valueFrom:
  configMapKeyRef:
    key:
    name:
    optional:

欄位name值為要引用的ConfigMap物件的名稱
欄位key可用於指定要引用ConfigMap物件中某鍵的鍵名
欄位optional用於為當前Pod資源指明此引用是否為可選

此類環境變數的使用方式與直接定義的環境變數並無區別,它們可被用於容器的啟動指令碼或直接傳遞給容器應用等。

傳遞ConfigMap中的單個Key

下面示例中包含了兩個資源,彼此之間使用 "--" 相分隔,第一個資源是名為 busybox-httpd-config 的 ConfigMap 物件,它包含了兩個鍵值資料;第二個資源是名為 configmap-env-demo 的 Pod物件,它通過環境變數引用了busybox-httpd-config物件中的鍵值資料,並將其直接傳給了自定義執行的容器應用httpd:

cat busybox.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: busybox-httpd-config
  namespace: default
data:
  httpd_port: "8080"
  verbose_level: "-vv"
---
apiVersion: v1
kind: Pod
metadata:
  name: configmap-env-demo
  namespace: default
spec:
  containers:
  - image: busybox
    name: busybox-httpd
    command: [ "/bin/httpd" ]
    args: [ "-f","-p","$(HTTPD_PORT)","$(HTTPD_LOG_VERBOSE)" ]
    env:
    - name: HTTPD_PORT							#定義第一個變數名稱
      valueFrom:										  #引用變數
        configMapKeyRef:							 #引用來自configMap的變數
          name: busybox-httpd-config			#指定ConfigMap的名稱
          key: httpd_port								  #指定ConfigMap中要引用的key名稱
    - name: HTTPD_LOG_VERBOSE
      valueFrom:
        configMapKeyRef:
          name: busybox-httpd-config
          key: verbose_level
          optional: true

注意,在command和args欄位中引用環境變數要使用$(VAR_NAME)的格式,待上面配置檔案中的資源建立完成後,可以通過如下命令驗證Pod資源監聽的埠等配置資訊是否為 busybox-httpd-config中定義的內容:

kubectl apply -f busybox.yaml
configmap/busybox-httpd-config created
pod/configmap-env-demo created

kubectl exec pods/configmap-env-demo -- ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/httpd -f -p 8080 -vv
    8 root      0:00 ps aux

kubectl exec pods/configmap-env-demo -- env | grep HTTPD
HTTPD_PORT=8080
HTTPD_LOG_VERBOSE=-vv

注意:建立引用了ConfigMap資源的Pod物件時,被引用的資源必須事先存在,否則將無法啟動相應的容器,直到被依賴的資源建立完成為止。不過,那些未引用不存在的ConfigMap資源的容器將不受此影響。另外,ConfigMap是名稱空間級別的資源,它必須與引用它的Pod資源在同一個名稱空間中。

傳遞ConfigMap中的所有Key

如果我們要引入的變數有很多呢?此時,為容器依次配置相應的環境變數是一件很煩躁的事情,而且容易出錯,對此,Pod資源支援在容器中使用envFrom欄位直接將ConfigMap資源中的所有鍵值一次性地完整匯入。格式如下:

spec:
  containers:
  - name: busybox
    image: busybox
    envFrom:
    - prefix: HTCPG_
      configMapRef:
        name: configmap_name
        optional: true

envFrom欄位是物件列表,可用於同時從多個ConfigMap物件匯入鍵值資料。
為了避免從多個ConfigMap引入鍵值資料時產生鍵key重名(名稱衝突),可以在每個引用中將被匯入的鍵使用 prefix 欄位指定一個特性的字首,如 HTCPG_ 一類的字串,於是,ConfigMap物件中的httpd_port將成為Pod資源中名為HTCPG_httpd_port的變數。

如果鍵名中使用了連線線 "-",那麼在轉換為變數時,連線線將自動被替換為下劃線 "_"。

如下:

cat envFrom.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: busybox-httpd-config
  namespace: default
data:
  httpd_port: "8080"
  verbose_level: "-vv"
---
apiVersion: v1
kind: Pod
metadata:
  name: configmap-env-demo
  namespace: default
spec:
  containers:
  - image: busybox
    name: busybox-httpd
    command: [ "/bin/httpd" ]
    args: [ "-f", "-p", "$(HTCPG_httpd_port)", "$(HTCPG_verbose_level)" ]
    envFrom:
    - prefix: HTCPG_
      configMapRef:
        name: busybox-httpd-config
        optional: false

待Pod資源建立完成後,可通過檢視其環境變數驗證其匯入的結果:

kubectl apply -f envFrom.yaml
kubectl exec pods/configmap-env-demo -- ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/httpd -f -p 8080 -vv
    7 root      0:00 ps aux

kubectl exec pods/configmap-env-demo -- printenv | grep HTCPG
HTCPG_verbose_level=-vv
HTCPG_httpd_port=8080

注意:從ConfigMap物件匯入資源時,prefix為可選欄位,不定義時,所有變數名同ConfigMap中的鍵名。如果不存在鍵名衝突的可能性,例如從單個ConfigMap物件匯入變數或在ConfigMap物件中定義鍵名時依然添加了特定的字首,那麼省略字首的定義即不會導致鍵名衝突,又能保持變數的簡潔。

5. ConfigMap載入Pod方式之儲存卷

若ConfigMap物件中的鍵值來源於較長的檔案內容,那麼使用環境變數將其匯入會使得變數值佔據過多的記憶體空間而不易清理。此類資料通常用於為容器應用提供配置檔案,因此將其記憶體直接作為檔案進行引用方為較好的選擇,其實現方式是,在定義Pod資源時,將此類ConfigMap物件配置為ConfigMap型別的儲存卷,而後由容器將其掛載至特定的掛載點後直接進行訪問。

掛載整個儲存卷

關聯為Pod資源的儲存卷時,ConfigMap物件中的每個鍵都對應地對應為一個檔案,鍵名轉為檔名,而值則為相應檔案的內容,即便是通過直接建立的鍵值資料,也一樣表現為檔案檢視。掛載於容器上之後,由鍵值資料表現出的檔案位於掛載點目錄中,容器中的程序可直接讀取這些檔案的內容。

配置Pod資源時,基於儲存卷的方式引用ConfigMap物件的方法非常簡單,僅需要指明卷名稱及要應用的ConfigMap物件名稱即可。

1.建立配置檔案
我們下面建立三個Nginx配置檔案,然後將這三個配置檔案掛載到Nginx的配置目錄中

在我們的宿主機上建立我們的檔案目錄

k8sops@k8s-master01:~$ mkdir data/nginx/{conf.d,html} -p

建立配置檔案vhost.conf

cat data/nginx/conf.d/vhost.conf
server {
        listen       80;
	server_name  www.k8sops.cn;

	include /etc/nginx/conf.d/*.conf;
        location  / {
            root   /usr/share/nginx/html;
            index index.html index.htm;
        }
}

建立配置檔案gzip.conf

cat data/nginx/conf.d/gzip.cfg
    gzip on;
    gzip_min_length 1k;
    gzip_buffers 16 64K;
    gzip_http_version 1.1;
    gzip_comp_level 6;
    gzip_types text/plain application/x-javascript text/css application/xml application/javascript;
    gzip_vary on;
    gzip_proxied any;
    underscores_in_headers on;
    proxy_ignore_client_abort on;

建立配置檔案ngx-status.conf

cat data/nginx/conf.d/ngx-status.cfg
     location /ngx_status     {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
        }

2.建立ConfigMap物件

基於目錄建立nginx-config-files物件

kubectl create configmap nginx-config-files --from-file=./data/nginx/conf.d/

檢視建立的configmap

kubectl describe configmap nginx-config-files

3.建立Pod資源清單來引用ConfigMap物件並將其掛載至相應指定的目錄中

cat configmap-volume-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: configmap-volume-pod
  namespace: default
spec:
  containers:
  - name: configmap-containers
    image: nginx:latest
    volumeMounts:									#卷掛載配置
    - name: ngx-config								#卷名稱
      mountPath: /etc/nginx/conf.d/				#掛載到容器中的路徑目錄
      readOnly: true									#是否只讀
  volumes:													#卷配置
  - name: ngx-config									#定義一個卷名稱
    configMap:												#configMap配置
      name: nginx-config-files							#指定configMap名稱

4.建立Pod物件

kubectl apply -f configmap-volume-pod.yaml

5.檢視Pod狀態

kubectl get pods -o wide | grep configmap-volume-pod
configmap-volume-pod          1/1     Running   0          48s     172.20.1.14   k8s-node01   <none>           <none>

6.檢視Pod掛載狀態

kubectl describe pods/configmap-volume-pod | grep -A 2  Mounts
    Mounts:
      /etc/nginx/conf.d/ from ngx-config (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-xxqkj (ro)

7.驗證掛載

檢視配置

kubectl exec pods/configmap-volume-pod -- ls /etc/nginx/conf.d
gzip.cfg
ngx-status.cfg
vhost.conf

測試Nginx配置打印出配置

kubectl exec pods/configmap-volume-pod -- nginx -T

訪問stub_status模組

kubectl exec pods/configmap-volume-pod -- curl 2>/dev/null  http://127.0.0.1/ngx_status
Active connections: 1
server accepts handled requests
 8 8 8
Reading: 0 Writing: 1 Waiting: 0

如上可見,nginx-config-files中的三個檔案都被新增到來容器中,並實現了由容器應用Nginx載入並生效

掛載儲存卷中的部分鍵值

有時候,使用者很可能不期望在容器中掛載某ConfigMap儲存卷中的所有檔案,這在通過一個ConfigMap物件為單個Pod資源中的多個容器分別提供配置時尤其常見。例如前面示例中,使用者可能只期望在容器中掛載ConfigMap儲存卷後只“匯出”其中出vhost.conf和gzip.cfg檔案,只提供給傳輸壓縮功能,而不輸出 nginx stub status資訊,此時將其 volumes 配置段改為如下所示的內容即可。

apiVersion: v1
kind: Pod
metadata:
  name: configmap-volume-pod
  namespace: default
spec:
  containers:
  - name: configmap-containers
    image: nginx:latest
    volumeMounts:						#卷掛載配置
    - name: ngx-config					#掛載的卷名稱
      mountPath: /etc/nginx/conf.d/		#掛載在容器中的目標路徑
      readOnly: true						#是否為只讀
  volumes:										#卷配置
  - name: ngx-config						#定義一個卷名稱
    configMap:									#卷從configMap中取值
      name: nginx-config-files				#指定要掛載的configMap名稱
      items:											#nginx-config-files ConfigMap中的鍵
      - key: vhost.conf								#指定要掛載鍵
        path: vhost.conf							#掛載的路徑
        mode: 0644									#掛載後的檔案許可權
      - key: gzip.cfg
        path: compression.cfg
        mode: 0644

ConfigMap儲存卷的items欄位的值是一個物件列表,可巢狀使用的欄位有三個,具體如下:

  • key:要引用的鍵名稱,必選欄位。
  • path:對應的鍵於掛載點目錄中生成的檔案相對路徑,可以不同於鍵名稱,必選欄位。
  • mode:檔案的許可權模型,可用範圍為0到0777。

1.將原來的Pod刪除,然後重新建立Pod

kubectl delete pods/configmap-volume-pod
kubectl apply -f configmap-volume-pod.yaml

2.驗證Nginx配置檔案

kubectl exec pods/configmap-volume-pod -- nginx -T
kubectl exec pods/configmap-volume-pod -- ls /etc/nginx/conf.d
compression.cfg
vhost.conf

獨立掛載儲存卷中的鍵值

上面的兩種方式中,無論是裝載所有檔案還是部分檔案,掛載點目錄下原有的檔案都會被隱藏或者稱為覆蓋,在我們沒有掛載的時候,/etc/nginx/conf.d目錄下有default.conf檔案,當我們掛載之後default.conf就被隱藏或者說覆蓋掉了,但有時候我們希望掛載進的檔案不覆蓋相應目錄下的其它檔案,這個時候就可以通過volumeMounts屬性中的subPath欄位來解決,它可以支援使用者從儲存卷掛載單個檔案或者單個目錄而非整個儲存卷。

例如下面示例 /etc/nginx/conf.d 目錄中掛載一個 vhost.conf 檔案,並且不覆蓋原來目錄下的 default.conf 檔案。
/usr/share/nginx/html目錄中掛載一個configmap.html檔案,並且不覆蓋原來目錄下的 index.html 檔案。

1.刪除原來建立的ConfigMap和Pod

kubectl delete configmap nginx-config-files
kubectl delete pods/configmap-volume-pod

2.建立兩個ConfigMap,分別用於nginx配置檔案和nginx網頁檔案

#建立nginx配置檔案configmap
kubectl create configmap nginx-config-files --from-file=./data/nginx/conf.d/

#寫一個網頁檔案
cat data/nginx/html/configmap.html
<h1>ConfigMap-Volume-Pod-Mounts</h1>

#建立nginx網頁檔案configmap
kubectl create configmap nginx-html-files --from-file=./data/nginx/html/configmap.html

3.建立Pod資源配置清單

apiVersion: v1
kind: Pod
metadata:
  name: configmap-volume-pod
  namespace: default
spec:
  containers:
  - name: configmap-containers
    image: nginx:latest
    volumeMounts:
    - name: ngx-config
      mountPath: /etc/nginx/conf.d/vhost.conf
      subPath: vhost.conf
      readOnly: true
    - name: ngx-html
      mountPath: /usr/share/nginx/html/configmap.html
      subPath: configmap.html
      readOnly: true
  volumes:
  - name: ngx-config
    configMap:
      name: nginx-config-files
  - name: ngx-html
    configMap:
      name: nginx-html-files

4.建立Pod物件

kubectl apply -f configmap-volume-pod.yaml

5.檢視Pod物件掛載狀態

kubectl describe pods/configmap-volume-pod | grep -A 3 Mounts
    Mounts:
      /etc/nginx/conf.d/vhost.conf from ngx-config (ro,path="vhost.conf")
      /usr/share/nginx/html/configmap.html from ngx-html (ro,path="configmap.html")
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-xxqkj (ro)

6.驗證Pod Nginx配置

kubectl exec pods/configmap-volume-pod -- ls /etc/nginx/conf.d
default.conf
vhost.conf

kubectl exec pods/configmap-volume-pod -- nginx -T

7.驗證Pod網頁檔案掛載配置

#檢視檔案是否存在
kubectl exec pods/configmap-volume-pod -- ls -lrth /usr/share/nginx/html
total 12K
-rw-r--r-- 1 root root 612 May 26 15:00 index.html
-rw-r--r-- 1 root root 494 May 26 15:00 50x.html
-rw-r--r-- 1 root root  37 Jun  9 07:02 configmap.html

#訪問configmap網頁檔案
curl http://172.20.1.17/configmap.html
<h1>ConfigMap-Volume-Pod-Mounts</h1>

6. 使用ConfigMap資源的注意事項

在Pod資源中呼叫ConfigMap物件時需要注意以下幾個問題。

  • 以儲存卷訪問引用的ConfigMap必須在Pod啟動前存在,除非在Pod中將他們全部標記為optional,否則會導致Pod無法正常啟動的錯誤,同樣即使存在ConfigMap,在引用ConfigMap中的鍵不存在時,也會導致一樣的錯誤。
  • 當以環境變數注入的ConfigMap中的鍵不存在時會被忽略,Pod可以正常啟動,但錯誤引用的資訊會以InvalidVariableNames事件記錄於日誌中。
  • ConfigMap是名稱空間級的資源,因此引用它的Pod必須處於同一名稱空間中。
  • kubelet不支援引用Kubernetes API Server上不存在的ConfigMap,這包括那些通過kubelet的--manifest-url--config選項,以及 kubelet REST API 建立的Pod。

有段時間沒跟大家分享資源福利了,看了下自己的資料夾,整理了一些我認為比較好的Python學習資料了。相信這套資料可以對你進階高階工程師有幫助

學習工具

大廠實戰手冊

自學視訊(部分)

【資料免費領取方式】:點這裡:2020Python高薪實戰學習大合集