Kubernetes为常规数据和机密数据提供了原生配置资源,这使得配置生命周期与应用生命周期解耦。配置资源模式解释了ConfigMap和Secret资源的概念,以及我们如何使用它们,以及它们的限制。
存在问题
EnvVar配置模式的一个显著缺点是它只适合于少数变量和简单的配置。另一个是由于环境变量可以在不同的地方定义,所以往往很难找到一个变量的定义。而且即使找到了,你也不能完全确定它没有在其他位置被覆盖。例如,在Docker镜像中定义的环境变量可以在运行时替换Kubernetes部署资源中的环境变量。
通常情况下,最好将所有的配置数据保存在一个地方,而不是分散在各种资源定义文件中。但是把整个配置文件的内容放到一个环境变量中是没有意义的。所以,一些额外的间接性将允许更多的灵活性,这正是Kubernetes配置资源所提供的。
解决方案
Kubernetes提供了专门的配置资源,比纯环境变量更灵活。这两个对象分别是ConfigMap和Secret对象,分别用于通用数据和敏感数据。
我们可以以同样的方式使用这两者,因为两者都提供了键值对的存储和管理。当我们在描述ConfigMaps时,同样的情况也可以应用于Secrets。除了实际的数据编码(对Secrets来说是Base64),ConfigMaps和Secrets的使用在技术上没有区别。
一旦创建并保存数据的ConfigMap,我们就可以通过两种方式使用ConfigMap的密钥:
-
作为环境变量的引用,其中键是环境变量的名称。 -
作为映射到Pod中安装的卷的文件。键作为文件名。
当通过Kubernetes API更新ConfigMap时,挂载的ConfigMap卷中的文件会被更新。因此,如果一个应用程序支持配置文件的热重载,它可以立即从这样的更新中受益。但是,如果将ConfigMap条目作为环境变量使用,更新就不会被反映出来,因为环境变量在进程启动后无法更改。
除了ConfigMap和Secret之外,另一种选择是直接将配置存储在外部卷中,然后挂载。
下面的例子集中在ConfigMap的使用上,但它们也可以用于Secrets。但有一个很大的区别:Secrets的值必须是Base64编码的。
ConfigMap资源在其数据部分包含键值对,如例1-1所示。
apiVersion: v1
kind: ConfigMap
metadata:
name: random-generator-config
data:
PATTERN: Configuration Resource #1
application.properties: |
# Random Generator config
log.file=/tmp/generator.log
server.port=7070
EXTRA_OPTIONS:"high-secure,native"
SEED:"432576345"
#1 ConfigMaps可以作为环境变量和挂载文件访问,我们建议在ConfigMaps中使用大写键表示环境变量的用法,作为挂载文件使用时使用正确的文件名。
我们在这里看到,ConfigMap也可以携带完整的配置文件的内容,比如本例中的Spring Boot application.properties。您可以想象,对于一个非平凡的用例,这一部分可能会变得相当大。
我们不需要手动创建完整的资源描述符,也可以使用kubectl来创建ConfigMaps或Secrets。对于前面的例子,等效的 kubectl 命令就像例 1-2 中的那样。
1-2. 通过文件创建ConfigMap
kubectl create cm spring-boot-config
--from-literal=JAVA_OPTIONS=-Djava.security.egd=file:/dev/urandom
--from-file=application.properties
然后,这个ConfigMap可以在不同的地方被读取–凡是定义了环境变量的地方,如例1-3所示。
1-3,环境变量定义ConfigMap
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- env:
- name: PATTERN
valueFrom:
configMapKeyRef:
name: random-generator-config
key: PATTERN
....
如果一个ConfigMap有许多条目要作为环境变量使用,使用某种语法可以节省大量的输入。envFrom:allows公开所有ConfigMap条目,而不是像前面例子中的env: section那样单独指定每个条目,它的键也可以用作有效的环境变量。我们可以在前面加上一个前缀,如例1-4所示。
1-4,从ConfigMap设置环境变量
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
envFrom: #1
- configMapRef:
name: random-generator-config
prefix: CONFIG_ #2
#1 从ConfigMap random-generator-config中拾取所有可用作环境变量名的键。
#2 将所有合适的ConfigMap键前缀为CONFIG_。对于例1-1中定义的ConfigMap,这就导致了三个暴露的环境变量:CONFIG_PATTERNAME、CONFIG_EXTRA_OPTIONS和CONFIG_SEED。
与ConfigMaps一样,Secret也可以作为环境变量使用,可以是每个条目,也可以是所有条目。要访问Secret而不是ConfigMap,请用secretKeyRef替换configMapKeyRef。
当作为卷使用时,完整的ConfigMap被投射到该卷中,键作为文件名使用。见例1-5。
1.5, 挂载ConfigMap作为卷
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
volumeMounts:
- name: config-volume
mountPath: /config
volumes:
- name: config-volume
configMap:
name: random-generator-config #1
#1 ConfigMap支持的卷将包含尽可能多的文件和条目,map的键为文件名,map的值为文件内容。
例1-1中的配置被挂载为一个卷,结果在/config文件夹中有两个文件。一个包含ConfigMap中定义的内容的application.properties,和一个只有一行内容的PATTERN文件。
配置数据的映射可以通过在卷声明中添加额外的属性进行更精细的调整。您可以不将所有条目映射为文件,也可以单独选择应该暴露的每一个键,以及应该在其下提供的文件名。更多详情请参考ConfigMap文档。
Secrets有多安全?
Secrets 持有Base64编码的数据,并在将其作为环境变量或挂载卷传递给Pod之前对其进行解码。这经常被混淆为一种安全功能。Base64 编码不是一种加密方法,从安全角度来看,它被认为与纯文本相同。Secrets 中的 Base64 编码允许存储二进制数据,那么为什么 Secrets 被认为比 ConfigMaps 更安全呢?Secrets还有一些其他的实现细节使其安全。在这方面正在不断改进,但目前主要的实现细节如下。
-
一个Secret 只被分发到运行需要访问该Secret 的Pod的节点上。 -
在节点上,Secret 被存储在tmpfs的内存中,从不写入物理存储中,当Pod被移除时,Secret 被移除。 -
在Etcd中,Secret 是以加密的形式存储的。
不管这些,仍然有办法以根用户的身份访问Secrets ,甚至通过创建一个Pod和挂载一个Secrets 。您可以将基于角色的访问控制(RBAC)应用于Secrets (就像您可以对ConfigMaps或其他资源做的那样),并且只允许具有预定义服务帐户的特定Pods读取它们。但有能力在命名空间中创建Pod的用户仍然可以通过创建Pod来升级他们在该命名空间中的权限。他们可以在权限更大的服务帐户下运行Pods,并仍然可以读取Secrets 。在命名空间中具有 Pod 创建权限的用户或控制器可以冒充任何服务帐户,并访问该命名空间中的所有 Secrets 和 ConfigMaps。因此,敏感信息的额外加密往往也是在应用层进行的。
另一种借助Kubernetes存储配置的方式是使用gitRepo卷。这种卷在Pod上挂载一个空目录,然后克隆一个Git仓库到其中。在Git上保留配置的好处是,你可以免费获得版本管理和审计。但是gitRepo卷需要从外部访问Git仓库,而Git仓库不是Kubernetes资源,可能位于集群之外,需要单独监控和管理。克隆和挂载发生在Pod的启动过程中,本地克隆的repo不会随着变化自动更新。这个卷的工作原理类似于《不可变配置》一章中介绍的方法,使用Init Containers将配置复制到共享的本地卷中。
事实上,gitRepo类型的卷现在已经被淘汰了,取而代之的是基于Init Container的解决方案,因为这种方法更普遍适用,并且支持其他数据源,而不仅仅是Git。所以今后,你可以使用同样的方法从外部系统中检索配置数据并将其存储到卷中,但不使用预定义的gitRepo卷,而是使用更灵活的Init Container方法.我们在 “Kubernetes Init Containers “中详细解释了这种技术。
讨论
ConfigMaps和Secrets允许将配置信息存储在专用资源对象中,便于使用Kubernetes API进行管理。使用ConfigMaps和Secrets最显著的优势是,它们将配置数据的定义和使用解耦。这种解耦使得我们可以通过使用配置独立于配置来管理对象。
ConfigMaps和Secrets的另一个好处是,它们是平台的固有特性。不需要像《不可改变的配置》一章中那样的自定义构造。
但是,这些配置资源也有其限制:Secrets的大小limt为1 MB,它们不能存储任意大的数据,也不太适合非配置应用数据。你也可以在Secrets中存储二进制数据,但由于它们必须是Base64编码,所以你只能用700 kb左右的数据来存储。
现实世界的Kubernetes集群也会对每个命名空间或项目可以使用的ConfigMaps数量进行单独配额,所以ConfigMap并不是金锤子。
接下来的两章将介绍如何通过使用Immutable Configuration和Configuration Template来处理大量的配置数据。
原文始发于微信公众号(云原生内经):Kubernetes 设计模式之配置资源
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/167965.html