万级节点Nginx配置分发需避免手工同步,Ansible易因变量未定义报UndefinedError,应加default过滤器并显式加载vars;SaltStack需通过context注入grains/pillar,且reload前必须执行nginx -t验证。

万级节点的 Nginx 配置一致性分发,靠手工改 nginx.conf 或 scp 同步,根本不可行;Ansible 和 SaltStack 都能做,但选错方案会导致模板渲染失败、变量覆盖混乱、reload 不生效,甚至配置漂移。
Ansible 中用 template 模块渲染 Nginx 配置时,为什么总报 jinja2.exceptions.UndefinedError?
常见于变量未定义却在 nginx.conf.j2 里直接引用,比如写了 {{ upstreams }} 却没在 vars 或 host_vars 中声明。Ansible 默认不校验变量是否存在,直到渲染那一刻才炸。
- 在 playbook 里加
vars_prompt或vars_files前,先用debug: var=upstreams确认变量已加载 - 模板中所有变量都套上默认值:写成
{{ upstreams | default([]) }}而不是裸写{{ upstreams }} - 避免在
group_vars/all.yml里用include_vars动态加载,它不保证加载顺序;改用vars_files显式声明加载路径 - 检查 Jinja2 循环语法:
{% for s in servers %}后必须有{% endfor %},漏掉会静默失败(只报 undefined)
SaltStack 的 sls 文件里用 file.managed + template: jinja,为什么生成的配置里变量全是空字符串?
Salt 默认不自动注入 grains 和 pillar 到 Jinja 上下文,除非显式启用。你写的 {{ grains['id'] }} 看似合理,实际是空的。
- 在
file.managed块里必须加上context:手动传参,例如:context: hostname: {{ grains['id'] }} port: {{ pillar.get('nginx_port', 8080) }} - 别依赖
pillar.get()在模板里调用——Jinja 渲染阶段 pillar 还没被解析;所有 pillar 数据必须提前通过context注入 - 如果要用条件判断主机角色,优先用
grains['roles']而非自定义 grain,否则得在每台 minion 上手动 set:salt '*' grains.setval roles '["web", "api"]' - 注意
file.managed的replace: False会跳过渲染,只做文件存在性检查——这是静默跳过模板更新的最常见原因
reload Nginx 时,Ansible 报 service: nginx is not running,但 SaltStack 却提示 Job failed with return code 1
本质都是 reload 命令执行失败,但错误捕获粒度不同:Ansible 的 service 模块对 systemd 返回码做了封装,而 Salt 的 service.running 默认不检查配置语法是否合法。
- Ansible 必须在 reload 前加一步验证:
- name: Test nginx config command: nginx -t changed_when: false
否则service: name=nginx state=reloaded会因配置错误直接失败 - SaltStack 要显式调用
cmd.run执行nginx -t,再用onfail关联 reload 步骤;不能只依赖service.running的enable: True - 两者都要注意 SELinux 上下文:若用
copy或file.managed改了/etc/nginx/conf.d/下的文件,需补setype: httpd_config_t(Ansible)或seuser: system_u(Salt) - reload 不等于 restart:用
state=restarted会中断连接;万级节点务必用state=reloaded,且确保上游 LB 已配置健康检查
真正难的不是模板怎么写,而是当节点角色混杂(比如同一台机器既跑 web 又跑 api)、配置层级嵌套(global → site → location)、且需要灰度发布时,如何让变量作用域不冲突、reload 不误伤。这需要把 inventory 分组逻辑和 pillar 结构设计同步考虑,而不是只盯着 jinja 语法。











