Skip to content

Kubernetes(六)–ConfigMaps是如何工作的?

这一篇文章介绍下Kubernetes中如何做配置。

前言

云原生的微服务应用应该是应用和配置解耦的,这样可以带来很多好处,包括可以重用应用镜像,简化测试。
举个例子,一个应用通常有Dev,Test,Prod 3个环境,在Dev下开发,在Test下测试,在Prod上线,不同的环境会使用不同的资源,
比如使用的数据库不同,cluster的节点不同等等。
如果把程序和配置耦合在一起,那么就需要创建3份镜像,每次改变配置后都需要重新创建新的镜像,这样给开发带来很大的不便。
比如要管理多份镜像,也不利于测试,比如代码和配置同时都有改动,不利于快速定位时代码有问题,还是配置不正确。
所以要把代码和应用进行解耦,这样只需要创建一份镜像,每次在不同的环境去加载不同的配置即可。

ConfigMap

Kubernetes利用ConfigMap 这样一个object 来实现把配置和Pod进行解耦,或者说实现在Pod运行在动态注入数据。
这里提到Pod也包括了Pod中运行的container,实际读配置的是container 的镜像,但是Pod是Kubernetes的最小原子单元,所以这里说Pod。

ConfigMap 主要用来存储非敏感配置信息,不应该用来存放证书和密码。Kubernetes 提供另一个object Secret 用来存放敏感数据。
ConfigMap是一个map结构,每一个条目(entry) 是一个键值对。key可以是字母数字,也可以包含下划线,连接线,点等字符。
举个例子:

db-port: 3306
hostname: prod-db1

value也可以是完整的文件内容。

当配置数据存储在ConfigMap中后,Pod可以通过以下方式使用:
– 环境变量
– container startup command的参数
– 数据卷中的文件

事实上应用也只能通过以上方式使用配置,应用并不直接感知到ConfigMap的存在。

还有一种应用叫Kubernetes-native 应用,这种原生的应用不同于普通的应用,它能够直接访问Kubernetes API,因此这种原生应用能够直接访问ConfigMap,而不用通过上面提到的环境变量和数据卷的方式访问。

接下来我们具体学习如何创建ConfigMap以及如何使用ConfigMap

创建ConfigMap的方式

命令式:我们可以直接通过kubernetes 命令kubectl create configmap 直接创建ConfigMap object.
并且可以直接在命令中提供key value或者通过文件创建。通过文件创建时,文件名是key, 对应的value是文件的内容。
命令式ConfigMap 一旦创建完成就无法更改。

kubectl create configmap testmap1 --from-literal shortname=msb.com --from-literal longname=magicsandbox.com

声明式:来看一个ConfigMap的Yaml文件

kind: ConfigMap
apiVersion: v1
metadata:
  name: multimap
data:
  given: Nigel
  family: Poulton

和之前我们介绍的Pod,Deployment,Service,Storage等不同,ConfigMap的yaml 结构中没有spec,而是有一个data

同样也可以在Yaml中定义一个value是文件内容的 key,value。

kind: ConfigMap
apiVersion: v1
metadata:
  name: test-conf
data:
  test.conf: |
    env=plex-test
    endpoint=0.0.0.0:30001
    char=utf8
    vault=PLEX/test
    log-size=512M

然后执行kubectl describe configmap test-conf 查看。结果如下图所示。
test-confg

具体使用ConfigMap

上面提到应用使用ConfigMap有三种方式: 环境变量,container startup 命令中的参数,数据卷。
这里我们分别具体介绍如何使用。

我们先创建一个叫multimap的ConfigMap
multimap.yml

kind: ConfigMap
apiVersion: v1
metadata:
  name: multimap
data:
  given: Nigel
  family: Poulton

然后部署

kubectl apply -f multimap.yml
kubectl describe cm multimap

注意cm是configmap的缩写,其他地方都用的是configmap 这里用的是cm仅仅为了展示缩写
结果如下:
multimap

  • 利用环境变量使用ConfiMap

这种方式读取ConfigMap的值然后创建container中的环境变量,然后应用就可以通过读取环境变量来使用ConfigMap中的值了。
上面我们定义了一个multimap的ConfigMap,现在我们在Pod中引用它,并创建两个环境变量。
Pod的yaml如下所示:

kind: Pod
apiVersion: v1
metadata:
  name: envpod
spec:
  containers:
  - name: container1
    image: ubuntu:latest
    command: ["sleep"]  # 这个很重要否则container 启动后会立即退出
    args: ["infinity"]  # 
    ports:
    - containerPort: 8080
    env:
    - name: FIRSTNAME
      valueFrom:
        configMapKeyRef:
          name: multimap
          key: given
    - name: LASTNAME
      valueFrom:
        configMapKeyRef:
          name: multimap
          key: family

执行kubectl apply -f envpod.yml 部署此pod,待其状态running

然后执行kubectl exec envpod -- env | grep NAME 查看环境变量
结果如下图所示。
envpod result

  • 利用container startup 命令中的参数使用ConfigMap
    这个和读取环境变量的方式基本相同,其实这种方式的意思是,我们可以通过环境变量读取ConfigMap,并且可以在container startup 中的命令里使用这些定义的环境变量。

比如定义一个args1.yml

kind: Pod
apiVersion: v1
metadata:
  name: args1
spec:
  containers:
  - name: container1
    image: ubuntu:latest
    command: ["/bin/sh", "-c", "echo First name $(FIRSTNAME) last name $(LASTNAME)"]
    ports:
    - containerPort: 8080
    env:
    - name: FIRSTNAME
      valueFrom:
        configMapKeyRef:
          name: multimap
          key: given
    - name: LASTNAME
      valueFrom:
        configMapKeyRef:
          name: multimap
          key: family

这里注意两点:
(1)在startup command里我们引用了环境变量$(FIRSTNAME) 和$(LASTNAME)。
(2)这里command 执行完会立即结束,然后container也会推出,会导致Pod陷入 CrashLoopBackOff 状态

那我们怎么验证它工作了呢? 我们可以查看这个Pod的log

kubectl logs args1

pod logs

利用环境变量使用ConfigMap有个限制就是,当更新ConfigMap后,并不能反映到运行的容器中去,即环境变量不能随之更新。

  • 利用数据卷使用ConfigMap
    利用数据卷是使用ConfigMap最为灵活的方式,并且更新ConfigMap也能够反映到运行的容器中,即可以在创建container后更新ConfigMap,并且这个更新可以被运行的应用感知。

下面创建一个使用数据卷使用ConfigMap的Pod, yaml文件如下所示:
configMapVolumePod.yml

kind: Pod
apiVersion: v1
metadata:
  name: configmapvolumepod
spec:
  volumes:
  - name: volmap
    configMap:
      name: multimap
  containers:
  - name: container1
    image: ubuntu:latest
    command: ["sleep"]
    args: ["infinity"]
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: volmap
      mountPath: /etc/name

spec.volumes 利用ConfigMap multimap 创建了一个特殊的volume叫ConfigMap volume。
这个数据卷会遍历multimap这个ConfigMap object存储的键值对(或叫记录),并生成对应的文件。
文件名是ConfigMap的key, 文件内容是ConfigMap的value。在这个例子中我们把这个数据卷挂载到了/etc/name 目录,那么数据卷的文件也会出现在container的这个目录。我们可以查看相关文件和内容。
config map volume pod

Published inKubernetes

Comments are closed.

Author Copyriht by BackendSite