Asible——将文件部署到受管主机和管理复杂的Play和Playbook
第五章 将文件部署到受管主机
(一)、ansible模块
- patch:通过GNU将补丁应用于文件
- synchronize:围绕rsync命令的打包程序加快和简化常见任务,只修改目标文件和源文件中不同的部分。
- file:能让文件具备正确的权限和SELinux类型,类似chcon命令,(user_home_t是专门用于标识用户主目录下的文件或目录的类型)
- file和copy模块都能修改文件属性
- copy:将控制节点上的文件传到受管主机中
- fetch:从受管主机提取文件
- lineinfile:确保特定行位于某个文件中,或使用反向引用正则表达式来替换现有行
- blockinfile:(" | "保留换行符,“ > ”不保留换行符)
- stat:类似于stat命令,检索文件的状态信息,确认文件校验和等功能
- debug: 将文件内容输出
- 使用ansible.posix.synchronize模块,类似于rsync命令
(二)、Jinja2简介
- Ansile使用Jinja2模板系统来修改文件,然后再将文件分发到受管主机
- Ansible也使用Jinja2在playbook中引用变量
- Ansible允许在模板中使用Jinja2循环和条件,但playbook中中
1.表达式{{ EXPR }}会换成该表达式或变量的结果。也可以使用{% EXPR %}用于特殊的控制结构或逻辑,也可以使用{# COMMENT #}语法括起不应出现在最终文件中的注释。
(1)模板文件通常保存在playbook项目的templates目录中,并且通常分配有.j2文件扩展名,以标明是Jinja2模板文件。
(2)要使用ansible.builtin.template模块,使用以下语法:与src键关联的值指定来源Jinja2模板,而与dest键关联的值指定要在目标主机上创建的文件。
tasks:- name: template renderansible.builtin.template:src: /tmp/j2-template.j2dest: /tmp/dest-condig-file.txt
3.管理模板文件
为避免其他系统管理员修改ansible管理的文件,最好在模板顶部包含注释,以指示不应手动编辑该文件
4.使用循环
Jinja2使用for语句来提供循环功能。例如:
{% for user in users %}{{ user }}
{% endfor %}
例如:以下示例模板使用for语句逐一运行users变量中的所有值,将myuser替换为各个值,但值为root 时除外。
{# for statement #}
{% for myuser in users if not myuser =="root" %}
User number {{ loop.index }} - {{ myuser }}
{% endfor %}
这段代码的核心逻辑是:遍历 users
中的每个用户,跳过名为 "root"
的用户,然后按 “序号 - 用户名” 的格式渲染出其他用户的信息。
5.使用条件句,例如以下示例:仅当finished变量的值为true时,才可将result变量的值放入已部署的文件。
{% if finished %}
{{ result }}
{% endif%}
第六章 管理复杂的Play和Playbook
(一)利用主机模式选择主机
1. 最基础的主机模式
- 规则:在 Ansible 清单(Inventory,记录受管主机的配置文件)中直接列出单个受管主机的名称。
- 效果:该主机成为
ansible-navigator
等命令执行操作时唯一的目标主机。
2. Gathering Facts
任务的影响
Gathering Facts
是 Playbook 运行时默认的第一个任务,作用是 “收集受管主机的系统信息(如操作系统、IP、硬件等)”。- 规则:它会在 “与主机模式匹配的所有受管主机” 上运行;如果某台主机在执行此任务时发生故障(比如连接失败、权限不足),这台主机就会被从当前 Play 中移除,后续任务不再对它执行。
3. IP 地址在主机模式中的限制
- 允许的情况:只有当 IP 地址明确写在清单中时,才能在主机模式中用 IP 来指定主机。
- 禁止的情况:如果 IP 地址没列在清单里,哪怕它能通过 DNS 解析到某个主机名,也不能用这个 IP 来指定主机。
4.使用通配符匹配多个主机
- ‘*’表示可匹配任意字符串
- ‘*.example.com' 表示通配符匹配以’.example.com'结尾的所有清单名称
- ‘192.168.2.*’表示通配符匹配以’192.168.2.'开头的所有清单名称
- 可以通过逻辑列表来引用清单中的多个条目,以逗号分割
- 使用(&)符号,他的工作方式类似于逻辑AND
例如:下图表示主机模式将匹配lab组中同时也属于datacenter1组的计算机
- 要从主机模式中排除某一模式的主机,可以在主机模式的前面使用(!)符号,它的工作方式类似于逻辑NOT
例如:下图表示匹配datacenter组中顶柜的所有主机,但test2.example除外
(二)包含和导入文件
如果playbook很长或者很复杂,可以将其分成较小的文件以便于管理。可以将多个playbook组和到一个主pplaybook中,或者将文件中的任务列表插入play,这样可以更轻松的在不同项目中重用play 或任务序列。
其中,包含内容和导入内容是两种普遍的操作
1.导入内容(import_tasks)
导入内容是一个静态操作,在playbook运行期间,ansible会在最初解析playbook时预处理导入的内容
通过import_playbook指令,可以将包含play列表的外部文件导入plabook.
导入任务文件时,在解析该playbook时将直接查到该文件中的任务。由于import_tasks在解析playbook时会静态导入任务,所以必须考虑以下事项:
- 使用impost_tasks功能时,导入设置的when等条件语句将应用于导入的每个任务。
- 不能将循环用于import_tasks功能
2.包含内容(include_tasks)
包含内容是一个动态操作,在playbook运行期间,ansible会在内容到达时处理所包含的内容
---
- name: Install web serverhost: webserverstasks:- include_tasks: webserver_tasks.yml
3.两者区别
在 Ansible 中,include_tasks
与import_tasks
都能用于引入外部任务文件 ,但它们在工作机制、任务处理时机和任务列表展示等方面存在区别:
工作机制与处理时机
include_tasks
:是动态包含,在运行 playbook 时,当执行流程到达include_tasks
语句所在位置,才会读取并执行引入的任务文件。 比如在一个大型的部署 playbook 中,根据不同的服务器角色(通过变量判断),动态决定是否引入特定的配置任务文件,只有当执行到相关部分,且条件满足时才会引入任务。这意味着可以结合条件判断语句(如when
) ,根据运行时的实际情况(如变量值、主机事实等)决定是否引入任务。例如:
yaml
- name: Conditional include taskshosts: alltasks:- name: Check if should include tasksset_fact:include_my_tasks: "{{ ansible_os_family == 'Debian' }}"- name: Include tasks conditionallyinclude_tasks: my_tasks.ymlwhen: include_my_tasks
import_tasks
:是静态导入,在解析 playbook 阶段,Ansible 就会读取并解析被导入的任务文件,将其中的任务合并到主 playbook 中。所以无法结合运行时的条件判断来决定是否导入任务,在解析阶段就已经确定好要导入的任务。比如在一个通用的服务器初始化 playbook 里,不管服务器是什么环境,都要导入基础软件安装任务,使用import_tasks
就能在一开始就把任务确定下来。示例如下
yaml
- name: Import taskshosts: alltasks:- name: Always import base tasksimport_tasks: base_install_tasks.yml
对任务列表显示的影响
include_tasks
:当使用ansible-navigator run --list-tasks
或ansible-playbook --list-tasks
列出任务时,只会显示include_tasks
这个引入任务的操作,而不会展示被引入任务文件中的具体任务 。比如运行上述包含include_tasks
的 playbook,任务列表中只会出现类似Include tasks conditionally
这样的任务,而不会列出my_tasks.yml
中的具体任务。import_tasks
:使用相同命令列出任务时,会直接展示被导入任务文件中的具体任务。 例如在上述使用import_tasks
的例子中,任务列表里会直接显示base_install_tasks.yml
中每个安装软件等具体任务。
错误处理
include_tasks
:如果被包含的任务文件中存在错误,只有当执行到include_tasks
语句时才会报错。import_tasks
:在解析 playbook 阶段,若被导入的任务文件存在语法等错误,Ansible 就会立即报错,阻止 playbook 继续执行。
任务重用性
include_tasks
:每次执行到include_tasks
语句时,都会重新处理被包含的任务文件,在不同场景下可以根据运行时条件灵活调整任务行为,适用于需要动态调整任务的场景。import_tasks
:任务在解析阶段就被合并到主 playbook 中,一旦导入就成为主 playbook 的一部分,更侧重于将一些固定的、通用的任务集整合到多个 playbook 中,提高代码复用性 ,但灵活性相对较低。