400网站建设办公,查看网站主机,万网域名备案查询,自己做的网站转成二维码ansible管理变量和事实与实施任务控制
在 Ansible 中#xff0c;变量和事实#xff08;Facts#xff09;就像给剧本#xff08;Playbook#xff09;配备的 “信息工具箱”#xff0c;让你的自动化配置管理更灵活、更智能。
变量#xff1a;提前准备的 “预设信息”
变…ansible管理变量和事实与实施任务控制
在 Ansible 中变量和事实Facts就像给剧本Playbook配备的 “信息工具箱”让你的自动化配置管理更灵活、更智能。
变量提前准备的 “预设信息”
变量就像你出门前准备的清单提前可以提前预先定义好各种信息用的时候直接拿出来用。 怎么定义 在 Playbook 里直接写 就像把清单贴在剧本首页 - hosts: webserversvars:app_port: 8080 # 定义应用端口变量app_name: myapp # 定义应用名称变量tasks:- name: 启动应用command: /opt/{{ app_name }}/start --port {{ app_port }}单独放变量文件 就像把清单放进文件夹更整洁 # vars/app_vars.yml
app_port: 8080
app_name: myapp然后在 Playbook 里引用 - hosts: webserversvars_files:- vars/app_vars.yml命令行传变量 临时改清单比如临时换个端口 ansible-playbook deploy.yml -e app_port9090变量的小技巧 可以用{{ 变量名 }}在任务中调用像插卡一样灵活支持条件判断比如 “如果是生产环境端口用 443测试环境用 8080”
事实Facts自动收集的 “系统情报”
事实就像 Ansible 派出去的 “侦察兵”会自动收集目标主机的信息比如 IP 地址、操作系统、内存大小等不用你手动问。 怎么看收集到的情报 跑个命令让侦察兵汇报 ansible webservers -m setup会得到一堆信息比如 ansible_facts[os_family]操作系统类型比如 RedHat、Debianansible_facts[default_ipv4][address]主机 IP 地址ansible_facts[memory_mb][total]总内存MB 在 Playbook 里用事实 比如根据操作系统选不同的安装命令 - hosts: alltasks:- name: 安装nginxDebian系统apt: namenginx statepresentwhen: ansible_facts[os_family] Debian- name: 安装nginxRedHat系统yum: namenginx statepresentwhen: ansible_facts[os_family] RedHat小提示 事实默认会自动收集如果想关掉比如加快执行速度可以在 Playbook 里加gather_facts: no可以自定义事实local facts把自己关心的信息存到目标主机的/etc/ansible/facts.d/目录Ansible 会自动读取
总结变量 vs 事实
变量你主动告诉 Ansible 的信息提前设定事实Ansible 主动从目标主机收集的信息动态获取
两者结合就像给 Ansible 装上了 “大脑”—— 既知道你提前安排的计划又能根据实际情况灵活调整让配置管理既聪明又高效
管理 VARIABLES
变量简介
ansible 利用变量来存储数据以便在Ansible项目文件中重复引用有利于简化项目的创建和维护降低出错率。我们在playbook中可以针对如用户、软件包、服务、文件等进行变量定义。
变量命名规则
只能包含字母、数字和下划线如包含空格、点、$符号都为非法变量名只能以字母开头
变量范围和优先级
ansible项目文件中多个位置支持定义变量主要包含三个基本范围
Global scope从命令行或 Ansible 配置设置的变量。Play scope在play和相关结构中设置的变量。Host scope由清单、事实fact收集或注册的任务在主机组和个别主机上设置的变量。
优先级从高到低顺序Global - Play - Host。
在多个级别上定义了相同名称的变量则采用优先级别最高的变量。
Play scope
在 Ansible 里“Play scope”剧本作用域可以理解为一个 Play剧本的 “管辖范围” 和 “生效边界”。它就像给这个 Play 划了个圈圈里的规则、变量、设置只在这个范围内起作用不会跑到圈外去影响其他 Play。
举个生活例子你家里有客厅和卧室两个区域相当于两个 Play。在客厅里你规定 “看电视音量不能超过 30”这是客厅 Play 的变量 / 设置这个规则只在客厅生效到了卧室就不算数了 —— 这就是每个 Play 有自己独立的 scope。
具体来说Play scope 包含这些 “圈内要素”
目标主机通过hosts指定的主机 / 主机组只有这些主机受这个 Play 管理变量在 Play 的vars或vars_files里定义的变量只在当前 Play 的任务中可用提权设置当前 Play 里的become相关配置不会影响其他 Play事实收集gather_facts的开关状态只控制当前 Play 是否收集主机信息
比如一个 Playbook 里有两个 Play
- name: 管理web服务器 # Play 1hosts: webserversvars:app: nginx # 这个变量只在Play 1里有效tasks:- name: 安装nginxyum: name{{ app }} statepresent- name: 管理数据库服务器 # Play 2hosts: dbserversvars:app: mysql # 这个变量只在Play 2里有效tasks:- name: 安装mysqlyum: name{{ app }} statepresent这里两个 Play 的app变量互不干扰因为它们各自有独立的 scope。
简单说Play scope 就是 Ansible 里的 “楚河汉界”让每个 Play 在自己的地盘里按自己的规则干活互不打扰
vars 声明
在 Ansible 中vars就像给 Playbook 准备的 “变量口袋”用来提前存放各种需要反复使用的信息。声明变量的方式灵活多样就像你可以把东西放在口袋、抽屉或专门的收纳盒里一样。
1. 直接在 Play 里声明最直观
就像把常用物品直接揣在口袋里随用随拿。在 Play 的vars块里定义变量只在当前 Play 中生效。
- name: 部署web应用hosts: webserversvars:app_name: blog # 应用名称app_port: 8080 # 运行端口max_connections: 100 # 最大连接数tasks:- name: 创建应用目录file:path: /opt/{{ app_name }} # 引用变量state: directory2. 单独放变量文件更整洁
如果变量太多就像东西太多需要用抽屉分类收纳。把变量写在单独的 YAML 文件里再在 Playbook 中引用。
# 变量文件vars/app_settings.yml
app_name: blog
app_port: 8080
db_host: db.example.com在 Playbook 中调用这个文件
- name: 部署web应用hosts: webserversvars_files:- vars/app_settings.yml # 引入外部变量文件tasks:- name: 配置数据库连接lineinfile:path: /opt/{{ app_name }}/config.iniline: db_host {{ db_host }}3. 命令行临时声明应急用
就像临时从口袋里掏出个备用物品适合临时修改变量值不用改 Playbook 本身。用-e参数传递
# 临时把端口改成9090运行
ansible-playbook deploy.yml -e app_port90904. 主机 / 组变量按目标分类
如果不同主机需要不同变量比如 web 服务器和数据库服务器配置不同可以在inventory目录下创建专门的变量文件Ansible 会自动对应。
目录结构通常是这样
inventory/├── hosts # 主机清单├── group_vars/ # 组变量对整个组生效│ ├── webservers.yml # web服务器组的变量│ └── dbservers.yml # 数据库服务器组的变量└── host_vars/ # 主机变量对单台主机生效└── web01.yml # 给web01主机单独的变量比如group_vars/webservers.yml里写
app_type: nginx
log_path: /var/log/nginx变量使用小技巧 引用变量时用双大括号{{ 变量名 }}比如{{ app_name }} 变量名可以包含字母、数字和下划线不能以数字开头 支持嵌套比如 app:name: blogport: 8080引用时用 {{ app.name }}{{ app.port }}简单说vars声明就是给 Ansible 提前 “备课”—— 把需要用的信息整理好用的时候直接喊名字就能调出来不用重复写死既灵活又好维护
Host scope
主机变量应用于主机和主机组。主机变量优先级高于主机组变量。
主机清单中定义
较旧的做法是直接在清单文件中定义。不建议采用但仍可能会遇到。
[servers]
node1 userlaoma
node2[servers:vars]
userlaowang目录分层结构定义
在项目目录中创建如下目录 group_vars定义主机组变量。目录中文件名可以直接使用 主机组名 或者 主机组名.yaml 。 host_vars定义主机变量。目录中文件名可以直接使用 主机名 或者 主机名.yaml 。
主机连接特殊变量
详情参考主机连接特殊变量。 ansible_connection与主机的连接类型可以是 smart、ssh 或 paramiko。默认为smart。 ansible_host要连接的主机的名称默认值就是主机清单名称。 ansible_portssh 端口号如果不是 22。 ansible_userssh 用户名。 ansible_ssh_pass要使用的 ssh 密码。切勿以纯文本形式存储此变量始终使用保管库。 ansible_ssh_private_key_filessh 使用的私钥文件。如果使用多个密钥并且您不想使用 SSH 代理这很有用。 ansible_ssh_common_args此设置始终附加到 sftp、scp 和 ssh 的默认命令行。 ansible_sftp_extra_args此设置始终附加到默认的 sftp 命令行。 ansible_scp_extra_args此设置始终附加到默认的 scp 命令行。 ansible_ssh_extra_args此设置始终附加到默认的 ssh 命令行。 ansible_become等效于 ansible_sudo 或 ansible_su允许强制提权。 ansible_become_method允许设置权限提升方法。 ansible_become_user等效于 ansible_sudo_user 或 ansible_su_user允许设置您通过权限升级成为的用户。 ansible_become_pass等效于 ansible_sudo_pass 或 ansible_su_pass允许您设置权限提升密码切勿以纯文本形式存储此变量始终使用保管库。请参阅变量和保管库。
数组变量
除了将与同一元素相关的配置数据软件包列表、服务列表和用户列表等分配到多个变量外管理员也可以使用数组变量将多个值存储在同一变量中。
示例
user1_first_name: Bob
user1_last_name: Jones
user1_home_dir: /users/bjones
user2_first_name: Anne
user2_last_name: Cook
user2_home_dir: /users/acook改写如下
users:bjones:first_name: Boblast_name: Joneshome_dir: /users/bjonesacook:first_name: Annelast_name: Cookhome_dir: /users/acook数组变量引用方式一
# Returns Bob
users.bjones.first_name
# Returns /users/acook
users.acook.home_dir数组变量引用方式二
# Returns Bob
users[bjones][first_name]
# Returns /users/acook
users[acook][home_dir]引用方式总结
如果使用方法一**.分隔符**引用的关键字与python的功能函数同名例如discard、copy、add那么就会出现问题。方法二[‘’]引用方式可以避免这种错误。尽管两种方法都可以使用为了减少排故难度Ansible中统一使用其中一种方法。
示例1
---
- name: test vars statement in playhosts: node1vars: users:laoma:user_name: laomahome_path: /home/laomalaowang:user_name: laowanghome_path: /home/laowangtasks:- name: add user {{ users.laoma.user_name }}user:name: {{ users.laoma.user_name }}home: {{ users.laoma.home_path }}- name: debug laowangdebug: msg: username is {{ users[laowang][user_name] }}home_path is {{ users[laowang][home_path] }}示例2
---
- name: test vars statement in playhosts: node1vars: users:- user_name: laoma1home_path: /home/laoma1- user_name: laoma2home_path: /home/laoma2tasks:- name: add user {{ users.0.user_name }}user:name: {{ users.0.user_name }}home: {{ users.0.home_path }}- name: debug {{ users[1].user_name }}debug: msg: {{ users[1].user_name }}register 语句
**register 语句捕获任务输出。**输出保存在一个临时变量中稍后在playbook中可用于调试用途或者达成其他目的。
示例
---
- name: Installs a package and prints the resulthosts: node1tasks:- name: Install the packageyum:name: httpdstate: installedregister: install_result- debug: var: install_result在 Ansible 里register就像给任务装了个 “记录仪”能把任务执行的结果比如命令输出、状态信息存起来方便后面的任务 “回看” 或 “利用” 这些结果。
打个比方就像你让同事去查一个文件的大小他回来告诉你 “文件有 100MB”——register就相当于把这句话记在笔记本上你后面可以根据这个结果决定 “要不要备份”如果大于 50MB 就备份。
基本用法记录任务结果
在任务里加register: 变量名就会把结果存到这个变量里。比如记录ls命令的输出
- name: 查看/tmp目录内容command: ls /tmpregister: tmp_files # 把结果存到tmp_files变量里- name: 打印刚才的结果debug:var: tmp_files # 显示变量内容运行后会看到tmp_files里包含很多信息命令是否成功success、输出内容stdout、错误信息stderr等。
实用场景根据结果做判断
最常用的是结合when条件根据记录的结果决定下一步操作。
比如检查某个进程是否存在存在就重启不存在就启动
- name: 检查nginx进程command: pgrep nginxregister: nginx_statusignore_errors: yes # 即使命令失败进程不存在也不终止Playbook- name: 如果进程存在就重启nginxservice:name: nginxstate: restartedwhen: nginx_status.rc 0 # rc0表示命令成功进程存在- name: 如果进程不存在就启动nginxservice:name: nginxstate: startedwhen: nginx_status.rc ! 0 # rc≠0表示命令失败进程不存在这里nginx_status.rc是命令的返回码rc即 return code0 代表成功非 0 代表失败。
常用的结果字段
register变量里有很多有用的 “子信息”常用的有
stdout命令的标准输出比如ls列出的文件stderr命令的错误输出如果命令失败rc返回码0 成功非 0 失败changed任务是否改变了系统状态布尔值failed任务是否失败布尔值
比如只想看命令输出的内容
- name: 查看系统版本command: cat /etc/os-releaseregister: os_info- name: 打印系统版本信息debug:msg: 系统版本{{ os_info.stdout }} # 只取stdout部分简单说register就是 Ansible 里的 “记事贴”—— 让任务之间能 “传递消息”根据前面的结果动态决定后面的操作让 Playbook 变得更智能、更灵活
MAGIC 变量
magic 变量由 Ansible 自动设置可用于获取与特定受管主机相关的信息。
假设当前清单内容为
controller[webs]
node1
node2[dbs]
node3
node4最常用四个 Magic 变量 inventory_hostname包含清单中配置的当前受管主机的主机名称。这可能因为各种原因而与FACTS报告的主机名称不同。 [laomacontroller web]$ ansible node1 -m debug -a varinventory_hostname
node1 | SUCCESS {inventory_hostname: node1
}group_names列出当前受管主机所属的所有主机组。 [laomacontroller web]$ ansible node1 -m debug -a vargroup_names
node1 | SUCCESS {group_names: [webs]
}groups列出清单中的所有组以及组中含有的主机。 [laomacontroller web]$ ansible node1 -m debug -a vargroups
node1 | SUCCESS {groups: {all: [workstation,node1,node2,node3,node4],dbs: [node3,node4],ungrouped: [controller],webs: [node1,node2]}
}hostvars包含所有受管主机的变量可用于获取另一台受管主机的变量的值。如果还没有为受管主机收集FACTS则它不会包含该主机的 FACTS。 例如hostvars.controller.group_names
在 Ansible 里“MAGIC 变量”魔法变量就像自带的 “万能钥匙”不需要你手动定义Ansible 会自动生成并提供这些变量帮你快速获取 inventory主机清单里的各种信息让 Playbook 更灵活地处理主机间的关系。
它们之所以叫 “魔法变量”是因为你不用声明就能直接用就像凭空出现的工具专门解决和主机清单相关的问题。
最常用的几个 “魔法变量”
1. inventory_hostname当前主机的 “身份证”
返回当前正在处理的主机在 inventory 里的名字不是主机的 hostname而是你在清单里写的名字。
比如 inventory 里写着 web01.example.com那这个变量就返回它。
- name: 显示当前主机名debug:msg: 正在处理的主机{{ inventory_hostname }}2. groups主机组的 “花名册”
返回所有主机组的列表以及每个组里的主机。比如想知道 webservers 组有哪些主机
- name: 显示web服务器组的所有主机debug:msg: web组主机{{ groups[webservers] }}如果想获取所有主机组的名字用 groups.keys()。
3. group_names当前主机的 “所属群组”
返回当前主机所在的所有组列表形式。比如一台主机既在 webservers 组又在 prod 组这个变量就会返回这两个组名。
- name: 显示当前主机所属的组debug:msg: 我属于这些组{{ group_names }}4. hostvars其他主机的 “信息库”
可以获取其他主机的变量或 facts 信息相当于 “跨主机查资料”。
比如想获取 db01 主机的 IP 地址需要先收集过 facts
- name: 显示db01的IPdebug:msg: 数据库IP{{ hostvars[db01][ansible_default_ipv4][address] }}5. play_hosts当前 Play 的 “任务清单”
返回当前 Play 中正在处理的所有主机受 hosts 字段限制的主机列表。
- name: 显示当前Play要处理的所有主机debug:msg: 本次任务涉及主机{{ play_hosts }}为什么需要魔法变量
它们就像 Ansible 内置的 “导航系统”帮你在复杂的主机清单中定位信息
比如跨主机通信web 服务器需要知道数据库服务器的 IP比如根据主机所在组执行不同任务比如动态获取当前处理的主机信息
管理 SECRETS
Ansible Vault 简介
Ansible可能需要访问密码或API密钥等敏感数据此信息可能以纯文本形式存储在清单变量或其他Ansible文件中。任何有权访问Ansible文件的用户或存储这些Ansible文件的版本控制系统都能够访问此敏感数据。
这显然存在安全风险。Ansible随附的 Ansible Vault 可以加密任何由Ansible使用的结构化数据文件包括清单变量、playbook中含有的变量文件、在执行playbook时作为参数传递的变量文件以及Ansible角色中定义的变量。
变量管理推荐做法
包含敏感变量的文件可通过 ansible-vault 命令进行保护。敏感变量和所有其他变量保存在相互独立的文件中。管理组变量和主机变量的首选方式是在项目目录中创建子目录。
可为每个主机组或受管主机使用独立的目录。这些目录可包含多个变量文件它们都由该主机组或受管主机使用。
管理 FACTS
FACTS 介绍
FACTS 是 Ansible 在受管主机上自动检测到的变量默认保存在内容中只存在于本次playbook执行期间。
FACTS含有主机相关的信息可以像play中的常规变量一样使用。
受管主机的 facts 包括
• 主机名称 • 内核版本 • 网络接口 • IP地址 • 操作系统版本 • 各种环境变量 • CPU数量 • 提供的或可用的内存 • 可用磁盘空间
借助 facts可以方便地检索受管主机的状态并根据该状态确定要执行的操作。
例如
可以根据当前内核版本的FACTS运行条件任务以此来重新启动服务器。可以根据通过FACTS报告的可用内存来自定义 MySQL 配置文件。可以根据FACTS的值设置配置文件中使用的 IPv4 地址。
通常每个play在执行第一个任务之前会先自动收集FACTS。
查看 FACTS 内容
示例1查看所有变量
---
- name: Dump factshosts: node1tasks:- name: Print all factsdebug:var: ansible_facts示例2查看单个变量
---
- hosts: node1tasks:- name: Print Ansible factsdebug: msg: The default IPv4 address of {{ ansible_fqdn }}is {{ ansible_default_ipv4.address }}部分 FACTS
FACTVARIABLE短主机名ansible_facts[‘hostname’]完全限定的域名ansible_facts[‘fqdn’]主要IPv4地址基于路由ansible_facts[‘default_ipv4’][‘address’]所有网络接口的名称列表ansible_facts[‘interfaces’]/dev/vdal磁盘分区的大小ansible_facts[‘devices’][‘vda’][‘partitions’][vda1][‘size’]DNS服务器列表ansible_facts[‘dns’][‘nameservers’]当前运行的内核的版本ansible_facts[‘kernel’]
setup 和 gather_facts 模块
setup 和 gather_facts 模块都可以用来收集facts gather_facts 模块只能用来收集facts。 setup 模块除了用来收集facts还提供额外选项 filter 选项用于查看特定facts值。 gather_subset 选项用于控制收集facts范围
关闭 FACTS 收集
关闭 FACTS 收集部分原因
不使用任何FACTS希望加快play速度或减小play在受管主机上造成的负载受管主机因为某种原因而无法运行setup模块需要安装一些必备软件后再收集FACTS
Ansible配置文件设置
[defaults]
gathering explicitplay中设置
---
- name: Fact dumphosts: node1gather_facts: no即使关闭以后也可以随时使用setup模块收集facts。
实施任务控制
编写循环任务
利用循环管理员无需编写多个使用同一模块的任务。例如确保存在五个用户不需要编写五个任务而是只需编写一个任务来对含有五个用户的列表迭代。
Ansible支持使用 loop 关键字对一组项目迭代任务。您可以配置循环以利用列表中的各个项目、列表中各个文件的内容、生成的数字序列或更为复杂的结构来重复任务。
简单循环
简单循环对一组项目迭代任务。loop关键字添加到任务中 将应对其迭代任务的项目列表取为值。循环变量item保存每个迭代过程中使用的值。
示例:
---
- name: add several usershosts: node1gather_facts: notasks:- name: add user janeuser:name: janegroups: wheelstate: present- name: add user joeuser:name: joestate: presentgroups: wheel使用loop循环改写
- name: test loophosts: node1gather_facts: notasks:- name: add usersuser:name: {{ item }}groups: wheelstate: presentloop:- jane- joe这个 Playbook 的作用是在node1主机上批量创建两个用户jane 和 joe并将他们加入wheel组。
name: test loop这是 Play 的名称用于标识这个 Play 的用途hosts: node1指定在node1这台主机上执行gather_facts: no关闭 facts 收集加快执行速度因为这个任务不需要系统信息任务部分使用了loop关键字后面跟着一个用户列表[jane, joe]
在循环过程中Ansible 会自动将列表中的每个元素依次赋值给item变量然后执行user模块
第一次循环item jane创建用户 jane 并加入 wheel 组第二次循环item joe创建用户 joe 并加入 wheel 组
user模块的参数说明
name: {{ item }}用户名这里引用循环变量groups: wheel指定用户所属的附加组wheel 组通常用于 sudo 权限state: present确保用户存在如果不存在则创建
执行这个 Playbook 后目标主机上会新增 jane 和 joe 两个用户且都属于 wheel 组。这种循环方式非常适合需要批量执行相同操作的场景避免了重复编写任务代码。
循环散列或字典列表
在以下示例中列表中的每个项实际上是散列或字典。
示例中的每个散列或字典具有两个键即name和groups当前item循环变量中每个键的值可以分别通过item.name和item.groups变量来检索。
示例
- name: test loophosts: node1gather_facts: notasks:- name: add usersuser:name: {{ item.name }}groups: {{ item.groups }}state: presentloop: - name: janegroups: wheel- name: joegroups: root改写为
---
- name: add several usershosts: node1gather_facts: novars:users:- name: janegroups: wheel- name: joegroups: roottasks:- name: add users user:name: {{ item.name }}state: presentgroups: {{ item.groups }} loop: {{ users }}Register 与 Loop
示例
---
- name: Loop Register Testhosts: node1gather_facts: notasks:- name: Looping Echo Taskshell: echo This is my item: {{ item }}loop:- one- tworegister: result- name: Show result variabledebug:var: result- name: Show result variable stdoutdebug:msg: STDOUT from previous task: {{ item.stdout }}loop: {{ result.results }}编写条件任务
Ansible可使用conditionals在符合特定条件时执行任务或play。
例如管理员可利用条件来区分不同的受管节点并根据它们所符合的条件来分配功能角色。 Playbook变量、注册的变量和ANSIBLE FACTS都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。
用例
定义变量min_memory判断被管理节点可用内存是否满足该值。捕获命令输出判定task是否执行完成以便决定是否进行下一步操作。被管理节点上收集到的网络facts判定是否适合哪种绑定bonding或者trunking。根据CPU的数量决定如何调优web服务器。Registered变量与预定义的变量对比判断是否有变化。例如文件的MD5值。
when 语句
ansible playbook 中使用 when 来运行条件任务。
when 用于有条件地运行任务取要测试的条件作为值。如果条件满足则运行任务。若条件不满足则跳过任务。
注意通常的惯例是将可能存在的任何when关键字放在任务名称和模块(及模块参数)的后面。原因是任务是YAML散列/字典when 语句只是任务中的一个键就如任务的名称以及它所使用的模块一样。
常见判断
操作示例等于值为字符串ansible_machine “x86_64”等于值为数字max_memory 512小于min_memory 128大于min_memory 256小于等于min_memory 256大于等于min_memory 512不等于min_memory ! 512变量存在min_memory is defined变量不存在min_memory is not defined布尔变量值是1、True或yes的求值为真。memory_available布尔变量值是0、False或no的求值为假。memory_availablememory_available变量值为真最终结果为假。not memory_available第一个变量的值存在作为第二个变量的列表中的值ansible_distribution in supported_distros
布尔值变量判断
示例
---
- name: test hosts: node1gather_facts: novars:run_my_task: truetasks:- name: test whendebug:msg: Hello run my taskwhen: run_my_task示例中的when语句导致任务仅在run_my_task为 true时运行。
变量是否定义判断
变量判断
defined not undefined 变量定义返回真undefined not defined 变量未定义返回真none 变量定义了但是值是空值返回真
示例1
---
- hosts: node1gather_facts: novars:username: laomatasks:- debug:msg: var: username is definedwhen: username is defined示例2判断受管主机是否具有相应设备。
---
- name: create and use lvhosts: node1tasks:- name: Create a logical volume of 4000mlvol:vg: researchlv: datasize: 4000when: ansible_lvm.vgs.research is defined- debug:msg: Volume group does not existwhen: ansible_lvm.vgs.research is not defined文件属性判断
file如果路径是一个普通文件返回真directory如果路径是一个目录返回真link如果路径是一个软连接返回真mount如果路径是一个挂载点返回真exist如果路径是存在返回真
示例
---
- hosts: node1gather_facts: novars:file_name: /etc/hoststasks:- debug:msg: {{ file_name }} is regular filewhen: file_name is file任务执行结果判断
succeeded通过任务的返回信息判断任务执行成功返回真。failed通过任务的返回信息判断任务执行失败返回真。changed通过任务的返回信息判断任务执行状态为changed返回真。skipped通过任务的返回信息判断任务没有满足条件跳过执行返回真。
示例
---
- hosts: node1gather_facts: novars:doshell: yestasks:- shell: cat /etc/hostsregister: resultignore_errors: truewhen: doshell yes- name: successdebug:msg: successwhen: result is succeeded- name: faileddebug:msg: failedwhen: result is failed- name: changeddebug:msg: changedwhen: result is changed- name: skippeddebug:msg: skipwhen: result is skipped其他测试
设置doshell: “no”设置shell: cat /etc/hosts-no-exist
in 和 not in 判断
示例1给用户添加组
---
- name: test hosts: node1gather_facts: novars:username: devopssupergroup: wheeltasks:- name: gather user informationshell: id {{ username }}register: result- name: Task run if user is in supergroupsuser:name: {{ username }}groups: {{ supergroup }}append: yeswhen: supergroup not in result.stdout示例2给用户添加多个组
---
- name: test hosts: node1gather_facts: novars:username: devopssupergroups: - wheel- roottasks:- name: gather user informationshell: id {{ username }}register: result- name: Task run username is in supergroupsuser:name: {{ username }}groups: {{ item }}append: yeswhen: item not in result.stdoutloop: {{ supergroups }}Ansible Handlers
Ansible Handlers 功能
Ansible的模块的设计是可以多次执行的当被管理节点是预期状态时是不会做任何更改的。然而有时候执行了一个任务还需要进一步执行下一个任务。
例如更改了服务配置文件之后需要重新加载配置文件才能生效。Handlers是由其他任务通知执行的任务可看做inactive任务通过notify调用。
示例
---
- name: deploy web serverhosts: node1tasks:- name: install packagesyum:name: httpdstate: presentnotify:- enable and restart apache- name: install httpd-manualyum:name: httpd-manualstate: presentnotify:- enable and restart apache- debug: msg: last task in taskshandlers:- name: enable and restart apacheservice:name: httpdstate: restartedenabled: yes在 Ansible 中Handlers处理器 就像一个 “待命的助手”专门用来处理那些 “只有在系统状态发生变化时才需要执行” 的操作。它有点像 “触发器”—— 只有当某个任务真正改变了系统状态比如修改了配置文件Handlers 才会被触发执行。
为什么需要 Handlers
举个例子当你修改了 Nginx 的配置文件nginx.conf只有在配置文件真的被改动时才需要重启 Nginx 服务。如果配置文件没变化重启操作就是多余的。
Handlers 正是为这种场景设计的它能 “监听” 任务是否导致了系统状态变更通过changed: true标识只有变更发生时才执行指定操作避免无效重复执行。
基本用法定义和触发 Handlers
Handlers 的使用分为两步定义 Handlers 和 在任务中通知notifyHandlers。
- name: 配置Nginx并按需重启hosts: webserverstasks:- name: 修改Nginx配置文件copy:src: ./nginx.confdest: /etc/nginx/nginx.confnotify: # 当这个任务导致状态变更时通知Handlers- 重启Nginx服务 # 这里的名称要和Handlers中定义的一致handlers: # 定义Handlers放在Play的handlers块中- name: 重启Nginx服务 # 名称要和notify中的完全匹配service:name: nginxstate: restarted执行逻辑
执行 “修改 Nginx 配置文件” 任务 如果配置文件有变化changed: true则标记 “重启 Nginx 服务” 这个 Handler 为 “待执行”如果配置文件无变化changed: false则不通知 Handler 当 Play 中所有任务执行完毕后Ansible 会统一执行所有被标记为 “待执行” 的 Handlers。
Handlers 的特点 延迟执行Handlers 不会在被通知后立即执行而是等到当前 Play 中所有任务都执行完才统一运行。 幂等性保障即使多个任务通知同一个 Handler它也只会执行一次。例如 tasks:- name: 修改配置文件Acopy: srca.conf dest/etc/nginx/notify: 重启Nginx服务- name: 修改配置文件Bcopy: srcb.conf dest/etc/nginx/notify: 重启Nginx服务无论两个任务是否都触发了变更“重启 Nginx 服务” 只会执行一次避免多次重启。 名称唯一Handlers 通过name标识notify必须严格匹配名称包括大小写否则无法触发。
常见使用场景
Handlers 最适合处理 “配置变更后需要生效的操作”例如
服务重启Nginx、MySQL、Apache 等重新加载配置systemctl reload重建缓存如systemctl daemon-reload重新编译当源码或 Makefile 被修改时
简单说Handlers 就像 “按需执行的收尾工作”—— 平时待命只有当系统真的发生了需要它处理的变化时才会出手完成必要的后续操作让 Playbook 更高效、更符合实际运维逻辑。
处理 Errors
Errors 介绍
Ansible评估各任务的返回代码从而确定任务是成功还是失败。通常而言 当某个主机执行任务失败时Ansible将立即终止该主机继续执行play其他主机可以继续执行play。
---
- name: testhosts: node1,node2tasks:- name: show /etc/myhostsshell: cat /etc/myhosts- name: echo enddebug:msg: echo endignore_errors
您可能希望即使在任务失败时也继续执行play。例如您或许预期特定任务有可能会失败并且希望通过有条件地运行某项其他任务来恢复。
ignore_errors可以定义在以下位置
定义在 play 中则play中所有任务忽略错误。定义在 task 中则特定task忽略错误。
示例
---
- name: testhosts: node1tasks:- name: install a not exist packageyum:name: notexitpackagestate: presentignore_errors: yesregister: result- name: debug install resultdebug:msg: notexitpackage is not exitwhen: result is failedfail 模块
fail 模块执行该任务任务必定 failed。
示例
- name: test fail modulehosts: node1gather_facts: notasks:- debug:msg: task1- fail:- debug:msg: task3提示fail模块本身也可以配置when判断实现说明情况下任务是失败的。
failed_when
指明什么条件下判定任务执行失败。
示例
- name: test failed_whenhosts: node1tasks:- shell: /root/adduserregister: command_resultfailed_when: failed in command_result.stdout环境准备
[rootnode1 ~]# cat /root/adduser
#!/bin/bash
useradd devops /dev/null
if [ $? -eq 0 ];thenecho add user devops success
elseecho add user devops failed
fi
[rootnode1 ~]# chmod x /root/adduser 以上示例
当devops用户不存在时shell模块跳过执行。当devops用户存在时shell模块执行失败。
以上示例可改写为fail模块和when语句联合使用
- name: test fail modulehosts: node1tasks:- shell: /root/adduserregister: command_result- fail:msg: add user devops failedwhen: failed in command_result.stdoutchanged_when
指明什么条件下判定任务执行结果为changed。
示例1
- name: changed_whenhosts: node1tasks:- name: upgrade-databaseshell: /usr/local/bin/upgrade-databaseregister: resultchanged_when: Success in result.stdoutnotify:- restart_databasehandlers:- name: restart_databaseservice:name: mariadbstate: restarted