ansible template模块先在控制机用jinja2渲染模板再推送,需确保src位于templates/目录且后缀为.j2、dest为完整路径、变量防未定义、validate校验+backup备份、空白敏感处理。

Ansible 的 template 模块不是“把文件拷过去就完事”,而是先在控制机上用 Jinja2 引擎把变量、逻辑全算清楚,再生成最终内容推到目标主机——这意味着你改一个模板,就能让 100 台机器各得其所,但前提是变量有值、路径对、语法不崩。
template 模块调用必须写对 src 和 dest
src 不是任意路径,它只认 playbook 当前目录下的 templates/ 子目录,且后缀必须是 .j2;dest 是远程目标路径,要写全(比如 /etc/netplan/01-network.yaml)。
-
src: netplan.j2✅ 正确:模板在templates/netplan.j2 -
src: ./templates/netplan.j2❌ 错误:template模块自动拼templates/前缀,加了反而找不到 -
src: netplan.yaml❌ 错误:后缀不是.j2,Ansible 不识别为模板 -
dest: /etc/netplan❌ 危险:没写文件名,可能覆盖整个目录或报错
Jinja2 变量和条件必须防空、防未定义
直接写 {{ hostvars[inventory_hostname].ip }} 很容易在某台主机没定义 ip 时导致任务失败。Jinja2 不会自动跳过,它会抛 undefined error。
- 用
| default('192.168.1.100')提供兜底值:{{ network_config.ip | default('10.0.0.1') }} - 判空再循环:
{% if hostvars[inventory_hostname].routes %}{% for r in routes %}...{% endfor %}{% endif %} - 查 facts 要带层级防护:
{{ ansible_facts['default_ipv4']['address'] | default('127.0.0.1') }},避免default_ipv4本身为空
网络类配置必须加 validate + backup
渲染出错的 /etc/netplan/ 或 /etc/network/interfaces 可能导致节点失联,不能只靠 “看起来像对的” 就上线。
- 用
validate调系统校验工具:validate: '/usr/sbin/netplan generate --root /tmp/test 2>&1 | grep -q "No issues found"' - 强制开启
backup: yes,Ansible 会在覆盖前把原文件存成/etc/netplan/01-network.yaml.2026-09-29@15:41:22~这种格式 -
force: no可选:如果内容没变,就不触发覆盖,减少无谓变更
模板里别混用空格和换行逻辑
Jinja2 对空白敏感,尤其在 YAML 或 INI 类配置中,多一个空格、少一个换行都可能让语法失效。
-
{{ ansible_hostname }}推荐紧凑写法,避免{{ ansible_hostname }}中间有空格(某些过滤器链如| upper | trim会异常) - 用
{%- if ... -%}和{%- endif -%}去除前后空白,防止生成多余空行破坏 YAML 缩进 - 注释用
{# this won't appear #},别用<!-- HTML style -->,后者会被当字面量输出
真正难的不是写个 {{ ip }},而是想清楚:这台机器有没有这个 fact?这个变量在所有目标组里是否一致?校验命令在不同 OS 上路径是否兼容?这些细节不卡在测试环境,就卡在线上重启后连不上 SSH 的那一刻。











