emptyDir + initContainer实现ConfigMap的动态更新(K8s相关)

1. 絮絮叨叨

  • K8s部署服务时,一般都需要使用ConfigMap定义一些配置文件
  • 例如,部署分布式SQL引擎Presto,会在ConfigMap中定义coordinator、worker所需的配置文件
  • node.properties为例,node.environmentnode.data-dir的值将由Helm的values.yaml进行渲染
    data:
      node.properties: |
        # node.id由系统使用uuid自动赋值
        node.environment={{ .Values.environment }}
        node.data-dir={{ .Values.server.data_dir }}
    
  • 工作过程中,笔者接到了一个新的需求:node.id需要与podName保持一致,而非毫无规律的UUID
  • 如果是毫无规律的UUID,将nodeId与pod映射需要一个复杂的过程,笔者的做法一般是:
    1. 通过Presto的worker lists实现nodeId与pod IP的映射在这里插入图片描述
    2. 通过kubectl -n ${namespace} get pod -owide | grep ${IP}实现pod IP与pod的映射,从而最终实现nodeId与pod的映射(图片可能上下文不一致,忽略即可)在这里插入图片描述
  • 所谓的podName其实就是K8s中的metadata.name,也是kubectl -n ${namespace} get pod展示的NAME在这里插入图片描述

2. 一些前期调研

2.1 初始想法

拿到这个需求后,自己的想法很简单,以StatefulSet方式部署的coordinator为例:

  1. 更新node.properties的定义

    data:
      node.properties: |
        node.id=NODE_ID
        node.environment={{ .Values.environment }}
        node.data-dir={{ .Values.server.data_dir }}
    
  2. 定义 POD_NAME env,其值为metadata.name

    env:
      - name: POD_NAME
        valueFrom:
          fieldRef:
            fieldPath: metadata.name
    
  3. 通过container中的command,获取env、使用sed命令更新node.properties中的NODE_ID关键字

    command: [ 'sh', '-c', 'sed -i "s/NODE_ID/$POD_NAME/g" /opt/presto/etc/node.properties' ]
    
  • 存在的问题: 服务部署失败,提示ConfigMap所在卷是read-only的,read-only file system(当时触发这个问题的实现方案可能与描述存在差异,反正类似的方法行不通)

2.2 ConfigMap能否智能地动态更新? —— No

  • 由于当时对Helm values.yaml如何实现ConfigMap的更新机制不了解,笔者期望ConfigMap能智能加载容器的环境变量,自己实现更新
    • 保持上面的env定义不变,将node.properties的定义修改成如下样式
      data:
        node.properties: |
          node.id=$(POD_NAME)
          node.environment={{ .Values.environment }}
          node.data-dir={{ .Values.server.data_dir }}
      
    • 期望ConfigMap像Shell脚本一样,动态加载env
  • 笔者试验后发现,node.properties中node.id=$(POD_NAME)原封不动、未被修改

2.3 学习官方文档 —— 未解

  • 阅读K8s官方文档,发现有关ConfigMap的文档,主要是描述如何定义、使用ConfigMap,并未提及如何动态更新ConfigMap
    • 《ConfigMaps》:如何定义ConfigMap,两种使用方式:
      • ConfigMap映射为文件,一般都是作为etc/config/目录下的配置文件
      • 基于ConfigMap定义环境变量env,ConfigMap中的key-value及时一个环境变量
    • 《Configure a Pod to Use a ConfigMap》中的使用描述更加详细

3. 终极解决方案:emptyDir + initContainer

  • 通过read-only file system这个错误薪资,笔者找到了类似问题的交流帖:
    • Error config Map volume mount read-only file system error
    • k8s 使用 statefulset 如何在 pod 内获取序号并设置到环境变量里
  • 使用emptyDir + initContainer,实现了ConfigMap的动态更新

3.1 具体实现方案

  1. 定义volumes
    volumes:
      # 加载原始的ConfigMap
      - name: config-template-volume
        configMap:
          name: onequery-coordinator
      # 定义一个emtyDir
      - name: config-volume
        emptyDir: {}
    
  2. 创建initContainer,在initContainer中实现nodeId的动态更新
    initContainers:
      - name: config-template
        image: "{{ .Values.Images.onequery }}"
        # 将ConfigMap拷贝到emptyDir映射的路径,并使用sed命令、基于环境变量动态修改NODE_ID为podName
        command: [ 'sh', '-c', 'cp /etc/config-templates/* /opt/onequery/etc && (cat /etc/config-templates/node.properties | sed "s/NODE_ID/$POD_NAME/" > /opt/onequery/etc/node.properties)' ]
        volumeMounts:
          # 定义volumeMounts,分别将ConfigMap、emptyDir映射到container的指定路径
          - name: config-template-volume
            mountPath: /etc/config-templates
          - name: config-volume
            mountPath: /opt/onequery/etc
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
    
  3. coordinator对应的container中,定义volumeMount、与initContainer保持一致(也可以不一致)。启动后的coordinator container,可以访问写入emptyDir的、动态更新后的node.properties文件
    volumeMounts:
      - name: config-volume
        mountPath: /opt/onequery/etc
    

4. 后记

4.1 关于emptyDir卷

  • K8s官方文档对emptyDir卷的描述可知:emptyDir的生命周期与pod一致,特别适合在pod的不同容器中共享文件
  • 上面的实现方案中,即使initContainer、coordinator container中emptyDir卷的挂载路径不同,也可以共同读写emptyDir中的文件

4.2 volumes vs volumeMounts

  • volumes(存储卷):是K8s中的一种资源,用于将持久化存储与Pod绑定,与Pod具有相同的生命周期
  • volumeMounts(挂载点):
    • 在容器描述符中定义volumeMount,可以将 volume 挂载到容器中的指定路径
    • 在容器中读写上述路径下的文件,实际就是读写持久化存储中相应路径下的文件
  • 举个例子,阐述二者之间的关系:
    • volumes定义如下,将log-path与宿主机的/data00/basic_log/svc_logs/presto目录绑定
      volumes:
       - name: log-path
         hostPath:
           path: /data00/basic_log/svc_logs/presto/log
           type: DirectoryOrCreate # 支持动态创建目录
      
    • 在container中定义volumeMount,使得容器中的/opt/data/var/log路径对应
      volumeMounts:
        - name: log-path # volume name
          mountPath: /opt/data/var/log
          # 将基于环境变量POD_NAME、在宿主机磁盘上动态创建子目录,最终coordinator-0在宿主机上的路径为/data00/basic_log/svc_logs/presto/log/coordinator/coordinator-0
          subPathExpr: coordinator/$(POD_NAME) 
      
    • coordinator运行起来后,会在/opt/data/var/log下生成launcher.log。相应地,其所在宿主机的/data00/basic_log/svc_logs/presto/log/coordinator/coordinator-0目录下将出现launcher.log文件
    • 在容器中对launcher.log的读写操作,实际就是在读写宿主机中对应目录的launcher.log

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/759882.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Transformer丨基础Transformer模型和代码详解

笔者在深度学习入门期间自学过Transformer,但是那时碍于急于求成,并未对其进行深度归纳与分享。 近期,笔者观察到不论是自然语言处理模型还是视觉模型,已经几乎从传统的CNN、RNN的网络结构设计全面转向基于Transformer的结构设计…

002-基于Sklearn的机器学习入门:回归分析(上)

本节及后续章节将介绍机器学习中的几种经典回归算法,所选方法都在Sklearn库中聚类模块有具体实现。本节为上篇,将介绍基础的线性回归方法,包括线性回归、逻辑回归、多项式回归和岭回归等。 2.1 回归分析概述 回归(Regression&…

Vue3学习(一)

创建组件实例:我们传入 createApp 的对象实际上是一个组件 import { createApp } from vue // 从一个单文件组件中导入根组件 import App from ./App.vueconst app createApp(App) 大多数真实的应用都是由一棵嵌套的、可重用的组件树组成的。 App (root compone…

AI大模型的崛起:第四次工业革命的前奏?

在当今这个信息爆炸的时代,人工智能(AI)大模型的崛起引起了广泛的关注和讨论。有人将其视为第四次工业革命的前奏,然而,这真的可能吗?本文将探讨这一问题,并对中国AI大模型的发展进行简要分析。…

Android:移动垃圾软件

讲解政策相关,最近升级AI扫荡系统和证书防高风险,回复按留言时间来排,请耐心等待 移动垃圾软件 官方政策公告行为透明、信息披露清晰保护用户数据不要损害移动体验软件准则反垃圾软件政策Google API 服务用户数据政策官方政策公告 ​ 在 Google,我们相信,如果我们关注用户…

DIY智能音箱:基于STM32的低成本解决方案 (附详细教程)

摘要: 本文详细介绍了基于STM32的智能音箱的设计与实现过程,包括硬件设计、软件架构、语音识别、音乐播放等关键技术。通过图文并茂的方式,结合Mermaid流程图和代码示例,帮助读者深入理解智能音箱的工作原理,并提供实际操作指导。…

[图解]分析模式高阶+课程讲解03物品模式

1 00:00:00,280 --> 00:00:03,440 下一个要探讨的模式是物品模式 2 00:00:04,310 --> 00:00:08,300 说是物品模式,实际上更多的说物品规格 3 00:00:09,210 --> 00:00:12,560 首先,我们要区分一下物品和物品规格的定义 4 00:00:14,440 -->…

【C++】C++ 网店销售库存管理系统(源码+论文)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

抖音直播自动点赞脚本:让点赞变得简单

抖音直播自动点赞脚本:让点赞变得简单 简介 点赞是社交媒体上表达喜爱的一种方式,尤其在抖音这样的平台上,点赞不仅能够增加主播的人气,还能鼓励他们创作更多优质内容。然而,手动点赞往往既耗时又费力。为了解决这个…

算法与数据结构面试宝典——常见的数据结构都有哪些?详细示例(C#,C++)

文章目录 一、逻辑结构:线性与非线性线性数据结构非线性数据结构访问方式 二、数组(Array)三、链表(LinkedList)四、栈(Stack)五、队列(Queue)六、树(Tree&am…

Android高级面试_6_性能优化

Android 高级面试-7:网络相关的三方库和网络协议等 1、网络框架 问题:HttpUrlConnection, HttpClient, Volley 和 OkHttp 的区别? HttpUrlConnection 的基本使用方式如下: URL url new URL("http://www.baidu.com")…

pytest测试框架pytest-random-order插件随机执行用例顺序

Pytest提供了丰富的插件来扩展其功能,本章介绍下pytest-random-order插件,随机设置pytest测试用例的运行顺序,并对随机性进行一些控制。 官方文档: https://pytest-cov.readthedocs.io/en/latest/index.html 适配版本说明&#x…

AI智能客服项目拆解(1) 产品大纲

本文作为拆解AI智能客服项目的首篇,以介绍产品大纲为主。后续以某AI智能客服产品为例,拆解相关技术细节。 AI智能客服是一种基于人工智能技术的客户服务解决方案,旨在提高客户满意度和优化企业运营。利用人工智能和自然语言处理技术&#xff…

如何为数据库中的位图添加动态水印

许多数据库存储了以blob或文件形式保存的位图,其中包括照片、文档扫描、医学图像等。当这些位图被各种数据库客户端和应用程序检索时,为了日后的识别和追踪,有时需要在检索时为它们添加唯一的水印。在某些情况下,人们甚至希望这些…

数字图像处理之【高斯金字塔】与【拉普拉斯金字塔】

数字图像处理之【高斯金字塔】与【拉普拉斯金字塔】 1.1 什么是高斯金字塔? 高斯金字塔(Gaussian Pyramid)是一种多分辨率图像表示方法,用于图像处理和计算机视觉领域。它通过对原始图像进行一系列的高斯平滑和下采样操作&#x…

istitle()方法——判断首字母是否大写其他字母小写

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 istitle()方法用于判断字符串中所有的单词首字母是否为大写而其他字母为小写。istitle()方法的语法格式如下: str.istitle() …

Java并发编程基础知识点

目录 Java并发编程基础知识点1、线程,进程概念及二者的关系进程相关概念线程相关概念进程与线程的关系补充小知识点: 2、线程的状态Java线程的状态:Java线程不同状态之间的切换图示 3、Java程序中如何创建线程?①、继承Thread类②…

【python】python知名品牌调查问卷数据分析可视化(源码+调查数据表)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

某度,网盘免费加速,复活!

哈喽,各位小伙伴们好,我是给大家带来各类黑科技与前沿资讯的小武。 有小伙伴反馈之前如下夸克网盘脚本的加速方法失效,小武今天测试,依旧正常使用! 百度/迅雷/夸克,网盘免费加速,已破&#xf…

Vite: 高阶特性 Pure ESM

概述 ESM 已经逐步得到各大浏览器厂商以及 Node.js 的原生支持,正在成为主流前端模块化方案。 而 Vite 本身就是借助浏览器原生的 ESM 解析能力( type“module” )实现了开发阶段的 no-bundle ,即不用打包也可以构建 Web 应用。不过我们对于原生 ESM 的…