Ansible 学习笔记(进阶篇):文件管理、Jinja2 模板与 Playbook 组织
本文总结了Ansible进阶使用的核心技巧,重点包括:1)文件管理模块的幂等操作;2)Jinja2模板动态配置生成;3)高级主机选择模式;4)Playbook拆分复用策略。作者通过实际项目经验,整理了copy与template的区别、循环空组处理、import与include的适用场景等关键知识点,并分享了变量传递、条件判断等实用技巧。文章特别强调了文件操作的安全性和Playbook模块化的重要性
最近自学 Ansible,感觉已经能写一些简单的自动化脚本了,但一到实际项目就发现文件配置、动态生成和大规模主机管理还是有点乱。于是又翻了资料,把文件操作、Jinja2 模板和 Playbook 拆分组织这些重点内容整理了一下,写成这份笔记,方便自己以后复习,也分享给同样在学的同学。
目录
-
文件管理模块常用操作
-
Jinja2 模板生成动态配置
-
主机选择的高级模式
-
Playbook 拆分与复用(import vs include)
-
总结与易错点记录
-
学习小结
1. 文件管理模块常用操作
Ansible 自带的文件模块超级好用,基本覆盖了日常的创建、复制、修改、删除需求,而且大部分是幂等的,跑多少次都不会乱改。
常用模块:
-
file:创建/删除文件或目录,改权限、所有者 -
copy:把本地文件推到远程主机 -
lineinfile:确保某一行存在(或删除) -
stat:查看文件信息 -
synchronize:用 rsync 同步目录
几个常用例子:
创建空文件并设置权限:
- name: 创建配置文件
ansible.builtin.file:
path: /etc/myapp/app.conf
state: touch
mode: '0640'
owner: appuser
group: appgroup
复制本地文件(建议开 backup):
- name: 推送配置
ansible.builtin.copy:
src: files/app.conf
dest: /etc/myapp/app.conf
mode: '0640'
backup: yes
在文件末尾加一行:
- name: 添加环境变量
ansible.builtin.lineinfile:
path: /etc/profile
line: 'export JAVA_HOME=/opt/jdk'
state: present
insertafter: EOF
清理目录:
- name: 删除旧数据
ansible.builtin.file:
path: /tmp/old_data
state: absent
recurse: yes
目录同步(备份网站时常用):
- name: 同步 html 目录
ansible.posix.synchronize:
src: /var/www/html/
dest: /backup/html/
delete: yes
小体会:copy 适合静态文件,template 适合带变量的(后面会讲),先分清楚用哪个。
2. Jinja2 模板生成动态配置
静态文件用 copy 就行,但真实场景里配置经常要根据不同主机变化,这时候就得用 template 模块 + Jinja2 模板。
模板放 templates/ 目录,推荐用 .j2 后缀。
简单例子:生成 /etc/motd
templates/motd.j2:
欢迎登录 {{ ansible_hostname }}
当前时间:{{ ansible_date_time.date }}
内核:{{ ansible_kernel }}
Playbook:
- name: 生成动态 motd
ansible.builtin.template:
src: motd.j2
dest: /etc/motd
mode: '0644'
循环例子(生成 hosts 文件):
templates/hosts.j2:
127.0.0.1 localhost
{% for host in groups['webservers'] %}
{{ hostvars[host].ansible_default_ipv4.address }} {{ host }}
{% endfor %}
条件判断:
{% if ansible_distribution == 'Ubuntu' %}
# Ubuntu 专用配置
{% endif %}
常用过滤器:
-
{{ list | unique }} -
{{ value | default('默认值') }} -
{{ data | to_json }}
我踩过的坑:如果循环的组为空,会多出一堆空行,加个判断就好了:
{% if groups['webservers'] | length > 0 %}
{% for host in groups['webservers'] %}
...
{% endfor %}
{% endif %}
3. 主机选择的高级模式
写 Playbook 时,hosts: 这行可以写得很灵活,尤其是机器多了以后。
基础:
-
单机:
web1 -
组:
webservers、all -
通配:
web*
高级:
-
范围:
web[01:10] -
并集:
webservers,dbservers -
交集:
production:&webservers -
排除:
all:!web3
例子(灰度更新前5台生产web,跳过web3):
- hosts: web[1-5]:&production:!web3
tasks:
- ...
我现在做小项目时经常用交集+排除来控制滚动更新范围,挺好使的。
4. Playbook 拆分与复用(import vs include)
Playbook 写长了特别乱,最好拆成多个小文件。
-
import_tasks:静态导入,提前解析,条件可以作用到每个任务 -
include_tasks:动态包含,运行时决定,更灵活
通用任务文件 tasks/deploy.yml:
- name: 安装软件
ansible.builtin.package:
name: "{{ pkg_name }}"
state: present
- name: 启动服务
ansible.builtin.service:
name: "{{ service_name }}"
state: started
enabled: yes
主 Playbook:
- hosts: webservers
tasks:
- import_tasks: deploy.yml
vars:
pkg_name: nginx
service_name: nginx
区别:
-
import:适合固定流程,调试时可以用 --start-at-task 跳进去
-
include:适合根据条件动态决定包含哪个文件
我现在习惯把常用操作(安装软件、创建用户、配置防火墙)都拆成独立 tasks 文件,主文件只管传参和流程,改起来方便多了。
5. 总结与易错点记录
| 知识点 | 主要用途 | 易错点提醒 |
|---|---|---|
| copy vs template | 静态 vs 动态文件 | copy 不能用变量,template 必须 .j2 |
| lineinfile | 单行修改 | 正则写错会误删,记得 backup: yes |
| Jinja2 循环 | 动态生成 | 空组要判断,不然多空行 |
| 主机模式交集/排除 | 精准控制范围 | 逻辑容易搞混,多测试 |
| import vs include | 静态 vs 动态导入 | import 更严格,include 更灵活 |
| 变量传参 | 任务复用 | 用 vars 块传,避免全局污染 |
6. 学习小结
这部分内容练下来,感觉 Ansible 从“能写脚本”变成了“能管大项目”。文件模块 + 模板基本能解决 80% 的配置问题,Playbook 拆分后代码也整洁多了。
下次打算继续写变量、loop、roles 和错误处理。建议大家也自己搭几台虚拟机多敲,边敲边 debug 进步最快。
如果有同学也在学 Ansible,欢迎交流~
(完)
更多推荐
所有评论(0)