ConfigMap 文件与环境变量有不同生命周期
修改 ConfigMap 首先改变的是 API 对象。运行中的应用是否改变行为,还取决于 Kubernetes 如何交付数据,以及应用如何读取它。环境变量注入、普通卷投射、subPath 挂载和已经打开的文件,分别拥有不同生命周期。排查时应找到真正影响业务的消费者,而不是把所有配置传递方式都看成同一种机制。 区分交付与消费 容器环境中的 ConfigMap 引用会在容器启动时解析。更新对象不会重写已有进程的环境,也不会改写同一容器后续 exec 进程所使用的配置环境。替换 Pod 并引用所需版本,可以建立新的环境快照,但这属于生命周期动作,不是修改 data 字段之后自然发生的结果。配置变更记录与进程替换记录应能够对应。 普通 ConfigMap 卷则不同,kubelet 可以在之后把新数据投射进去。延迟受到同步周期和变更发现策略影响,因此 API 修改成功与文件发生变化不是同时发生的事件。投射更新也不会自动调用应用的重新加载函数。只在启动时解析一次配置的程序,即使文件已经变化,也可能一直使用先前读入的值。 打开文件描述引用的是已经打开的文件,而不是每次都重新解析原路径。路径背后的文件被替换,不会迫使旧描述符自动跟随新文件。因此,关闭并重新打开投射路径的进程可能读取新内容,另一个保留的描述符却仍读取旧文件。即使文件系统视图已经刷新,应用自己的缓存还可能再增加一层滞后。 把投射内容复制到可写位置,又会创建一个独立快照。副本不是指向 ConfigMap 的实时链接。如果启动脚本采用这种复制方式,更新这个副本也需要单独实现,不能期待源文件变化自动传播到另一份普通文件。 坏掉的样子 通过 subPath 挂载的 ConfigMap 不会获得普通方式的自动更新。为了方便只挂一个文件,实际上可能改变了配置更新契约。不能因为某个完整目录投射刷新成功,就承诺所有来自 ConfigMap 的文件都会刷新。两个容器对同一个对象表现不一致时,应查看各自真实 volumeMount 定义,而不是只比较 ConfigMap 名称。 监听配置变化需要明确的应用协议。监听器必须处理所用文件系统和库暴露的替换行为;读到新字节之后,验证与真正采用仍然是另外两步。分别读取多个键也可能与版本切换发生竞争。应用应定义怎样加载一致的一组配置、怎样拒绝无效值,以及怎样报告自己目前真正使用的版本,避免把检测到变化直接当成已经生效。 否则,一次成功编辑可能制造分裂视图:API 说 green,重新打开的投射路径也返回 green,进程却继续按 blue 工作。直接重启全部进程也许能暂时掩盖差异,却没有解释原因。应先比较对象、交付路径和应用状态,再选择符合预期契约的重新加载或替换方式,才能让后续配置变更保持可预测。 ...