LabHub
学习 学习路径 课程

Ansible 实战

Jinja2 — 从数据到配置文件

在 LabHub 中继续学习

一句话总结

template 把“各环境不同的配置文件”拆分为一个框架 + 各环境数据

概念图: 一个框架 + 各环境数据 · 过滤器 · 空白 · 从自动部署配置文件的那一刻起,就打开了错误配置杀死服务的路径。

为什么需要它

为 dev、stage、prod 分别维护 nginx 配置,三个文件很快会出现差异。每增加一台后端,就要修改三处;漏掉一处,该环境就会发生流量倾斜。template 把服务器清单变成数据,框架只编写一次。增加后端时,只需增加一行数据。

如何工作

Jinja2 常用语法只有三种。

在此基础上可以使用过滤器。例如 {{ name | upper }}{{ timeout | default(30) }}{{ data | to_nice_json }},以管道连接。default 尤其重要:它为可能未定义的值提供安全替代,避免变量缺失时输出 <no value> 或报错。

最常出问题的是空白{% for %} 等控制语句本身占据一行,渲染结果会留下空行;生成 YAML 配置时,空行甚至可能破坏文件。有两种解决方法:在语句中使用 {%- / -%} 删除前后空白,或在 template 模块中启用 trim_blocks/lstrip_blocks

掌握 template 模块的两个选项也能避免事故。validate 用指定命令检查渲染结果,只有通过后才部署;backup: true 在覆盖前保留副本。从自动部署配置文件的那一刻起,就打开了错误配置杀死服务的路径。 validate 是阻断这条路径成本最低的装置。

在实际项目中

第一,每次渲染结果都不同的 template。 在注释中写入时间戳,会让文件每次都发生变化,handler 每次执行,服务也每次重启。仅这一行就可能破坏零停机部署。

第二,使用 facts 的 template。 直接使用 ansible_facts,可以让每台服务器自动生成不同配置。但特殊环境中的 fact 可能出现意料外值,因此应使用 default 建立防线。

第三,在 template 中写入过多逻辑。 五层 if 已经不是 template,而是程序。应把分支提升到变量计算阶段,让 template 保持简单,更利于维护。

template 中常用的过滤器

Jinja2 的价值主要来自过滤器,掌握下面这些已经足够处理多数情况。

{{ port | default(8080) }}              값이 없으면 기본값
{{ name | mandatory }}                  없으면 에러 — 조용한 빈 값을 막는다
{{ items | join(',') }}                 목록을 문자열로
{{ config | to_nice_yaml(indent=2) }}   딕셔너리를 YAML 블록으로
{{ secret | b64encode }}                쿠버네티스 시크릿용
{{ path | basename }}                   경로 조각
{{ hosts | map(attribute='ip') | list }} 목록에서 필드만 뽑기

养成使用 mandatory 的习惯很重要。变量缺失时,Jinja2 默认可能填入空字符串,生成 listen ; 这类损坏配置,而问题直到服务重启才暴露。

ansible.cfg 中加入以下配置,可以让未定义变量立即报错。

[defaults]
error_on_undefined_vars = True

如何处理空白

生成文件出现大量空行,通常是控制结构造成的。

{% for h in hosts %}
server {{ h }};
{% endfor %}

这样写时,每个 {% %} 行都会留下换行。加上连字符可以删除。

{% for h in hosts -%}
server {{ h }};
{% endfor -%}

Ansible 的 template 模块默认不启用 trim_blocks,需要时可在 template 第一行声明。

#jinja2: trim_blocks: True, lstrip_blocks: True

如何测试 template

部署前先查看结果。

# 렌더링 결과만 보기 (파일을 쓰지 않는다)
ansible -i inv web -m template -a "src=nginx.conf.j2 dest=/tmp/out.conf" --check --diff

# 문법 검사
ansible-playbook site.yml --syntax-check

# 실제로 무엇이 바뀌는지
ansible-playbook site.yml --check --diff

--check --diff 的组合最有用:它能在不修改的情况下展示将要改变什么。生产部署前不运行它,一行错误配置就可能让服务停止。

还要加入一步,用目标程序自身的检查器验证生成配置。

- name: nginx 설정
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    validate: 'nginx -t -c %s'      # ← 실패하면 파일을 바꾸지 않는다
  notify: reload nginx

validate 会先检查临时文件,只有通过后才移到目标位置,损坏配置不会接触真实磁盘路径。

下一实验要做什么

从基础渲染开始,依次使用过滤、循环与条件,再通过空白控制整理结果。把 fact 与 inventory_hostname 用在 template 中,并用 validate 阻止错误配置部署。最后从 group variable 中的后端列表生成完整 nginx 配置。