对于Linux运维来说,Ansible不是“可选工具”,而是“必备神器”——它能帮你摆脱重复劳动,把时间花在更有价值的故障排查、架构优化上。
在 Ansible 自动化中,管理配置文件是核心任务之一。根据场景不同,我们需要把文件原样分发,或是动态生成后再推送,也可能只修改文件中的某一行。

下面围绕 Jinja2 模板和常用文件模块,系统地拆解它们的用法与适用场景。
4.1 Jinja2 模板:动态生成配置文件
Jinja2 是 Python 的模板引擎,Ansible 内置了对它的支持。通过模板,我们可以将变量、各主机相关的真实变量(facts)、循环和条件语句写入配置文件模板,推到远端时自动渲染成最终内容。
基本语法
- 变量:
{{ variable_name }}输出变量的值,可配合default过滤器预防未定义错误:{{ some_var | default('fallback') }} - 控制结构:
{% ... %} 条件: {% if ... %} ... {% elif ... %} ... {% else %} ... {% endif %}循环: {% for item in list %} ... {% endfor %}- 注释:
{# 这是注释 #} - 过滤器: 通过管道
|修饰变量,如{{ name | upper }}、{{ list | join(',') }}
模板文件中可用的数据
Playbook 中定义的变量( vars、vars_files)Inventory 中的主机变量和组变量( host_vars、group_vars)由 setup模块采集的各主机上的情况的变量(如ansible_facts['os_family'])魔法变量(如 inventory_hostname、groups)
示例:动态生成 Nginx 虚拟主机配置
模板文件nginx_vhost.conf.j2:
server { listen {{ nginx_listen_port | default(80) }}; server_name {{ server_name }}; root {{ document_root }}; index index.html index.htm; # 根据环境开启访问日志 {% if env == 'production' %} access_log /var/log/nginx/{{ server_name }}.log main; {% else %} access_log off; {% endif %} # 循环添加允许访问的IP {% for ip in allow_ips %} allow {{ ip }}; {% endfor %} deny all;}Playbook 调用template 模块:
- name: 部署 Nginx 虚拟主机配置 template: src: nginx_vhost.conf.j2 dest: /etc/nginx/conf.d/{{ server_name }}.conf owner: root group: root mode: '0644' vars: server_name: www.example.com document_root: /var/www/example env: production allow_ips: - 192.168.1.0/24 - 10.0.0.1推送后远端文件会渲染成完整的 server 块,变量被替换,条件、循环都已执行。
4.2 常用文件模块
Ansible 提供了多个模块来处理“文件”类操作,按功能和使用场景归纳如下。
1. copy – 原样复制文件
功能:把控制节点上的一个文件(或内容)复制到受管节点的指定位置。
特点:不做变量替换,适合静态文件(如二进制、脚本、已写死的配置文件)。
常用参数:src(本地源文件路径,或 content 提供字符串)、dest(远端目标路径)、owner/group/mode、backup(覆盖前备份原文件)。
- name: 分发静态脚本 copy: src: files/cleanup.sh dest: /usr/local/bin/cleanup.sh owner: root group: root mode: '0755'- name: 通过内容创建文件 copy: content: | # This is a static config debug=true dest: /etc/app/static.conf2. template – 动态模板渲染后复制
功能:将 Jinja2 模板渲染后,写入远端文件。
与 copy 模块的区别:template 处理的是 src 模板文件(.j2 后缀只是约定),它会先执行 Jinja2 引擎替换变量,再像 copy 一样设置属性。这是生成各环境差异化配置的核心方法。
额外参数:validate(某些程序支持配置文件语法校验,如 nginx -t)、force(是否强制覆盖,默认 yes)等。
- name: 动态生成 Redis 配置 template: src: redis.conf.j2 dest: /etc/redis/redis.conf validate: 'redis-server %s --test-memory 2' # 示例校验 notify: restart redis3. lineinfile – 按行管理文件内容
功能:确保某一行“存在且内容正确”,或删除匹配特定正则的行。常用于修改已有的配置文件中的某个键值,而不影响文件其余部分。
关键参数:
- path: 要操作的文件。
- regexp: 用于定位该行的正则表达式(通常匹配配置的关键字)。
- line: 要写入的完整行内容。
- state:
present(保证存在)或absent(删除匹配行)。 - backrefs: 启用反向引用,配合正则捕获组时可重构行内容。
- insertafter/
insertbefore:在匹配行之后或之前插入。
示例:确保 SSH 禁止 root 登录
- name: 确保 PermitRootLogin 设为 no lineinfile: path: /etc/ssh/sshd_config regexp: '^#?PermitRootLogin\s' line: 'PermitRootLogin no' state: present notify: restart sshd解释:正则匹配以 PermitRootLogin 开头(可能有注释 #)的行,然后用正确的行替换。如果文件里没有匹配行,lineinfile 会在末尾追加。
示例:删除某行
- name: 删除日志中的 DEBUG 行(可选) lineinfile: path: /etc/app/logging.conf regexp: '^DEBUG=' state: absent4. 其他常用模块
blockinfile: 若需插入或管理一个多行的文本块,用标记包围,比lineinfile更安全可控。fetch: 从受管节点拉取文件回控制节点(与copy方向相反)。file: 设置文件/目录属性(创建目录、软链接、权限等),不负责内容。常配合copy/template前使用。- name: 确保应用目录存在 file: path: /opt/myapp/config state: directory owner: app mode: '0755'
模块选择速查
copy | |
template | |
lineinfile | |
blockinfile | |
file | |
fetch |
所有这些模块都具备幂等性:多次执行只会让系统达到期望状态,不会重复修改。lineinfile 会根据正则检查是否已经是要写入的行,copy/template 会比对校验和,只有真正变化时才执行变更并返回 changed 状态。这种设计保证了 Ansible 自动化的安全与可靠。
夜雨聆风