Kubernetes学习之ConfigMap

一、认识ConfigMap资源
  在分布式环境中,基于负载、容错等需求的考虑,几乎所有的服务器都需要在不同的机器上分别部署不止一个实例。随着程序功能的日益复杂,同时配置文件的修改频率通常远远大于代码本身,这种情况下,有时仅仅是一个配置内容的修改,就不得不重新进行代码提交、打包、分发上线的流程。部署模式较大的场景中,分发上线工作即繁杂又沉重。
  究其根本,所有的这些麻烦都是由于配置和代码在管理和发布过程中紧密耦合所致。配置本身源于代码,是为了提高代码的灵活性而提取出来的一些经常变化的或需要定制的内容,而正是配置的这种天生的变化特征为部署过程带来了不小的麻烦,也最终催生了分布式系统配置管理系统,从而将配置内容从代码完全分离出来,及时可靠高效的提供配置访问和更新服务。
  作为分布式系统的Kubernetes也提供了统一配置管理方案–ConfigMap。Kubernetes基于ConfigMap对象实现了将配置文件从容器镜像中解耦,从而增强了容器应用的可移植性。简单来说,一个ConfigMap对象就是一系列配置数据的集合,这些数据可"注入"到Pod对象中,并为容器应用所使用,注入方式有挂载为存储卷和传递为环境变量两种。
  ConfigMap对象将配置数据以键值对的形式进行存储,这些数据可以在Pod对象中使用或者为系统组件提供配置,例如控制器对象等。不过,无论应用程序如何使用ConfigMap对象中的数据,用户都完全可以通过在不同的环境中创建名称相同但是内容不同的ConfigMap对象,从而为不同环境中同一功能的Pod资源提供不同的配置信息,实现应用于配置的灵活勾兑。
Kubernetes学习之ConfigMap_第1张图片

二、创建ConfigMap
  Kubernetes的不少资源既可以使用kubelet create命令创建,也可以使用清单创建,例如namespace。ConfigMap是另一个两种创建方式都可以常见的资源。而且,通过使用"kubectl create configmap"命令,用户可以根据目录、文件或直接值创建ConfigMap对象,命令语法格式如下所示:

kubectl create configmap <map-name> <data-source>

.
  其中,即为ConfigMap对象的名称,而是数据源,它可以通过直接值、文件或目录来获取。无论是哪一种数据源供给方式,它都要转换为ConfigMap对象中的Key-Value数据,其中Key由用户在命令行给出或者是文件数据源的文件名,它仅能由数字、字母、连接号和点号组成,而Value则是直接值或文件数据源的内容。

1)利用直接值创建
  为"kubelet create configmap"命令使用"--from-literal"选项可在命令行直接给出键值对来创建ConfigMap对象,重复使用此选项则可以传递多个键值对。命令格式如下:

kubelet create configmap configmap_name --from-literal=key-name-1=value-1

例如,下面的命令创建了一个名为special-config时传递了两个键值对:

]# kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
configmap/special-config created

查看ConfigMap对象的详细信息:

]# kubectl get configmap -o wide 
NAME                 DATA   AGE
special-config       2      8s

]# kubectl get configmap special-config -o yaml
apiVersion: v1
data:
  special.how: very
  special.type: charm
kind: ConfigMap
metadata:
  creationTimestamp: "2020-08-30T07:39:16Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:special.how: {}
        f:special.type: {}
    manager: kubectl
    operation: Update
    time: "2020-08-30T07:39:16Z"
  name: special-config
  namespace: default
  resourceVersion: "6456083"
  selfLink: /api/v1/namespaces/default/configmaps/special-config
  uid: 6d5f473b-bd99-49eb-9729-00fac9dd8642

2)基于文件创建
  为"kubectl create configmap"命令使用"--from-file"选项即可基于文件内容来创建ConfigMap对象,它的命令格式如下。可以重复多次使用"--from-file"选项以传递多个文件内容:

kubectl create configmap <configmap_name> --from-file=<path-to-file>

例如,下面的命令可以把事先准备好的Nginx配置文件模板保存于ConfigMap对象nginx-config中:

]# kubectl create configmap nginx-conf --from-file=/etc/nginx/nginx.conf.default
configmap/nginx-conf created

查看ConfigMap资源对象详细信息:

]# kubectl get configmap nginx-conf -o yaml 
apiVersion: v1
data:
  nginx.conf.default: |2
  
    worker_processes  1;


    events {
        worker_connections  1024;
    }


    http {
        include       mime.types;
        default_type  application/octet-stream;

        sendfile        on;
        keepalive_timeout  65;

        server {
            listen       80;
            server_name  localhost;

            location / {
                root   html;
                index  index.html index.htm;
            }

            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2020-08-30T07:47:58Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:nginx.conf.default: {}
    manager: kubectl
    operation: Update
    time: "2020-08-30T07:47:58Z"
  name: nginx-conf
  namespace: default
  resourceVersion: "6457570"
  selfLink: /api/v1/namespaces/default/configmaps/nginx-conf
  uid: a485c228-2a05-43cb-a5b1-87a40a40958b

3)基于目录创建
  如果配置文件数量较多且存储于有限的目录中时,kubelet还提供了基于目录直接将多个文件分别收纳为键值数据的ConfigMap资源创建方式。将"–from-file"选项后面所跟的路径指向一个目录路径就能将目录下的所有文件一同创建于同一ConfigMap资源中,命令格式如下:

]# kubectl create configmap nginx-conf-files --from-file=/data/nginx/
configmap/nginx-conf-files created

查看ConfigMap资源详细信息:

]# kubectl get configmap nginx-conf-files -o yaml 
apiVersion: v1
data:
  myserver-1.conf: |
    worker_processes  1;



    events {
        worker_connections  1024;
    }


    http {
        include       mime.types;
        default_type  application/octet-stream;

        sendfile        on;
        keepalive_timeout  65;


        server {
            listen       80;
            server_name  localhost;


            location / {
                root   html;
                index  index.html index.htm;
            }

            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }

        }
    }
  myserver-2.conf: |
    worker_processes  1;



    events {
        worker_connections  1024;
    }


    http {
        include       mime.types;
        default_type  application/octet-stream;

        sendfile        on;
        keepalive_timeout  65;


        server {
            listen       80;
            server_name  localhost;


            location / {
                root   html;
                index  index.html index.htm;
            }

            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }

        }
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2020-08-30T07:58:17Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:myserver-1.conf: {}
        f:myserver-2.conf: {}
    manager: kubectl
    operation: Update
    time: "2020-08-30T07:58:17Z"
  name: nginx-conf-files
  namespace: default
  resourceVersion: "6459321"
  selfLink: /api/v1/namespaces/default/configmaps/nginx-conf-files
  uid: 5a1075a3-e427-4a8c-a9df-1e2f23385b8e

4)使用清单创建ConfigMap
  基于配置文件创建ConfigMap资源时,它所使用的字段包括通常的apiVersion、kind和metadata字段,以及用于存储数据的关键字字段"data"。例如,如下配置资源清单文件:

]# cat my-configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-demo
  namespace: default
data:
  log_level: INFO
  log_file: /var/log/test.log

]# kubectl apply -f my-configmap.yaml 
configmap/configmap-demo created

查看ConfigMap资源对象:

]# kubectl get configmap -o wide 
NAME                 DATA   AGE
configmap-demo       2      10s

]# 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>

三、在Pod中使用ConfigMap资源
  Pod资源的环境变量值的获取方式之一包括引用ConfigMap对象中的数据,这一点通过在env中为valueFrom内嵌configMapKeyRef对象即可实现,其使用格式如下:

valueFrom:
  configMapKeyRef:
    key:
    name:
      optional:

.
  其中,字段name的值为要引用的ConfigMap对象的名称,字段key可用于指定要引用ConfigMap对象中某键的键名,而字段optional则用于为当前Pod资源指明引用是否为可选的。此类环境变量的使用方式与直接定义的环境变量并无区别,它们可被用于容器的启动脚本或直接传递给容器应用等。

1)编写Pod与ConfigMap资源的yaml文件

]# cat configmap-demo.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: busybox-http-config
  namespace: default
data:
  http_port: "8080"
  verbose_level: "-vv"

---
apiVersion: v1
kind: Pod
metadata:
  name: configmap-env-demo
  namespace: default
spec:
  containers:
  - name: busybox-httpd
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ["/bin/httpd"]
    args: ["-f","-p","$(HTTPD_PORT)","$(HTTPD_LOG_VERBOSE)"]
    env:
    - name: HTTPD_PORT
      valueFrom: 
        configMapKeyRef:
          name: busybox-http-config
          key: http_port
    - name: HTTPD_LOG_VERBOSE
      valueFrom:
        configMapKeyRef:
          name: busybox-http-config
          key: verbose_level
          optional: true

]# kubectl apply -f configmap-demo.yaml 
configmap/busybox-http-config created
pod/configmap-env-demo created

2)查看ConfigMap和Pod资源信息

]# kubectl get configmap busybox-http-config -o yaml 
apiVersion: v1
data:
  http_port: "8080"
  verbose_level: -vv
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"http_port":"8080","verbose_level":"-vv"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"busybox-http-config","namespace":"default"}}
  creationTimestamp: "2020-08-30T08:20:23Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:http_port: {}
        f:verbose_level: {}
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
    manager: kubectl
    operation: Update
    time: "2020-08-30T08:20:23Z"
  name: busybox-http-config
  namespace: default
  resourceVersion: "6463086"
  selfLink: /api/v1/namespaces/default/configmaps/busybox-http-config
  uid: 741b6ced-919a-4ff8-ae37-eecfd376a643

]# kubectl get pods -o wide 
NAME                 READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
configmap-env-demo   1/1     Running   0          3s    10.244.1.116   node1   <none>           <none>

]# kubectl describe pods configmap-env-demo 
Name:         configmap-env-demo
Namespace:    default
Priority:     0
Node:         node1/172.16.2.101
Start Time:   Mon, 31 Aug 2020 16:23:53 +0800
Labels:       <none>
Annotations:  Status:  Running
IP:           10.244.1.116
IPs:
  IP:  10.244.1.116
Containers:
  busybox-httpd:
    Container ID:  docker://dcb784ac9c189c847a75d06d8917a5eec672280ba1708a1652bbbdf8a7553219
    Image:         busybox
    Image ID:      docker-pullable://busybox@sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
    Port:          <none>
    Host Port:     <none>
    Command:
      /bin/httpd
    Args:
      -f
      -p
      $(HTTPD_PORT)
      $(HTTPD_LOG_VERBOSE)
    State:          Running
      Started:      Mon, 31 Aug 2020 16:23:54 +0800
    Ready:          True
    Restart Count:  0
    Environment:
      HTTPD_PORT:         <set to the key 'http_port' of config map 'busybox-http-config'>      Optional: false
      HTTPD_LOG_VERBOSE:  <set to the key 'verbose_level' of config map 'busybox-http-config'>  Optional: true
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-47pch (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-47pch:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-47pch
    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/configmap-env-demo to node1
  Normal  Pulled     <invalid>  kubelet, node1     Container image "busybox" already present on machine
  Normal  Created    <invalid>  kubelet, node1     Created container busybox-httpd
  Normal  Started    <invalid>  kubelet, node1     Started container busybox-httpd

可以看到当前Pod已经成功使用了ConfigMap资源中的数据

3)验证Pod信息

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

.
  创建ConfigMap资源的Pod对象时,被引用的资源必须事先存在,否则将无法启动相应的容器,直到被依赖的资源创建完成为止。不过,那些未引用不存在的ConfigMap资源的容器将不受此影响。另外,ConfigMap是名称空间级别的资源,它必须与引用它的Pod资源在同一个空间中。

四、ConfigMap存储卷
  若ConfigMap对象中的键值来源于较长的文件内容,那么使用环境变量将其导入会使得变量值占据过多的内存空间而且不易处理。这类数据通常用于为容器应用提供配置文件,因此使得将其内容直接作为文件进行引用方式为较好的选择。其实现方式是,在定义Pod资源时,将此类ConfigMap对象配置为ConfigMap类型的存储卷,而后由容器将其挂载至特定的挂载点后直接访问。

1)挂载整个存储卷
  关联为Pod资源的存储卷时,ConfigMap对象中的每个键都对应的表现为一个文件,键名转换为文件名,而键值则为相应文件的内容,即便是通过直接创建的键值数据,也一样表现为文件视图。挂载于容器之上,由键值数据表现出的文件位于挂载点目录中,容器中的进程可直接读取这些文件的内容。
  配置Pod资源时,基于存储卷的方式引用ConfigMap对象的方法也非常简单,仅需要指明存储卷名称及要引用的ConfigMap的对象名称即可。

]# cat configmap-volume.yaml 
apiVersion: v1
kind: Pod
metadata: 
  name: configmap-volume-demo
  namespace: default
spec:
  containers:
  - name: nginx-server
    image: nginx:alpine
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: ngxconfig
      mountPath: /data/
      readOnly: true
  volumes:
    - name: ngxconfig
      configMap:
        name: nginx-conf-files

]# kubectl apply -f configmap-volume.yaml 
pod/configmap-volume-demo created

查看Pod资源详细信息:

]# kubectl get pods  -o wide 
NAME                    READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
configmap-volume-demo   1/1     Running   0          11s   10.244.1.123   node1   <none>           <none>

]# kubectl describe pods configmap-volume-demo 
Name:         configmap-volume-demo
Namespace:    default
Priority:     0
Node:         node1/172.16.2.101
Start Time:   Mon, 31 Aug 2020 17:08:30 +0800
Labels:       <none>
Annotations:  Status:  Running
IP:           10.244.1.123
IPs:
  IP:  10.244.1.123
Containers:
  nginx-server:
    Container ID:   docker://f32e43cc784d89bc6b547ff7d21a54c252d9bf3d0a328327065e5b83401aefde
    Image:          nginx:alpine
    Image ID:       docker-pullable://nginx@sha256:a97eb9ecc708c8aa715ccfb5e9338f5456e4b65575daf304f108301f3b497314
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Mon, 31 Aug 2020 17:08:31 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /data/ from ngxconfig (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-47pch (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  ngxconfig:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      nginx-conf-files
    Optional:  false
  default-token-47pch:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-47pch
    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/configmap-volume-demo to node1
  Normal  Pulled     <invalid>  kubelet, node1     Container image "nginx:alpine" already present on machine
  Normal  Created    <invalid>  kubelet, node1     Created container nginx-server
  Normal  Started    <invalid>  kubelet, node1     Started container nginx-server

查看Pod中的配置文件是否存在:

]# kubectl exec -it configmap-volume-demo ls  -- /data/
myserver-1.conf  myserver-2.conf

2)挂载存储卷中的部分键值
  有的时候,用户很可能不期望在容器中挂载某个ConfigMap存储卷后于挂载点目录导出所有的文件,这在通过一个ConfigMap对象为单个Pod资源中的多个容器分别提供配置时尤其常见;所以ConfigMap存储卷也允许我们通过指定的字段来挂载特定的ConfigMap资源对象中的部分键值。

]# cat configmap-volume2.yaml 
apiVersion: v1
kind: Pod
metadata: 
  name: configmap-volume-demo
  namespace: default
spec:
  containers:
  - name: nginx-server
    image: nginx:alpine
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: ngxconfig
      mountPath: /data/
      readOnly: true
  volumes:
    - name: ngxconfig
      configMap:
        name: nginx-conf-files
        items:
        - key: myserver-1.conf
          path: myserver-1.conf
          mode: 0644

]# kubectl apply -f configmap-volume2.yaml 
pod/configmap-volume-demo created

查看Pod资源详细信息:

]# kubectl get pods -o wide 
NAME                    READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
configmap-volume-demo   1/1     Running   0          9s    10.244.1.124   node1   <none>           <none>

]# kubectl describe pods configmap-volume-demo 
Name:         configmap-volume-demo
Namespace:    default
Priority:     0
Node:         node1/172.16.2.101
Start Time:   Mon, 31 Aug 2020 17:17:51 +0800
Labels:       <none>
Annotations:  Status:  Running
IP:           10.244.1.124
IPs:
  IP:  10.244.1.124
Containers:
  nginx-server:
    Container ID:   docker://b7c88eba8c2f5c5a4bc6b025187bed9e5e3c3ab28ef544cd65310e08e0e6ad8f
    Image:          nginx:alpine
    Image ID:       docker-pullable://nginx@sha256:a97eb9ecc708c8aa715ccfb5e9338f5456e4b65575daf304f108301f3b497314
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Mon, 31 Aug 2020 17:17:52 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /data/ from ngxconfig (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-47pch (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  ngxconfig:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      nginx-conf-files
    Optional:  false
  default-token-47pch:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-47pch
    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/configmap-volume-demo to node1
  Normal  Pulled     <invalid>  kubelet, node1     Container image "nginx:alpine" already present on machine
  Normal  Created    <invalid>  kubelet, node1     Created container nginx-server
  Normal  Started    <invalid>  kubelet, node1     Started container nginx-server

验证ConfigMap资源是否已挂载:

]# kubectl exec -it configmap-volume-demo -- ls /data/
myserver-1.conf

使用ConfigMap资源的注意事项:
  1)以存储卷方式引用的ConfigMap必须先于Pod存在,除非在Pod中将它们全部标记为"optional",否则将会导致Pod无法正常启动的错误;同样,即使存在ConfigMap,在引用的键不存在时,也会导致一样的错误。
  2)当以环境变量方式注入的ConfigMap中的键不存在时会被忽略,Pod可以正常启动,但错误引用的信息会以"InvalidVariableNames"事件记录于日志中。
  3)ConfigMap是名称空间级别的资源,因此,引用它的Pod必须处于同一名称空间中。
  4)kubelet不支持引用Kubernetes API Server上不存在的ConfigMap资源,这包括那些通过kubelet的"–manifest-url"或"–config"选项,以及kubectl REST API创建的Pod。

你可能感兴趣的:(Kubernetes学习)