云计算时代操作系统Kubernetes之动态配置

笔者关于配置的话题已经有多篇了,不过细心的读者会发现,我们前边所有介绍的内容中,都是讲如何把确定的配置信息传递给容器实例,也就是我们的应用程序,但是情况不总是如此,有些时候我们无法在编写YAML文件的时候,确定具体配置项的值。

举几个例子来说明一下,作为Kubernetes平台的用户,当我们通过kubectl将要部署的应用程序推到API Server之后,对象数据会被保存到ETCD,接着控制器会收到通知,基于YAML文件的配置,比如说配置了replica,那么会调用API Server提供的API,来创建用户预期的POD对象,当这些POD对象被持久化到ETCD,然后会通知调度器,调度器基于预设的调度算法,以及集群当前资源的现状,会选择最合适的工作节点来运行这个新创建的应用程序。

上边的这段描述平淡无奇,笔者想说的是,如果我们要知道容器运行在哪个工作节点上,在编写YAML文件的时候,是不知道的。当然精通Kubernetes的同学会说,可以知道啊,我给POD设置集群中具体node节点名字不就行了,但是这就失去了调度的含义了,并且这种场景和笔者这里的描述不冲突。

除了容器具体会运行到那台工作节点这样的信息我们在编写YAML文件的时候不知道,还有譬如POD使用的CPU和内存信息等等,简单来说,我们需要一种机制来获取POD运行起来之后的状态信息。Kubernetes提供了Downward API机制,允许运行在POD中的容器能够获取到POD的元数据因袭,或者说POD可以把自己的某些字段,作为环境变量注入到容器进程中,或者作为文件挂载到容器的文件系统中。

看到这里,读者一定会问,那么到底什么是Downward API呢?其实Downward API这个概念不是很准确,因为根本没有什么API给我们来调用。笔者认为它更多描述的是一种能力,一种从POD中将某些字段注入到容器进程的环境变量中,因此大家不要纠结于名字上,如下图所示Downward API的工作原理:

《图1.1 Downward API将POD的元数据注入到容器的环境变量或者文件》

如上图所示,Downward API和configMap以及secret对象在讲配置信息注入到容器运行环境这一点上,基本没有什么太大的区别,唯一的不同就是这些配置信息,键值对来自于POD自己而已。这也是Downward这个词的意义所在,downward在英语中意思是“向下的”,而容器和POD的关系我们已经反复强调过,POD是逻辑的概念,因此你不会在工作节点上找到PDO这样的进程,容器隶属于POD,和POD具有相同的生命周期,因此从POD想容器实例传递自身元数据信息的过程,其实可以理解为“向下”,因此这种方式被称为Downward API。

我们在前边介绍如何把配置信息传递到容器的时候,大家知道我们可以通过valueFrom字段,来把外部的配置值注入到容器实例;如果配置信息在configMap中,我们可以使用configMapKeyRef字段;如果隐私信息在secret对象中,我们可以使用secretKeyRef字段。那么对于Downward API来说,区别不是太大,Kubernetes提供了fieldRef和resourceFieldRef字段,分别用来把POD相关的通用信息和资源信息注入到容器实例。

当然我们也可以把POD的元数据信息以文件的形式注入到容器中,采用的方式和congfigMap或者secret对象类似,通过downwardAPI数据卷类型先定义对应的数据卷,然后挂载到容器的文件系统的特定路径就可以了。读者看到这里可能会问,是不是所有的信息都可以注入到容器实例中?当然不是,我们来看看具体哪些字段,元数据信息可以通过downward API注入到容器实例中,如下表所示:

《图1.2 Downward API的fieldRef支持的字段和方式》

如上图所示,他们可以在POD的的YAML文件中,通过fieldRef字段的方式,来将如上表列出的字段,注入到容器进程中,供应用程序使用。如果我们要在容器中访问和计算资源相关的字段,那么就需要使用resourceFieldRef字段,如下图所示,resourceFieldRef支持的资源相关的信息:

《图1.3 Downward API的resourceFieldRef支持的字段和方式》

好了,有了上边这些信息的铺垫,接下来我们来通过具体的例子,来实战一下Downward API。我们的目的是通过Downward API在应用中把工作节点的IP地址和工作节点的名称打印出来,因此我们必须在POD的定义中,将相关信息注入到容器的环境变量中,分别是:POD_NAME,POD_IP,NODE_NAME,和NODE_IP。相关部分的POD定义如下图所示:


《图1.4 在POD定义中使用Downward API来注入信息到容器进程》

如上图所示,我们在容器中通过downward api把工作节点的信息注入到了容器中,这样就可以在容器中使用这些信息了。废话不多说,咱赶紧把这个POD部署到Kubernetes集群中,看看会返回哪些信息。已下是笔者的本地环境的输出:

➜  Kubernetes配置管理 kubectl apply -f yunpan-ssl-downward-api.yaml

pod/yunpan-ssldw created

➜  Kubernetes配置管理 kubectl get pod

NAME          READY  STATUS    RESTARTS  AGE

yunpan-ssldw  2/2    Running  0          25s

➜  Kubernetes配置管理 curl http://localhost:8080

Request processed by 云攀的Node应用 1.0 running in pod "yunpan-ssldw" on node "minikube".

Pod hostname: yunpan-ssldw; Pod IP: 172.17.0.10; Node IP: 192.168.49.2. Client IP: ::ffff:127.0.0.1

如果这个时候在名叫yunpan-ssldw的容器进程上执行env命令,输出的环境变量中应该有我们通过downward api注入的数据,我们来验证一下,在自己的环境上运行命令:kubectl exec yunpan-ssldw -- env,输出结果如下图所示:

《图1.5 在容器进程里运行env命令的输出结果》

如上图所示,我们从env命令的输出结果中可以看到我们通过downward api注入到yunpan-ssldw这个进程的环境变量和值。接下来,我们来看看另外一种类型,通过resourceFieldRef字段来把资源信息注入到容器实例中。

容器化部署的最大好处是单机资源的使用率,或者说部署密度。大白话说就是相同的资源配置,我们可以稳定的运行更多的应用实例,从企业经营的角度来看,这绝对是划算的方案。由于笔者到现在为止还没有介绍过如何在POD的YAML文件中设置资源请求和资源限制,因此我们会把具体的例子放到对应的章节来介绍,这里只是给大家介绍一下如何在POD中容器部分配置downward api来获取这些信息,如下面的配置片段所示:

env:

  - name: MAX_CPU_CORES

    valueFrom:

      resourceFieldRef:

        resource: limits.cpu

  - name: MAX_MEMORY_KB

    valueFrom:

      resourceFieldRef:

        resource: limits.memory

        divisor: 1k

另外和configMap以及secret类似,pod的元数据也可以文件的形式被挂载到容器的文件系统,假设我们希望将pod的名称信息以文件的形式关在到容器的/pod-metadata/pod-name这个目录,如下图所示的配置就可以让容器可以目录的文件中,读取到pod的名称:

《图1.6 通过文件挂载的方式来将POD元数据暴露给容器实例》

到现在为止,笔者已经陆陆续续的介绍了三种类型的对象来给应用程序提供配置信息:configMaps,secrets以及downward API,除非使用subPath,要不然我们无法将多个数据源的数据挂载到同一个目录,具体原因请参考笔者前边的文章。而使用subPath后也有问题,因为subPath模式下挂载使用的是直接拷贝文件的方式,因此如果我们对configMap对象做了更新,那么这个更新就不会自动刷新到容器实例中的文件上,这显然在大规模部署的集群下,会是个大问题,可能会造成更新丢失。

幸运的是,Kubernetes提供了被称作是projected volume的数据卷类型,我们可以将多个数据源的配置数据投影到同一个数据卷中,然后这个数据卷作为整体,被挂载到容器镜像指定的目录树路径上,从功能上看,projected volume和configMap,secret没有任何区别。如下图展示了project valume的工作原理:

《图1.7 使用project volume从整个多个数据源的配置信息》

最后,我们来实战一下projected volume,把多个数据源的数据投影到相同的数据卷,如下图所示:

《图1.8 将多个数据源信息通过projected vlume挂载到容器实例中》

如上图所示,我们通过使用projected类型的数据卷,来将来自于configMap和secret的信息挂载的envoy容器。好了,今天这篇文章内容就真没多了,接下来,经过多篇文章的铺垫,我们终于可以正式介绍Kubernetes的API对象了,由于整个Kubernetes可以说以POD对象为基石,因此接下来的关于API对象模型的文章,会以POD为核心,敬请期待!

你可能感兴趣的:(云计算时代操作系统Kubernetes之动态配置)