基于条件使用Bash脚本在YAML文件中编辑插入Targets节点(含删除功能需求)
如何编写Bash脚本在Prometheus配置YAML中按
type和group管理targets? 我有一份Prometheus的scrape配置YAML文件,内容如下:
scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] - job_name: 'node-exporter' relabel_configs: - source_labels: [__address__] target_label: instance regex: '([^:]+)(:[0-9]+)?' replacement: '${1}' static_configs: - labels: type: 'YYY' group: 'Bar' targets: - '192.168.1.134:80' - '192.168.1.146:80' - labels: type: 'YYY' group: 'Foo' targets: - '192.168.2.136:80' - labels: type: 'ZZZ' group: 'Foo' targets: - '192.168.2.100:80'
我想要写一个Bash脚本,能根据type和group这两个标签字段,给对应的targets列表添加或删除条目。比如执行./manage_targets.sh add 192.168.1.17:80 YYY Bar就能把这个目标添加到type=YYY且group=Bar的targets里;如果执行./manage_targets.sh remove 192.168.1.146:80 YYY Bar就会把这个目标从对应组里删掉。
我之前试过用jq和sed来处理,但都没成功:
jq本身是处理JSON的,虽然能转YAML,但处理嵌套结构的匹配和修改很麻烦;sed是基于文本匹配的,没法准确识别YAML的块结构,很容易把内容插错地方。
推荐使用yq工具处理YAML
yq是专门用于YAML文件处理的命令行工具(类似jq但针对YAML),它能轻松解析和修改YAML的嵌套结构,完美解决你的需求。首先确保你已经安装了yq(v4版本,不同版本语法差异大,这里用v4)。
下面是实现的脚本manage_targets.sh,支持添加和删除两种操作:
#!/bin/bash # 检查参数数量 if [ $# -lt 4 ]; then echo "用法: $0 <add|remove> <target> <type> <group>" echo "示例: $0 add 192.168.1.17:80 YYY Bar" echo "示例: $0 remove 192.168.1.146:80 YYY Bar" exit 1 fi ACTION=$1 TARGET=$2 TYPE=$3 GROUP=$4 YAML_FILE="prometheus.yml" # 替换成你的配置文件路径 # 检查yq是否安装 if ! command -v yq &> /dev/null; then echo "错误: 请先安装yq工具(v4版本)" exit 1 fi case $ACTION in add) # 检查目标是否已存在,避免重复添加 if yq e ".scrape_configs[] | select(.job_name == \"node-exporter\") | .static_configs[] | select(.labels.type == \"$TYPE\" and .labels.group == \"$GROUP\") | .targets[]" "$YAML_FILE" | grep -q "$TARGET"; then echo "目标 $TARGET 已经存在于 type=$TYPE group=$GROUP 中,无需重复添加" exit 0 fi # 添加目标到对应组的targets列表 yq e ".scrape_configs[] |= (select(.job_name == \"node-exporter\") | .static_configs[] |= (select(.labels.type == \"$TYPE\" and .labels.group == \"$GROUP\") | .targets += [\"$TARGET\"]))" -i "$YAML_FILE" echo "成功添加目标 $TARGET 到 type=$TYPE group=$GROUP" ;; remove) # 检查目标是否存在 if ! yq e ".scrape_configs[] | select(.job_name == \"node-exporter\") | .static_configs[] | select(.labels.type == \"$TYPE\" and .labels.group == \"$GROUP\") | .targets[]" "$YAML_FILE" | grep -q "$TARGET"; then echo "目标 $TARGET 不存在于 type=$TYPE group=$GROUP 中,无需删除" exit 0 fi # 从对应组的targets列表中删除目标 yq e ".scrape_configs[] |= (select(.job_name == \"node-exporter\") | .static_configs[] |= (select(.labels.type == \"$TYPE\" and .labels.group == \"$GROUP\") | .targets |= (del(.[] | select(. == \"$TARGET\")))))" -i "$YAML_FILE" echo "成功删除目标 $TARGET 从 type=$TYPE group=$GROUP" ;; *) echo "无效的操作,请使用 add 或 remove" exit 1 ;; esac
脚本说明
- 参数校验:先检查输入参数是否符合要求,给出清晰的用法提示;
- 依赖检查:确认
yq已安装,避免脚本运行失败; - 添加逻辑:
- 先检查目标是否已经存在,防止重复添加;
- 使用
yq精准定位到job_name=node-exporter的scrape配置,再匹配type和group对应的static_configs块,最后把目标追加到targets列表;
- 删除逻辑:
- 先检查目标是否存在,避免无意义的报错;
- 同样定位到对应块,删除
targets中匹配的条目;
- 原地修改:使用
-i参数让yq直接修改原文件,不需要额外处理临时文件。
使用方法
- 给脚本添加执行权限:
chmod +x manage_targets.sh - 添加目标:
./manage_targets.sh add 192.168.1.17:80 YYY Bar - 删除目标:
./manage_targets.sh remove 192.168.1.146:80 YYY Bar
为什么不用jq或sed?
jq:虽然可以通过转换格式处理YAML,但来回转换容易丢失YAML的注释和原有格式,而且嵌套结构的匹配修改语法非常繁琐;sed:YAML的缩进和块结构是语义化的,sed的文本匹配无法理解这些结构,很容易把内容插入到错误的缩进位置,或者破坏原有配置格式。
内容的提问来源于stack exchange,提问作者Maxim_united
相关产品推荐
相关产品推荐

