说到配置中心,大家接触过微服务的话,应该不陌生,像国内的分布式配置中心相关开源项目有 Diamond(阿里)、Apollo(携程)、Qconf(奇虎360)和 disconf(百度)等。
作为分布式系统的 Kubernetes 也提供了统一配置管理方案——ConfigMap。
Kubernetes 基于 ConfigMap 对象实现了将配置文件从容器镜像中解耦,从而增强了容器应用的可移植性。简单来说,一个 ConfigMap 对象就是一系列配置数据的集合,这些数据可 "注入" 到 Pod 对象中,并为容器应用所用,注入方式有挂载为存储卷和传递为环境变量两种。
ConfigMap 对象将配置数据以键值对的形式进行存储,这些数据可以在 Pod 对象中使用或者为系统组件提供配置。无论应用程序如何使用 ConfigMap 对象中的数据,用户都完全可以通过在不同的环境中创建名称相同但内容不同的 ConfigMap 对象,从而为不同环境中同一功能的 Pod 资源提供不同的配置信息,实现应用与配置的灵活勾兑。
Kubernetes 的不少资源既可以使用 kubectl create 命令创建,也可以使用清单创建,例如前面讲到的 namespace。
ConfigMap 是另一个两种创建方式都比较常用的资源。而且,通过使用 "kubectl create configmap" 命令,用户可以根据目录、文件或直接值创建 ConfigMap对象。命令的语法格式如下所示:
root@mh-k8s-master-247-10 ~]# kubectl create configmap --help Create a configmap based on a file, directory, or specified literal value. A single configmap may package one or more key/value pairs. When creating a configmap based on a file, the key will default to the basename of the file, and the value will default to the file content. If the basename is an invalid key, you may specify an alternate key. When creating a configmap based on a directory, each file whose basename is a valid key in the directory will be packaged into the configmap. Any directory entries except regular files are ignored (e.g. subdirectories, symlinks, devices, pipes, etc). Aliases: configmap, cm Examples: # Create a new configmap named my-config based on folder bar kubectl create configmap my-config --from-file=path/to/bar # Create a new configmap named my-config with specified keys instead of file basenames on disk kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt # Create a new configmap named my-config with key1=config1 and key2=config2 kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2 # Create a new configmap named my-config from the key=value pairs in the file kubectl create configmap my-config --from-file=path/to/bar # Create a new configmap named my-config from an env file kubectl create configmap my-config --from-env-file=path/to/bar.env Options: --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. --append-hash=false: Append a hash of the configmap to its name. --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource. --from-env-file='': Specify the path to a file to read lines of key=val pairs to create a configmap (i.e. a Docker .env file). --from-file=[]: Key file can be specified using its file path, in which case file basename will be used as configmap key, or optionally with a key and file path, in which case the given key will be used. Specifying a directory will iterate each named file in the directory whose basename is a valid configmap key. --from-literal=[]: Specify a key and literal value to insert in configmap (i.e. mykey=somevalue) -o, --output='': Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file. --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future. --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]. --validate=true: If true, use a schema to validate the input before sending it Usage: kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run=server|client|none] [options] Use "kubectl options" for a list of global command-line options (applies to all commands). [root@mh-k8s-master-247-10 ~]#
其中,<map-name> 即为 ConfigMap 对象的名称,而 <data-source> 是数据源,它可以通过直接值、文件或目录来获取。无论是哪一种数据源供给方式,它都要转换为 ConfigMap 对象中的 Key-Value 数据,其中 Key 由用户在命令行给出或是文件数据源的文件名,它仅能由字母、数字、连接号和点号组成,而 Value 则是直接值或文件数据源的内容。
为 "kubectl create configmap" 命令使用 "--from-literal" 选项可在命令行直接给出键值对来创建 ConfigMap 对象,重复使用此选项则可以传递多个键值对。命令格式如下:
kubectl create configmap configmap_name --from-literal=key-name-1=value-1 --from-literal=key-name-2=value-2 help: --from-literal=[]: Specify a key and literal value to insert in configmap (i.e.mykey=somevalue)
"kubectl get configmap" 命令可用于查看创建的 ConfigMap 对象 special-config 的相关信息。举个例子:
[root@mh-k8s-master-247-10 ~]# kubectl get configmap NAME DATA AGE istio-ca-root-cert 1 74d [root@mh-k8s-master-247-10 ~]# kubectl get configmap istio-ca-root-cert -o yaml apiVersion: v1 data: root-cert.pem: | -----BEGIN CERTIFICATE----- 省略 -----END CERTIFICATE----- kind: ConfigMap metadata: creationTimestamp: "2022-04-12T05:23:11Z" labels: istio.io/config: "true" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:root-cert.pem: {} f:metadata: f:labels: .: {} f:istio.io/config: {} manager: pilot-discovery operation: Update time: "2022-04-12T05:23:11Z" name: istio-ca-root-cert namespace: default resourceVersion: "6208" selfLink: /api/v1/namespaces/default/configmaps/istio-ca-root-cert uid: e03bd294-dd7d-417c-a6eb-3a6066cde0dd [root@mh-k8s-master-247-10 ~]#
为 "kubeclt create configmap" 命令使用 "--from-file" 选项即可基于文件内容来创建 ConfigMap 对象,可以重复多次使用 "--from-file" 选项以传递多个文件内容,它的命令格式如下:
Usage: kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run=server|client|none] [options]
例如,下面命令可以把事先准备好的 Nginx 配置文件模板保存于 ConfigMap 对象 nginx-config:
kubectl create configmap nginx-config\ --from-file=./data/configs/nginx/conf.d/www.aaa.com.conf \ --from-file=./data/configs/nginx/conf.d/www.bbb.com.conf
如果需要自行指定键名,则可在 "--from-file" 选项中直接指定自定义的键,命令格式如下:
kubectl create configmap nginx-config\ --from-file=aaa=./data/configs/nginx/conf.d/www.aaa.com.conf \ --from-file=bbb=./data/configs/nginx/conf.d/www.bbb.com.conf
如果配置文件数量较多且存储于有限的目录中时,kubeclt 还提供了基于目录直接将多个文件分别纳为键值数据的 ConfigMap 资源创建方式。将 "--from-file" 选项后面所跟的路径指向一个目录路径就能将目录下的所有创建于同一 ConfigMap 资源中,命令格式如下:
Usage: kubectl create configmap <configmap_nam>[--from-file=<path-to-directory>]
如下面的命令,将 /data/configs/nginx/conf.d/ 目录下的所有文件都保存于 nginx-config-files 对象中:
kubect create configmap nginx-config-file --from-file=./data/confnigs/nginx/conf.d/
基于配置文件创建 ConfigMap 资源时,它所使用的字段包括通常的 apiVersion、kind 和 metadata 字段,以及用于存储数据的关键字段 "data"。例如下面的示例代码:
apiVersion: v1 kind: configMap metadata: name: configmap-demo namespace: default data: log_level: INFO log_file: /var/log/test.log
如果其值来自于文件内容时,则使用配置文件创建 ConfigMap 资源的便捷性还不如直接通过命令行的方式,因此建议直接使用命令行加载文件或目录的方式进行创建。为了便于配置留存,可以在创建完成后使用 get -o yaml 命令获取到相关信息后再进行编辑留存。
Pod 资源的环境变量的获得方式之一包括引用 ConfigMap 对象中的数据,这一点通过在 env 字段中为 valueFrom 内嵌 configMapKeyRef 对象即可实现,其使用格式如下:
valueFrom: configMapKeyRef: key: name: optional:
下面是保存于配置文件 configmap-env.yaml 的资源定义示例,它包含了两个资源,彼此之间使用 "---" 互相分隔。
apiVersion: v1 kind: ConfigMap metadata: name: busybox-httpd-config namespace: default data: http_port: "8080" verbose_level: "-vv" --- apiVersion: v1 kind: Pod metadata: name: configmap-env-demo namespace: default spec: containers: - image: busybox-httpd command: ["/bin/httpd"] args: ["-f", "-p", "$(HTTPD_PORT)","$(HTTPD_LOG_VERBOSE)"] env: - name: HTTP_PORT valueFrom: configMapKeyRef: name: busybox-httpd-config key: httpd_port - name: HTTPD_LOG_VERBOSE valueFrom: configMapKeyRef name: busybox-httpd-config key: verbose_level optional: true
注意,在 command 或 args 字段中引用环境变量要使用 "$(VAR_NAME)" 的格式。待上面配置文件中的资源创建完成后,可以通过如下命令验证 pod 资源监听的端口等配置信息是否为 busybox-httpd-config 中定义的内容:
kubectl exec configmap-env-demo ps aux
ConfigMap 是名称空间级别的资源,它必须与引用它的 Pod 资源在同一空间中。
若 ConfigMap 对象中的键值来源于较长的文件内容,那么使用环境变量将其导入会使得变量值占据过多的内存空间而且不易处理。此类数据通常用于为容器应用提供配置文件,因此将其内容直接作为文件进行引用是较好的选择。其实现方式是,在定义 Pod 资源时,将此类 ConfigMap 对象配置为 ConfigMap 类型的存储卷,而后由容器将其挂载至特定的挂载点后直接进行访问。
关联为 Pod 资源的存储卷时,ConfigMap 对象中的每个键都对应地表现为一个文件,键名转为文件名,而键值则为相应文件的内容,即便是通过直接值创建的键值数据,也一样表现为文件视图。挂载于容器上之后,由键值数据表现出的文件位于挂载点目录中,容器中的进程可直接读取这些文件的内容。
配置 Pod 资源时,基于存储卷的方式引用 ConfigMap 对象的方法非常简单,仅需要指明存储卷名称及要应用的 ConfigMap 对象名称即可。
下面是于配置文件 configmap-volume-pod.yaml 中定义的 Pod 资源,具体如下:
apiVersion: v1 kind: Pod metadata: name: configmap-volume-demo namespace: default spec: containers: - image: nginx:alpine name: nginx-server volumeMounts: - name: ngxconfig mountPath: /etc/nginx/conf.d/ readOnly: true volumes: - name: ngxconfig configMap: name: nginx-config-files
有时候,我们可能期望在容器中挂载某 ConfigMap 存储卷后,只 "导出" 部分文件内容(只导出部分 key:value 数据),示例如下:
apiVersion: v1 kind: Pod metadata: name: configmap-volume-demo-2 namespace: default spec: containers: - image: nginx:alpine name: nginx-server volumeMounts: - name: ngxconfig mountPath: /etc/nginx/conf.d/ readOnly: true volumes: - name: ngxconfig configMap: name: nginx-config-files items: - key: myserver.conf path: myserver.conf mode: 0644 items: - key: youserver.conf path: youserver.conf mode: 0644
pod.spec.volumes.configMap 字段定义如下:
[root@mh-k8s-master-247-10 ~]# kubectl explain pod.spec.volumes.configMap KIND: Pod VERSION: v1 RESOURCE: configMap <Object> DESCRIPTION: ConfigMap represents a configMap that should populate this volume Adapts a ConfigMap into a volume. The contents of the target ConfigMap's Data field will be presented in a volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. ConfigMap volumes support ownership management and SELinux relabeling. FIELDS: defaultMode <integer> Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. items <[]Object> If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. name <string> Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names optional <boolean> Specify whether the ConfigMap or its keys must be defined [root@mh-k8s-master-247-10 ~]#
pod.spec.volumes.configMap.items 字段定义如下:
[root@mh-k8s-master-247-10 ~]# kubectl explain pod.spec.volumes.configMap.items KIND: Pod VERSION: v1 RESOURCE: items <[]Object> DESCRIPTION: If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. Maps a string key to a path within a volume. FIELDS: key <string> -required- The key to project. mode <integer> Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. path <string> -required- The relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. [root@mh-k8s-master-247-10 ~]#
前面几种方式中,无论是挂载所有文件还是部分文件,挂载点目录下原有的文件都会被隐藏。对于期望将 ConfigMap 对象提供的配置文件补充于挂载点目录下,并且不影响原本就存在的一些文件,这种方式显然难以如愿。
例如:/etc/nginx/conf.d 目录中原本就存在一些文件(如 default.conf),用户期望将 nginx-config-files 中的全部或部分文件装载进此目录中而不影响其原有的文件。
解决办法:使用容器的 volumeMounts 字段中使用的 subPath 字段来解决,它可以支持用户从存储卷挂载单个文件或单个目录而非整个存储卷。
apiVersion: v1 kind: Pod metadata: name: configmap-volume-demo-3 namespace: default spec: containers: - image: nginx:alpine name: nginx-server volumeMounts: - name: ngxconfig mountPath: /etc/nginx/conf.d/myserver.conf subPath: myserver.conf readOnly: true - name: ngxconfig mountPath: /etc/nginx/conf.d/yourserver.conf subPath: yourserver.conf readOnly: true volumes: - name: ngxconfig configMap: name: nginx-config-files
pod.spec.containers.volumeMounts 字段定义如下:
[root@mh-k8s-master-247-10 ~]# kubectl explain pod.spec.containers.volumeMounts KIND: Pod VERSION: v1 RESOURCE: volumeMounts <[]Object> DESCRIPTION: Pod volumes to mount into the container's filesystem. Cannot be updated. VolumeMount describes a mounting of a Volume within a container. FIELDS: mountPath <string> -required- Path within the container at which the volume should be mounted. Must not contain ':'. mountPropagation <string> mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. name <string> -required- This must match the Name of a Volume. readOnly <boolean> Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false. subPath <string> Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root). subPathExpr <string> Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. [root@mh-k8s-master-247-10 ~]#
建议:重启容器。