You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Ansible或yq一键生成{{}}变量替换后的YAML文件?

问题描述

我有多个类似如下内容的serverlist_xzy.yml文件:

all:
  children:
    web:
      hosts:
        srv-proxy-01:
          isWeb: true
  vars:
    zf_env: 'preprod'
    zf_zone: 'global'
    project_path:
      api: "proj_api_{{ zf_zone }}_{{ zf_env }}"
      data: "proj_data_{{ zf_zone }}_{{ zf_env }}"
      web: "proj_web_{{ zf_zone }}_{{ zf_env }}"
      flower: "proj_flower_{{ zf_zone }}_{{ zf_env }}"
    root_path:
      api: "/opt/{{ project_path['api'] }}"
      web: "/opt/{{ project_path['web'] }}"
      data: "/opt/{{ project_path['data'] }}"
    lazy_table: "{{ root_path['data'] }}/data_lazy_table"
    logrotate_logpath:
      api: "/var/log/{{ project_path['api'] }}_app"
      web: "/var/log/{{ project_path['web'] }}_app"
      worker: "/var/log/aaa_worker_{{ zf_zone }}_{{ zf_env }}_app"
      flower: "/var/log/{{ project_path['flower'] }}_app"
    htpasswd:
      path:
        api: "/etc/nginx/passwords/{{ project_path['api'] }}.passwdfile"
        web: "/etc/nginx/passwords/{{ project_path['web'] }}.passwdfile"
        flower: "/etc/nginx/passwords/{{ project_path['flower'] }}.passwfile"

需要将文件中所有{{}}形式的变量替换后输出到out.yml,最终效果示例:

$ grep worker out.yml
      worker: "/var/log/aaa_worker_global_preprod_app"

可以用Python实现,但想知道是否能用Ansible或yq一键完成该操作。


解决方案

一、用Ansible实现

Ansible原生支持Jinja2模板渲染,完美匹配需求中的{{}}变量语法,操作步骤如下:

  1. 编写Playbook文件
    创建render_vars.yml文件:
- name: 渲染YAML变量到输出文件
  hosts: localhost
  gather_facts: no
  tasks:
    - name: 读取原YAML文件内容
      slurp:
        src: serverlist_xzy.yml
      register: yaml_raw

    - name: 解析并渲染变量,写入目标文件
      copy:
        content: "{{ yaml_raw.content | b64decode | from_yaml | to_nice_yaml }}"
        dest: out.yml
  1. 执行Playbook
    直接运行命令:
ansible-playbook render_vars.yml

该方法会自动解析文件内的所有Jinja2变量,包括嵌套引用的变量,最终输出格式化后的完整YAML到out.yml。

二、用yq实现

yq支持自定义字符串替换逻辑,需手动处理变量的嵌套关系,步骤如下:

  1. 提取基础变量值
    先从原文件中获取核心变量:
zf_env=$(yq '.all.vars.zf_env' serverlist_xzy.yml | tr -d "'")
zf_zone=$(yq '.all.vars.zf_zone' serverlist_xzy.yml | tr -d "'")
  1. 递归替换所有变量
    使用yq的eval命令完成全量替换:
yq eval '
  .all.vars.project_path.api |= sub("{{ zf_zone }}_{{ zf_env }}"; env(zf_zone) + "_" + env(zf_env)) |
  .all.vars.project_path.data |= sub("{{ zf_zone }}_{{ zf_env }}"; env(zf_zone) + "_" + env(zf_env)) |
  .all.vars.project_path.web |= sub("{{ zf_zone }}_{{ zf_env }}"; env(zf_zone) + "_" + env(zf_env)) |
  .all.vars.project_path.flower |= sub("{{ zf_zone }}_{{ zf_env }}"; env(zf_zone) + "_" + env(zf_env)) |
  .all.vars.root_path.api |= sub("{{ project_path['api'] }}"; .all.vars.project_path.api) |
  .all.vars.root_path.web |= sub("{{ project_path['web'] }}"; .all.vars.project_path.web) |
  .all.vars.root_path.data |= sub("{{ project_path['data'] }}"; .all.vars.project_path.data) |
  .all.vars.lazy_table |= sub("{{ root_path['data'] }}"; .all.vars.root_path.data) |
  .all.vars.logrotate_logpath.api |= sub("{{ project_path['api'] }}"; .all.vars.project_path.api) |
  .all.vars.logrotate_logpath.web |= sub("{{ project_path['web'] }}"; .all.vars.project_path.web) |
  .all.vars.logrotate_logpath.worker |= sub("{{ zf_zone }}_{{ zf_env }}"; env(zf_zone) + "_" + env(zf_env)) |
  .all.vars.logrotate_logpath.flower |= sub("{{ project_path['flower'] }}"; .all.vars.project_path.flower) |
  .all.vars.htpasswd.path.api |= sub("{{ project_path['api'] }}"; .all.vars.project_path.api) |
  .all.vars.htpasswd.path.web |= sub("{{ project_path['web'] }}"; .all.vars.project_path.web) |
  .all.vars.htpasswd.path.flower |= sub("{{ project_path['flower'] }}"; .all.vars.project_path.flower)
' serverlist_xzy.yml > out.yml

该方法适合变量结构固定的场景,若嵌套层次多,Ansible方案会更高效省心。


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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:07:16