Ansible template模块是渲染后部署而非简单复制,模板须置于playbook同级templates/目录且以.j2结尾,src仅写文件名;变量需防未定义、Jinja2语法须严谨,validate参数是上线前关键校验。

Ansible 的 template 模块不是“复制文件”,而是“渲染后部署”——变量没传对、路径没放对、Jinja2语法写错,哪怕只少一个 {%,都会导致任务失败或生成错误配置。
模板文件必须放在 templates/ 目录且以 .j2 结尾
Ansible 不会自动扫描任意路径下的模板。它只认当前 playbook 所在目录同级的 templates/ 子目录,且文件名必须带 .j2 后缀(如 nginx.conf.j2)。如果你把模板放在 ./conf/nginx.conf 或 ./templates/nginx.conf,template 模块会直接报错 ERROR! template file not found。
-
src参数只写文件名,不写templates/前缀:正确写法是src: nginx.conf.j2,不是src: templates/nginx.conf.j2 - Playbook 和
templates/必须平级:结构只能是deploy.yml+templates/nginx.conf.j2,不能嵌套在子目录里 - 变量未定义时,Jinja2 默认渲染为空字符串,容易造成语法错误(比如
listen {{ http_port }}渲染成listen ;),建议配合|default过滤器,例如{{ http_port | default(80) }}
template 任务中变量怎么传:优先级和作用域很关键
变量来源有多个层级(inventory、playbook vars、host_vars、命令行 -e),但 template 模块本身不控制变量加载顺序——它只是把当前上下文可见的所有变量一股脑喂给 Jinja2。常见踩坑点:
- 主机级变量(如
host_vars/web01.yml中定义的max_connections: 200)在渲染时可用,但若该主机不在当前 play 的hosts:列表里,就访问不到 - 命令行
-e传参会覆盖所有其他来源的同名变量,适合临时调试:ansible-playbook site.yml -e "db_host=10.0.1.5" - 不要在
template任务里用vars:定义变量——它只对当前 task 生效,而模板渲染发生在整个 play 变量上下文中,此时vars:里的内容不可见 - 推荐做法:把环境相关变量集中写在
group_vars/websrvs.yml,再用ansible_processor_vcpus这类 facts 变量做动态计算(如worker_processes {{ ansible_processor_vcpus | int * 2 }})
Jinja2 控制结构要防空值、防缩进、防漏标签
模板里写 {% if %} 或 {% for %} 很方便,但实际运行时容易因数据结构不一致崩掉。比如循环一个可能为空的列表,或判断一个未定义字段,就会触发 AnsibleUndefinedVariable 错误。
-
{% for item in my_list %}前先加判断:{% if my_list is defined and my_list %}...{% endif %} - 字典字段访问务必加
is defined:错误写法{{ user.home_dir }}→ 正确写法{{ user.home_dir | default('/home/' + user.name) }} - Jinja2 对空白符敏感:
{% for x in list %}{{ x }}{% endfor %}渲染后是连在一起的,加换行要用{%-和-%}去除前后空白:{%- for x in list %}{{ x }}\n{%- endfor %} - 条件嵌套别太深,超过两层就考虑拆成多个模板或预处理变量(比如用
set_fact构造好结构再传入)
validate 参数不是可选项,是上线前最后一道防线
模板生成的配置文件如果语法错误,服务很可能启动失败。光靠人工检查 .j2 文件不现实,validate 能在传输前就验证内容是否合法。
- 对 Nginx 配置,加
validate: '/usr/sbin/nginx -t -c %s',%s 会被替换成临时文件路径 - 对 MySQL,用
validate: 'mysql --defaults-file=%s -e "SELECT 1" >/dev/null 2>&1' - 注意:
validate命令必须在目标主机上能执行,且返回 0 才算通过;否则任务中断并报错validation failed - 开发阶段建议始终启用
validate,哪怕只是简单grep -q 'listen' %s,也比上线后才发现端口没配强
真正难的从来不是写对一个 .j2 模板,而是让同一套模板在 20 台不同角色、不同 OS 版本、不同资源规格的机器上,每次都能渲染出合法、安全、符合预期的配置——这要求你对变量来源足够清醒,对 Jinja2 边界条件足够警惕,对 validate 的执行路径足够熟悉。










