内容简介:【编者的话】之前的文章《这次碰到的问题,并不是上面的办法无法实现配置热更新,而是无法实现配置滚动发布。我们不妨看一个常见的例子,一个 Deployment 引用了一个 ConfigMap(简洁起见,删去了 selector 和 labels 等字段):这里我们采用了通过修改对象中的 PodTemplate 触发滚动更新这个方案来做 ConfigMap 的更新:
【编者的话】之前的文章《 Kubernetes Pod 中的 ConfigMap 更新 》中,我总结了三种 ConfigMap 或 Secret 的更新方法:通过 Kubelet 的周期性 Remount 做热更新,通过修改对象中的 PodTemplate 触发滚动更新,以及通过自定义 Controller 监听 ConfigMap 触发更新。但在最近的业务实践中,却碰到了这些办法都不好使的情况。这篇文章就将更为深入地讨论这个主题。 如果你想和更多Kubernetes技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态 。
问题在哪?
这次碰到的问题,并不是上面的办法无法实现配置热更新,而是无法实现配置滚动发布。我们不妨看一个常见的例子,一个 Deployment 引用了一个 ConfigMap(简洁起见,删去了 selector 和 labels 等字段):
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 template: annotations: nginx-config-md5: d41d8cd98f00b204e9800998ecf8427e spec: containers: - name: nginx image: nginx volumeMounts: - name: nginx-config mountPath: /etc/config volumes: - name: config-volume configMap: name: nginx-config --- apiVersion: v1 kind: ConfigMap metadata: name: nginx-config data: nginx.conf: |- ## some configurations...
这里我们采用了通过修改对象中的 PodTemplate 触发滚动更新这个方案来做 ConfigMap 的更新:
- 每次部署时,计算 ConfigMap 的摘要(e.g. MD5),并填入 PodTemplate 的 Annotation 中;
- 假如 ConfigMap 发生变化,则摘要也会变化[^1],此会触发一次 Deployment 的滚动更新。
现在,我们更新了一次配置,但很不幸新的配置是错误的,使用错误配置的 Pod 将无法正常工作(比如无法通过 readinessProbe 的检查)。最终,滚定更新的过程会卡住,错误的配置并不会让你的 Deployment 整个宕掉。
真的是这样吗?
并不是!
问题在这里就显现出来了,nginx-config 已经更新成了错误的值,尽管尚未重建的 Pod 目前暂且健康,但是,一旦这些 Pod 宕掉发生 Pod 重建,或者 Pod 中的容器重新读取了一次配置,这些 Pod 就会进入异常状态:整个集群现在是摇摇欲坠的。
问题的根源是,在原地更新 ConfigMap 或 Secret 时,我们没有做滚动发布,而是一次性将新配置更新到了整个集群的所有实例中,我们所谓的“滚动更新”其实是在控制各个实例何时读取新配置,但由于 Pod 随时可能挂掉重建,我们是无法做到准确控制这个过程的。
假如你认为“错误的配置”很少见,那一个更有力的例子是 StatefulSet 的灰度发布(使用 StatefulSet 的 Partition 字段控制只把部分副本更新到新的 ControllerRevision),假如我们 StatefulSet 的配置也做灰度发布,那配置更新的问题就更明显了。
显然,同样的问题对于另两种更新方案也存在。当然,这并不是说这三种方式是错误的,它们也有自己适用的场景,只是当我们需要配置文件的更新滚动发布时,它们就不再适用了。
解决方案
上述方案的问题在于原地更新,要解决这个问题,我们只需要在每次 ConfigMap 变化时,重新生成一个 ConfigMap,再更新 Deployment 使用这个新的 ConfigMap 即可。而重新生成 ConfigMap 最简单的方式就是在 ConfigMap 的命名中加上 ConfigMap 的 data 值计算出的摘要,比如:
apiVersion: v1 kind: ConfigMap metadata: name: nginx-config-d41d8cd98f00b204e9800998ecf8427e data: nginx.conf: |- ## some configurations...
事实上,ConfigMap 滚动更新(ConfigMap Rollout)是社区中历时最久而尚未解决的问题之一(#22368),到目前为止,解决这个问题的方向也正是“每次更新新建一个 ConfigMap”这种“Immutable ConfigMap”模式( 详见这条评论 )。
这个方案自然就带来两个问题:
- 如何做到每次配置文件更新时,都创建一个新的 ConfigMap?目前社区的态度是把这一步放到 Client 来解决,比如 Kustomize 和 Helm。
- 历史 ConfigMap 会不断积累,怎么回收?针对这点,社区希望在服务端实现一个 GC 机制来清理没有任何资源引用的 ConfigMap。
当然,把逻辑放到 Client 里势必造成重复造轮子的问题:每一个 工具 都必须实现一遍类似的逻辑。因此也有人提议通过 Snapshot 的方式把逻辑全都推到服务端,这个方向目前八字都还没一撇,我们且按下不表。至少到现在为止,在 Client 做 ConfigMap 的新建与 Deployment 等对象的更新是最成熟的 ConfigMap 滚动更新方案。
因此,我们就在最后一节来说明 Helm 和 Kustomize 里怎么实现这个方案。
Helm 和 Kustomize 的实践方式
Kustomize
Kustomize 对这个方案有内置的支持,只需要使用 configGenerator 即可:
configMapGenerator: - name: my-configmap files: - common.properties
这段 yaml 在 Kustomize 中就会生成一个 ConfigMap 对象,这个对象的 data 来自于 common.properties 文件,并且 name 中会加上该文件的 SHA 值作为后缀。
在 Kustomize 的其它 layer 中,只要以 my-configmap 作为 name 引用这个 ConfigMap 即可,当最终渲染时,Kustomize 会自动进行替换操作。
Helm
首先注意,Helm 在 tips and tricks 里提到的修改 Annotation 的方案是无法做到滚动更新的,原因见第一节,假如你想要的是合理的滚动更新的话,注意不要踩到坑里去。
Helm 对于这个方案没有比较好的支持,需要依托于 named template 机制来封装一下。思路是定义一个 named template,用于渲染 ConfigMap 的 data,然后针对这个 named template 计算 SHA 值并添加到 ConfigMap 名字中。
{{/* 定义一个 Named Template,将配置文件渲染为 ConfigMap */}} {{- define "my-configmap.data" -}} config.toml: |- {{ include (print $.Template.BasePath "/_config.toml.tpl") . | indent 2 }} another-config.yaml: |- {{ include (print $.Template.BasePath "/_another-config.yaml.tpl") . | indent 2 }} {{- end -}} {{/* ConfigMap 部分 */}} apiVersion: v1 kind: ConfigMap metadata: name: my-configmap-{{ include "my-configmap.data" . | sha256sum | trunc 8 }} data: {{ include "my-configmap.data" . | indent 2 }} --- {{/* Deployment 部分 */}} apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 template: spec: volumes: - name: my-config configMap: name: my-configmap-{{ include "my-configmap.data" . | sha256sum | trunc 8 }} ...(其它字段略)
关键点只有一个,那就是把 ConfigMap 的 data 定义成 Named Template,这样就可以很容易地访问这个模板的渲染值并且计算 SHA。
当然上面只是个示例,正式写 chart 时,还要做好合理的文件切分,比如把 Named Template 放到 _helpers.tpl 文件中统一维护。
当资源名字改变后,Helm 会自动删除旧的资源,因此使用 Helm 时不必担心 ConfigMap 累计过多的问题。缺点就是我们无法脱离 Helm 去做 rollback。
结语
事实上这种从 Client 端出发的解决方案并不是很优雅,或多或少都有比较 Hack 的感觉。尽管客观情况是 ConfigMap 和 Secret 现在的用法已经完全深入到所有的 Kubernetes 使用场景中,对于如此基础的资源,很难大刀阔斧地去做改进,甚至于小修小补都是“牵一发而动全身”,需要非常慎重地去考虑。但社区的创造力是无穷的,最近又有相关的 KEP 涌现出来(尽管还很粗糙),相信在不远的将来,我们会看到更好用的 ConfigMap Rollout 管理机制。
以上所述就是小编给大家介绍的《Kubernetes 中的 ConfigMap 配置更新(续)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Igniton 配置手工更新
- 更新配置自动化工具
- DuiC 配置中心 1.7.0 发布,支持配置实时更新
- Kubernetes Pod 中的 ConfigMap 配置更新
- YARN NodeManager 动态更新资源配置参数
- 配置中心 duic-java-client 1.3.0 发布,配置实时更新
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
黑客攻防技术宝典(第2版)
[英] Dafydd Stuttard、[英] Marcus Pinto / 石华耀、傅志红 / 人民邮电出版社 / 2012-6-26 / 99.00元
内容简介: Web应用无处不在,安全隐患如影随形。承载着丰富功能与用途的Web应用程序中布满了各种漏洞,攻击者能够利用这些漏洞盗取用户资料,实施诈骗,破坏其他系统等。近年来,一些公司的网络系统频频遭受攻击,导致用户信息泄露,造成不良影响。因此,如何确保Web应用程序的安全,已成为摆在人们眼前亟待解决的问题。 本书是Web安全领域专家的经验结晶,系统阐述了如何针对Web应用程序展开攻击与......一起来看看 《黑客攻防技术宝典(第2版)》 这本书的介绍吧!