ConfigMap 许多应用经常会有从配置文件,命令行参数或者环境变量中读取一些配置信息,这些配置信息不应该直接写死在到应用程序中,比如你一个应用连接一个 redis 服务,下一次下一次想要更换一个的,还得重新修改代码,重新制作一个镜像, 这样是不可取的, ConfigMap 给我们提供了向容器中注入配置信息的能力,不仅可以用来保存单个属性,也可以用来保存整个配置文件,比如我们可以用来配置一个redis服务的访问地址,也可以用来保存整个redis的配置文件

创建

通过Yaml文件创建

ConfigMap资源对象使用 key-value 形式的键值对来配置数据,这些数据可以在 Pod 中使用, ConfigMap 和我们后面的 Secrets 比较类似,一个较大的区别是 ConfigMap 可以比较方便的处理一些非敏感的数据,比如密码之类的还是需要使用 Secrets 来进行管理,

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-demo1
data:
data.1: hello
data.2: world
config:
property.1=value-1
property.2=value-2
property.3=value-3

其中配置数据在 data 属性下面进行配置,前两个被用来保存单个属性,后面一个被用来保存一个配置文件。

1
kubectl create -f xxx.yaml

通过指定文件创建

同时也可以用 kubectl create configmap -h 来查看关于创建 ConfigMap 的帮助信息

1
2
3
4
5
6
7
8
9
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

可以从一个给定的目录来创建一个 ConfigMap 对象,比如我们有一个 testcm 的目录,该目录下面包含一些配置文件,redismysql 的连接信息

1
2
3
4
5
6
7
8
9
10
11
$ ls testcm
redis.conf
mysql.conf

$ cat testcm/redis.conf
host=127.0.0.1
port=6379

$ cat testcm/mysql.conf
host=127.0.0.1
port=3306

可以使用 from-file 关键字来创建包含这个目录下面所有配置文件的 ConfigMap:

1
2
$ kubectl create configmap cm-demo1 --from-file=testcm
configmap "cm-demo1" created

from-file 参数指定在该目录下面的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容, 创建完成过后,使用命令来查看 ConfigMap列表:

1
2
3
$ kubectl get configmap
NAME DATA AGE
cm-demo1 2 17s

使用 describe 命令查看详细信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
kubectl describe configmap cm-demo1
Name: cm-demo1
Namespace: default
Labels: <none>
Annotations: <none>

Data
====
mysql.conf:
----
host=127.0.0.1
port=3306

redis.conf:
----
host=127.0.0.1
port=6379

Events: <none>

可以看到 keytestcm 目录下面的文件名称,对应的 value 值的话就是文件内容,如果文件里面的配置信息很大的话,describe 的时候肯跟不会显示对应的值,要查看键值的话,可以使用如下的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ kubectl get configmap cm-demo1 -o yaml
apiVersion: v1
data:
mysql.conf: |
host=127.0.0.1
port=3306
redis.conf: |
host=127.0.0.1
port=6379
kind: ConfigMap
metadata:
creationTimestamp: 2018-06-14T16:24:36Z
name: cm-demo1
namespace: default
resourceVersion: "3109975"
selfLink: /api/v1/namespaces/default/configmaps/cm-demo1
uid: 6e0f4d82-6fef-11e8-a101-525400db4df7

除了通过文件目录进行创建, 也可以使用指定的文件进行创建 ConfigMap, 我们创建一个 redis 配置的单独 ConfigMap对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ kubectl create configmap cm-demo2 --from-file=testcm/redis.conf
configmap "cm-demo2" created
$ kubectl get configmap cm-demo2 -o yaml
apiVersion: v1
data:
redis.conf: |
host=127.0.0.1
port=6379
kind: ConfigMap
metadata:
creationTimestamp: 2018-06-14T16:34:29Z
name: cm-demo2
namespace: default
resourceVersion: "3110758"
selfLink: /api/v1/namespaces/default/configmaps/cm-demo2
uid: cf59675d-6ff0-11e8-a101-525400db4df7

可以看到关联 redis.conf 文件配置信息的 ConfigMap 对象创建成功了,--from-file 可以使用多次,可以使用两次分别指定 redis.confmysql.conf 文件,就和直接指定整个目录一样的效果了

通过字符串创建

通过帮助文档可以直接使用字符串进行创建, 通过 --from-literal 参数传递配置信息,同样的,这个参数可以使用多次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kubectl create configmap cm-demo3 --from-literal=db.host=localhost --from-literal=db.port=3306
configmap "cm-demo3" created
$ kubectl get configmap cm-demo3 -o yaml
apiVersion: v1
data:
db.host: localhost
db.port: "3306"
kind: ConfigMap
metadata:
creationTimestamp: 2018-06-14T16:43:12Z
name: cm-demo3
namespace: default
resourceVersion: "3111447"
selfLink: /api/v1/namespaces/default/configmaps/cm-demo3
uid: 06eeec7e-6ff2-11e8-a101-525400db4df7

使用

ConfigMap 创建成功了,那么我们应该怎么在 Pod 中使用呢,我们说 ConfigMap 这些配置数据可以通过很多种方式在 Pod里使用,主要有一下集中方式:

  • 设置环境变量的值
  • 在容器里设置命令行参数
  • 在数据卷里面创建config文件

ConfigMap 填充环境变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: v1
kind: Pod
metadata:
name: testcm1-pod
spec:
containers:
- name: testcm1
image: busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.host
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.port
envFrom:
- configMapRef:
name: cm-demo1

创建 Pod

1
kubectl create -f testcm-pod.yaml

这个 Pod 运行后会输出如下几行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ kubectl logs testcm1-pod 
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=testcm1-pod
DB_PORT=3306
SHLVL=1
HOME=/root
mysql.conf=host=127.0.0.1
port=3306

redis.conf=host=127.0.0.1
port=6379

KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
DB_HOST=localhost

DB_HOSTDB_PORT 都已经正常输出了,另外的环境变量是因为我们这里直接把 cm-demo1 给注入锦鲤啊了,所以把他们整个键值给输出出来了,这也是符合预期的, 另外我们可以使用 ConfigMap 来这只命令行参数,ConfigMap 也可以被用来设置容器中的命令货参数值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: Pod
metadata:
name: testcm2-pod
spec:
containers:
- name: testcm2
image: busybox
command: [ "/bin/sh", "-c", "echo $(DB_HOST) $(DB_PORT)" ]
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.host
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: cm-demo3
key: db.port

运行这个 Pod 后会输出如下信息

1
2
$ kubectl logs testcm2-pod
localhost 3306

另外一种方式是非常常见的使用 ConfigMap 的方式: 通过数据卷使用,在数据卷里面使用 ConfigMap, 就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Pod
metadata:
name: testcm3-pod
spec:
containers:
- name: testcm3
image: busybox
command: [ "/bin/sh", "-c", "cat /etc/config/redis.conf" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: cm-demo2

运行这个 Pod, 查看日志

1
2
3
$ kubectl logs testcm3-pod
host=127.0.0.1
port=6379

也还在 ConfigMap 值被映射的数据卷里去控制路径,如下 Pod 定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Pod
metadata:
name: testcm4-pod
spec:
containers:
- name: testcm4
image: busybox
command: [ "/bin/sh","-c","cat /etc/config/path/to/msyql.conf" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: cm-demo1
items:
- key: mysql.conf
path: path/to/msyql.conf

运行这个 Pod,查看日志

1
2
3
$ kubectl logs testcm4-pod
host=127.0.0.1
port=3306

需要注意的是,当 ConfigMap 以数据卷的形式挂载进 Pod 的时候,这时更新 ConfigMap Pod 內挂载的配置信息会热更新,这时可以增加一些监测配置文件变更的脚本,然后 reload 对应服务