You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在保留原有值的前提下增删Kubernetes ConfigMap字段

如何安全更新Kubernetes ConfigMap中的JSON数据(仅增删字段,保留原有值)

你的需求很明确:要更新ConfigMap里的JSON配置,但绝对不能覆盖现有字段的已有值(因为这些值可能被其他Pod/Service修改过),只能添加新字段、删除目标数据中不存在的字段。下面我分享两种可行的实现方案,分别基于Ansible(你提到的部署工具)和kubectl+Python脚本。


方案一:用Ansible实现

Ansible的kubernetes.core.k8s模块可以操作K8s资源,但直接覆盖data会丢失原有数据,所以我们需要先拉取现有ConfigMap,处理JSON后再更新。

完整Playbook示例

- name: 安全更新ConfigMap的JSON数据(仅增删字段)
  hosts: localhost
  gather_facts: no
  vars:
    # 替换成你的ConfigMap信息
    configmap_name: "app-config"
    configmap_namespace: "default"
    # 你的目标JSON(只定义需要保留/新增的字段,不需要的字段会被删除)
    target_json: |
      { 
        "channels": ["10", "20", "30", "100", "10000"], 
        "settings": "on", 
        "metadata": { "name": "test", "action": "delete" }
      }
  tasks:
    - name: 获取现有ConfigMap
      kubernetes.core.k8s_info:
        kind: ConfigMap
        name: "{{ configmap_name }}"
        namespace: "{{ configmap_namespace }}"
      register: existing_cm

    - name: 解析现有JSON配置
      set_fact:
        existing_json: "{{ existing_cm.resources[0].data.config | from_json }}"
      # 假设你的JSON存在data.config键下,若键名不同请修改

    - name: 解析目标JSON
      set_fact:
        target_json_parsed: "{{ target_json | from_json }}"

    - name: 合并JSON(核心逻辑)
      set_fact:
        updated_json: >
          {% set merged = existing_json.copy() %}
          {# 第一步:删除现有JSON中目标没有的字段(比如例子里的expiry) #}
          {% for key in merged.keys() | list %}
            {% if key not in target_json_parsed %}
              {% set _ = merged.pop(key) %}
            {% endif %}
          {% endfor %}
          {# 第二步:添加目标JSON中有但现有没有的字段(如果有的话) #}
          {% for key, value in target_json_parsed.items() %}
            {% if key not in merged %}
              {% set _ = merged.update({key: value}) %}
            {% endif %}
          {% endfor %}
          {{ merged }}

    - name: 将合并后的JSON写回ConfigMap
      kubernetes.core.k8s:
        kind: ConfigMap
        name: "{{ configmap_name }}"
        namespace: "{{ configmap_namespace }}"
        state: present
        definition:
          data:
            config: "{{ updated_json | to_json }}"

逻辑说明

这个Playbook的核心是合并JSON步骤:

  1. 先复制现有JSON的所有内容
  2. 删除现有JSON里目标JSON没有的字段(比如你例子中的expiry
  3. 添加目标JSON里有但现有JSON没有的字段(如果有的话)
  4. 完全保留现有字段的原值,不管目标JSON里对应字段的值是什么

方案二:用kubectl + Python脚本实现

如果你不想用Ansible,也可以用Python脚本结合kubectl来完成,逻辑和上面一致,但更灵活,还支持嵌套字段的处理。

脚本示例

import json
import subprocess
import sys

def get_existing_config(cm_name, namespace):
    """获取现有ConfigMap中的JSON数据"""
    try:
        result = subprocess.run(
            ["kubectl", "get", "configmap", cm_name, "-n", namespace, "-o", "json"],
            capture_output=True,
            text=True,
            check=True
        )
        cm_data = json.loads(result.stdout)
        return json.loads(cm_data["data"]["config"])  # 同样注意键名是否正确
    except subprocess.CalledProcessError as e:
        print(f"获取ConfigMap失败: {e.stderr}")
        sys.exit(1)

def recursive_merge(existing, target):
    """递归合并JSON,支持嵌套字段的增删(保留现有值)"""
    merged = existing.copy()
    
    # 删除现有有但目标没有的字段(支持嵌套)
    for key in list(merged.keys()):
        if key not in target:
            del merged[key]
        elif isinstance(merged[key], dict) and isinstance(target[key], dict):
            # 递归处理嵌套字典
            merged[key] = recursive_merge(merged[key], target[key])
    
    # 添加目标有但现有没有的字段(支持嵌套)
    for key, value in target.items():
        if key not in merged:
            merged[key] = value
    
    return merged

def update_configmap(cm_name, namespace, updated_json):
    """将更新后的JSON写回ConfigMap"""
    updated_json_str = json.dumps(updated_json)
    try:
        subprocess.run(
            ["kubectl", "patch", "configmap", cm_name, "-n", namespace,
             "--type", "merge",
             f'--patch={{\"data\": {{\"config\": "{updated_json_str}"}}}}'],
            check=True
        )
        print("ConfigMap更新成功!")
    except subprocess.CalledProcessError as e:
        print(f"更新ConfigMap失败: {e.stderr}")
        sys.exit(1)

if __name__ == "__main__":
    # 替换为你的实际配置
    CONFIGMAP_NAME = "app-config"
    NAMESPACE = "default"
    TARGET_JSON = {
        "channels": ["10", "20", "30", "100", "10000"],
        "settings": "on",
        "metadata": {"name": "test", "action": "delete"}
    }

    existing_json = get_existing_config(CONFIGMAP_NAME, NAMESPACE)
    merged_json = recursive_merge(existing_json, TARGET_JSON)
    update_configmap(CONFIGMAP_NAME, NAMESPACE, merged_json)

使用说明

  1. 确保kubectl已经配置好集群访问权限
  2. 修改脚本中的CONFIGMAP_NAMENAMESPACETARGET_JSON为你的实际值
  3. 运行脚本:python update_cm_json.py

这个脚本支持嵌套字段的增删,比如如果目标JSON的metadata里新增了子字段,会自动添加;如果现有metadata里有子字段但目标没有,会删除,同时保留现有子字段的值。


注意事项

  • 请确认你的JSON数据在ConfigMap中的键名(比如例子中的data.config),如果键名不同,需要修改对应代码
  • 如果你的JSON有复杂的嵌套结构(比如多层数组+字典),可以根据需求调整递归合并函数的逻辑
  • 操作前建议先备份ConfigMap:kubectl get configmap <name> -n <namespace> -o yaml > backup.yaml

内容的提问来源于stack exchange,提问作者nsteiner

火山引擎 最新活动