当前位置: 首页 > news >正文

Ansible 学习笔记:变量事实管理、任务控制与文件部署

管理变量和事实

管理 FACTS

FACTS 介绍

FACTS 是 “Flexible AC Transmission Systems(柔性交流输电系统)” 的缩写,是指一类用于增强电力系统传输能力、稳定性与控制性的电力电子装置或技术。

它通过快速调节系统中的电压、电流、阻抗或相位角,提高交流电网的传输效率与安全性。

查看 FACTS 内容

示例1:查看所有变量

[yuxb@controller web 09:49:50]$ cat playbook.yml ---# - name: Installs a package and prints the result#  hosts: node1#  tasks:#   - name: Install the package#     yum:#       name: httpd#       state: installed#     register: install_result#   - debug: #       var: install_result- name: Dump factshosts: node1​tasks:- name: Print all factsdebug:var: ansible_facts...​

示例2:查看单个变量

目的:

通过 setup 模块获取 facts,并在 playbook 中打印指定变量的值。

---- hosts: node1tasks:- name: Print Ansible factsdebug: msg: >The default IPv4 address of {{ ansible_fqdn }}is {{ ansible_default_ipv4.address }}

使用 setup 模块收集目标主机 facts:

[yuxb@controller web 09:57:03]$ ansible node1 -m setup > node1.facts^[[A[yuxb@controller web 09:57:1sz node1.factsacts​

说明:

  • -m setup:使用 setup 模块收集系统信息(Facts)

  • > node1.facts:将输出保存到本地文件 node1.facts 中,便于查看和搜索

setup 和 gather_facts 模块

Facts 是 Ansible 自动收集的远程主机信息,比如:

  • 主机名、IP、操作系统、内存、CPU

  • 网络接口、磁盘挂载、Python 版本

  • 默认网关、路由、FQDN 等

setup模块
  • setup 是一个 Ansible 模块,你可以手动调用它来 收集并查看某个主机的所有 facts

  • 适合临时查看、调试或提取特定信息。

# 收集并打印出 node1 的所有系统信息。ansible node1 -m setup​
# 只查看默认 IPv4 的 facts 信息ansible node1 -m setup -a 'filter=ansible_default_ipv4'​
gather_facts 参数
  • gather_factsPlaybook 中的一个参数,用于指定 是否自动在执行任务前收集 facts

  • 默认是 true

示例:

---- hosts: allgather_facts: true  # 默认就是 truetasks:- name: Print OS typedebug:msg: "This system is {{ ansible_os_family }}"

设置为 false(不收集):

---- hosts: allgather_facts: falsetasks:- name: This will not have factsdebug:msg: "No facts will be available"
总结对比表:
特性setup 模块gather_facts 参数
类型模块(可命令行或 task 中使用)Playbook 级参数
作用时机手动执行时收集 facts在每次 Playbook 运行前自动执行
默认行为不自动运行默认是自动运行(true)
过滤功能支持 filter 查询特定 facts不支持 filter,只能全量收集
使用场景临时查询、过滤 facts、调试等用于 Playbook 中任务执行前的数据准备

实施任务控制

Ansible 中,"实施任务控制" 通常指的是对任务执行流程的控制,比如:

  • 条件执行(when)

  • 循环执行(with_items / loop)

  • 错误处理(block / rescue / ignore_errors)

  • 任务依赖(tags / handlers)

  • 异步执行(async / poll)

  • 任务注册与判断(register)

编写循环任务

复杂循环

[yuxb@controller web 10:36:36]$ cat playbook.yml # yaml格式起始行,一般不省略---​# Playbook中第一个play# play具有属性:name,hosts,become,tasks,缩进一致# name属性,用于简要描述play- name: Enable intranet services# hosts属性,用于定义要在哪个受管理节点执行hosts: node1# tasks属性,用于描述play中任务,属性是列表格式tasks:# 第一个任务# 任务具有属性:涵name和模块名等。# name属性,用于简要描述任务- name: latest version of httpd and firewalld installed# 指明模块名,也就是要执行的任务yum:# 执行要操作的rpm包名称name:# rpm包名称是-开头的列表格式,或者逗号分隔的列表格式- httpd- firewalld# 定义软件包的状态,lastet代表升级为最新版本state: latest# 第二个任务- name: test html page is installed# copy模块,用于将content属性值写入到目标文件copy:content: "Welcome Laoma WebSite!\n"dest: /var/www/html/index.html# 第三个任务- name: firewalld enabled and running# service模块,用于启用并启动firewalld服务service:name: "{{item}}"enabled: truestate: startedloop:- httpd- firewalld# 第四个任务# - name: firewalld permits access to httpd service#   # firewalld,用于放行http服务#   firewalld:#     service: http#     permanent: true#     state: enabled#     immediate: yes# 第五个任务- name: httpd enabled and running# service模块,用于启用并启动httpd服务service:name: httpdenabled: truestate: started​# Playbook中第二个play,-开头表示列表- name: Test intranet web serverhosts: localhostbecome: notasks:- name: connect to intranet web server# uri模块,用于测试网站是否可以访问uri:url: http://node1return_content: yesstatus_code: 200​# yaml格式结束行,一般省略...​# 验证[yuxb@controller web 10:36:41]$ ansible-playbook playbook.yml ​PLAY [Enable intranet services] *********************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [latest version of httpd and firewalld installed] **********************************************ok: [node1]​TASK [test html page is installed] ******************************************************************changed: [node1]​TASK [firewalld enabled and running] ****************************************************************ok: [node1] => (item=httpd)ok: [node1] => (item=firewalld)​TASK [httpd enabled and running] ********************************************************************ok: [node1]​PLAY [Test intranet web server] *********************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [localhost]​TASK [connect to intranet web server] ***************************************************************ok: [localhost]​PLAY RECAP ******************************************************************************************localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   node1                      : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   ​

简单循环

示例一
[yuxb@controller web 10:40:57]$ vim playbook.yml---- name: add several usershosts: node1gather_facts: notasks:- name: add user janeuser:name: "jane"groups: "wheel"state: present- name: add user joeuser:name: "joe"state: presentgroups: "wheel"...​# 使用loop循环改写[yuxb@controller web 10:49:39]$ cat playbook.yml ---- name: add several usershosts: node1gather_facts: notasks:- name: add user janeuser:name: "{{ item }}"groups: "wheel"state: presentloop:- jane- joe  ...​# 验证[yuxb@controller web 10:36:55]$ ansible-playbook playbook.yml ​PLAY [add several users] ****************************************************************************​TASK [add user jane] ********************************************************************************changed: [node1] => (item=jane)changed: [node1] => (item=joe)​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   ​
示例二
[yuxb@controller web 10:58:12]$ cat playbook.yml ---- name: add several usershosts: node1gather_facts: notasks:- name: add user janeuser:name: "{{ item.name }}"groups: "{{ item.groups }}"state: presentloop:- name: janegroups: wheel- name: joegroups: root...​# 验证[yuxb@controller web 10:49:53]$ ansible-playbook playbook.yml ​PLAY [add several users] ****************************************************************************​TASK [add user jane] ********************************************************************************ok: [node1] => (item={u'name': u'jane', u'groups': u'wheel'})changed: [node1] => (item={u'name': u'joe', u'groups': u'root'})​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   ​

Do-Until Loops

Do-Until 循环 是一种 后测试循环结构,意思是:

  • 先执行一次循环体

  • 然后再判断条件

  • 直到条件为真时,循环才会终止

示例:测试 node2,什么时候可以ping通。

[yuxb@controller web 10:58:14]$ vim playbook.yml [yuxb@controller web 11:20:47]$ cat playbook.yml ---- name: test loophosts: node1gather_facts: notasks:- shell: ping -c1 -w 2 node2register: resultuntil: result.rc == 0retries: 20delay: 1...​# 关闭node2测试[yuxb@controller web 11:21:03]$ ansible-playbook playbook.yml ​PLAY [test loop] ************************************************************************************​TASK [shell] ****************************************************************************************FAILED - RETRYING: command (20 retries left).FAILED - RETRYING: command (19 retries left).FAILED - RETRYING: command (18 retries left).FAILED - RETRYING: command (17 retries left).​# 测试过程中打开node2后[yuxb@controller web 11:21:03]$ ansible-playbook playbook.yml ​PLAY [test loop] ************************************************************************************​TASK [shell] ****************************************************************************************FAILED - RETRYING: command (20 retries left).FAILED - RETRYING: command (19 retries left).FAILED - RETRYING: command (18 retries left).FAILED - RETRYING: command (17 retries left).FAILED - RETRYING: command (16 retries left).FAILED - RETRYING: command (15 retries left).FAILED - RETRYING: command (14 retries left).FAILED - RETRYING: command (13 retries left).FAILED - RETRYING: command (12 retries left).FAILED - RETRYING: command (11 retries left).FAILED - RETRYING: command (10 retries left).FAILED - RETRYING: command (9 retries left).FAILED - RETRYING: command (8 retries left).FAILED - RETRYING: command (7 retries left).FAILED - RETRYING: command (6 retries left).FAILED - RETRYING: command (5 retries left).changed: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   ​

编写条件任务

在 Ansible 中,使用 when 子句实现条件判断,使任务根据特定条件是否满足来执行。

常见判断

在某些场景中,变量可能并不是每次都存在,如果直接使用未定义的变量,会导致任务报错。因此,判断变量是否已定义是一个最佳实践

变量是否定义判断

示例一

变量是否定义判断

[yuxb@controller web 11:45:48]$ cat playbook.yml ---- hosts: node1gather_facts: novars:username: yuxbtasks:- debug:msg: "var: username is defined"when: username is defined...​# 执行[yuxb@controller web 11:46:19]$ ansible-playbook playbook.yml ​PLAY [node1] ****************************************************************************************​TASK [debug] ****************************************************************************************ok: [node1] => {"msg": "var: username is defined"}​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   ​

示例2:判断受管主机是否具有相应设备。

# 看有没有sdb硬盘[yuxb@controller web 11:49:01]$ cat playbook.yml ---- hosts: node1gather_facts: yesvars:username: yuxbtasks:- debug:msg: "sdb is exist"when: ansible_devices.sdb is defined...​# 执行[yuxb@controller web 11:46:21]$ ansible-playbook playbook.yml ​PLAY [node1] ****************************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [debug] ****************************************************************************************skipping: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0​​# 看有没有sr0盘[yuxb@controller web 11:49:05]$ vim playbook.yml [yuxb@controller web 11:50:15]$ cat playbook.yml ---- hosts: node1gather_facts: yesvars:username: yuxbtasks:- debug:msg: "sr0 is exist"when: ansible_devices.sr0 is defined...​# 执行[yuxb@controller web 11:49:13]$ ansible-playbook playbook.yml ​PLAY [node1] ****************************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [debug] ****************************************************************************************ok: [node1] => {"msg": "sr0 is exist"}​PLAY RECAP ******************************************************************************************node1                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
in 和 not in 判断

用于判断某个值是否存在于一个 字符串列表字典键中

示例1:给用户添加组
[yuxb@controller web 13:50:47]$ cat playbook.yml ---- 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...​[root@node1 ~ 13:47:57]# useradd devops[root@node1 ~ 13:48:12]# id devopsuid=1091(devops) gid=1091(devops) 组=1091(devops)​# 执行[yuxb@controller web 13:50:10]$ ansible-playbook playbook.yml ​PLAY [test] *****************************************************************************************​TASK [gather user information] **********************************************************************changed: [node1]​TASK [Task run if user is in supergroups] ***********************************************************changed: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
示例二:根据主机所属组控制输出
[yuxb@controller web 13:59:02]$ cat inventory controller​[nodes]node1node2node3node4​[webs]node1 node2​[dbs]node3node4​[yuxb@controller web 13:58:56]$ cat playbook.yml ---- name: test hosts: node1 node3gather_facts: notasks:- name: install httpdyum:name: httpdstate: presentwhen: inventory_hostname in groups.webs- name: install mariadbyum:name: mariadb       state: present    when: inventory_hostname in groups.dbs ...​# 执行[yuxb@controller web 14:02:01]$ ansible-playbook playbook.yml ​PLAY [test] *****************************************************************************************​TASK [install httpd] ********************************************************************************skipping: [node3]ok: [node1]​TASK [install mariadb] ******************************************************************************skipping: [node1]changed: [node3]​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   node3                      : ok=1    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

loop 和 when 联合

  • loop:用于对一组元素逐个执行任务

  • when:用于对每一个循环项(item)进行条件判断

loopwhen 一起使用时,when 表达式会对 每个 item 单独判断

示例:当 / 文件系统可用空间大于300000000 安装 mariadb-server

解决方法:通过 ansible_facts 获取 / 文件系统可用空间

[yuxb@controller web 14:27:02]$ cat playbook.yml ---- name: Combining Loops and Conditional Play hosts: node1tasks:- name: install mariadb-server if enough space on rootyum:name: mariadb-serverstate: latestloop: "{{ ansible_mounts }}"when:- item.mount == "/"- item.size_available > 300000000...​# 执行[yuxb@controller web 14:25:52]$ ansible-playbook playbook.yml ​PLAY [Combining Loops and Conditional Play] *********************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [install mariadb-server if enough space on root] ***********************************************skipping: [node1] => (item={u'block_used': 35554, u'uuid': u'b5c926d1-b582-436b-95a9-38664b23e619', u'size_total': 1063256064, u'block_total': 259584, u'mount': u'/boot', u'block_available': 224030, u'size_available': 917626880, u'fstype': u'xfs', u'inode_total': 524288, u'options': u'rw,relatime,attr2,inode64,noquota', u'device': u'/dev/sda1', u'inode_used': 326, u'block_size': 4096, u'inode_available': 523962}) ok: [node1] => (item={u'block_used': 524536, u'uuid': u'db4466fc-68b8-4fd7-82b1-0b578187dafa', u'size_total': 53660876800, u'block_total': 13100800, u'mount': u'/', u'block_available': 12576264, u'size_available': 51512377344, u'fstype': u'xfs', u'inode_total': 26214400, u'options': u'rw,relatime,attr2,inode64,noquota', u'device': u'/dev/mapper/centos-root', u'inode_used': 34139, u'block_size': 4096, u'inode_available': 26180261})​PLAY RECAP ******************************************************************************************node1                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Ansible Handlers

Handler(处理器) 是 Ansible 中的一种特殊任务,用于在任务发生变更(changed)时才触发执行的动作。

Ansible Handlers 功能

功能说明
  • Handlers 是为 “有变更时才执行的操作” 而设计的

  • 常用于在某些操作完成后执行额外的步骤,例如:

    • 修改配置文件后重启服务

    • 更新程序后重载守护进程

    • 改变权限后重新应用策略

工作原理
  1. 任务执行后发生变更(changed)

  2. 该任务中使用 notify 通知某个 handler

  3. Handler 在 playbook 的最后统一执行一次(除非用 meta: flush_handlers 强制提前执行)

示例 在远程主机 node1部署 Web 服务器

[yuxb@controller web 14:40:17]$ cat playbook.yml ---- 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 tasks​handlers:- name: enable and restart apacheservice:name: httpdstate: restartedenabled: yes...​# 执行[yuxb@controller web 14:27:08]$ ansible-playbook playbook.yml ​PLAY [deploy web server] ****************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [install packages] *****************************************************************************changed: [node1]​TASK [install httpd-manual] *************************************************************************changed: [node1]​TASK [debug] ****************************************************************************************ok: [node1] => {"msg": "last task in tasks"}​RUNNING HANDLER [enable and restart apache] *********************************************************changed: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

处理 Errors

Ansible评估各任务的返回代码,从而确定任务是成功还是失败。通常而言, 当某个主机执行任务失败时,Ansible将立即终止该主机继续执行play,其他主机可以继续执行play。

示例:

# 环境[root@node1 ~ 14:37:44]# cp /etc/hosts /etc/myhost[root@node2 ~ 15:02:29]# rm -f /etc/myhost​[yuxb@controller web 14:41:21]$ vim playbook.yml [yuxb@controller web 15:03:54]$ cat playbook.yml ---- name: testhosts: node1,node2tasks:- name: show /etc/myhostsshell: cat /etc/myhosts- name: echo enddebug:msg: echo end​# 执行[yuxb@controller web 15:01:27]$ ansible-playbook playbook.yml ​PLAY [test] *****************************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node2]ok: [node1]​TASK [show /etc/myhosts] ****************************************************************************fatal: [node2]: FAILED! => {"changed": true, "cmd": "cat /etc/myhosts", "delta": "0:00:00.003767", "end": "2025-08-14 15:02:49.212666", "msg": "non-zero return code", "rc": 1, "start": "2025-08-14 15:02:49.208899", "stderr": "cat: /etc/myhosts: 没有那个文件或目录", "stderr_lines": ["cat: /etc/myhosts: 没有那个文件或目录"], "stdout": "", "stdout_lines": []}fatal: [node1]: FAILED! => {"changed": true, "cmd": "cat /etc/myhosts", "delta": "0:00:00.003663", "end": "2025-08-14 15:02:49.235356", "msg": "non-zero return code", "rc": 1, "start": "2025-08-14 15:02:49.231693", "stderr": "cat: /etc/myhosts: 没有那个文件或目录", "stderr_lines": ["cat: /etc/myhosts: 没有那个文件或目录"], "stdout": "", "stdout_lines": []}​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   node2                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

ignore_errors

您可能希望即使在任务失败时也继续执行play。例如,您或许预期特定任务有可能会失败,并且希望通过有条件地运行某项其他任务来恢复。

ignore_errors可以定义在以下位置:

  • 定义在 play 中,则play中所有任务忽略错误。

  • 定义在 task 中,则特定task忽略错误。

示例:

[yuxb@controller web 15:03:57]$ vim playbook.yml [yuxb@controller web 15:05:33]$ cat playbook.yml ---- 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 failed​# 执行[yuxb@controller web 15:05:16]$ ansible-playbook playbook.yml ​PLAY [test] *****************************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [install a not exist package] ******************************************************************fatal: [node1]: FAILED! => {"changed": false, "msg": "No package matching 'notexitpackage' found available, installed or updated", "rc": 126, "results": ["No package matching 'notexitpackage' found available, installed or updated"]}...ignoring​TASK [debug install result] *************************************************************************ok: [node1] => {"msg": "notexitpackage is not exit"}​PLAY RECAP ******************************************************************************************node1                      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1 

force_handlers

play中使用关键字 force_handlers,控制当play中某个任务执行失败后是否继续执行之前定义的notify,可用值yes或no(也可以是true或false),默认no(false)。

示例:

[yuxb@controller web 15:05:39]$ vim playbook.yml [yuxb@controller web 15:07:11]$ cat playbook.yml ---- name: testhosts: node1force_handlers: yestasks:- name: a task which always notifies its handlercommand: /bin/truenotify: restart the sshd- name:  fails because the package doesn't existyum:name: notexistpkgstate: latest​handlers:- name: restart the sshdservice:name: sshdstate: restarted[yuxb@controller web 15:05:45]$ ansible-playbook playbook.yml ​PLAY [test] *****************************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [a task which always notifies its handler] *****************************************************changed: [node1]​TASK [fails because the package doesn't exist] ******************************************************fatal: [node1]: FAILED! => {"changed": false, "msg": "No package matching 'notexistpkg' found available, installed or updated", "rc": 126, "results": ["No package matching 'notexistpkg' found available, installed or updated"]}​RUNNING HANDLER [restart the sshd] ******************************************************************changed: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=3    changed=2    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0        

fail 模块

fail 模块,执行该任务,任务必定 failed。

示例:

[yuxb@controller web 15:07:14]$ vim playbook.yml [yuxb@controller web 15:09:33]$ cat playbook.yml ---- name: test fail modulehosts: node1gather_facts: notasks:- debug:msg: task1- fail:- debug:msg: task3[yuxb@controller web 15:07:33]$ ansible-playbook playbook.yml ​PLAY [test fail module] *****************************************************************************​TASK [debug] ****************************************************************************************ok: [node1] => {"msg": "task1"}​TASK [fail] *****************************************************************************************fatal: [node1]: FAILED! => {"changed": false, "msg": "Failed as requested from task"}​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0        

failed_when

指明什么条件下,判定任务执行失败。

示例:

[yuxb@controller web 15:09:36]$ vim playbook.yml [yuxb@controller web 15:11:21]$ cat playbook.yml ---- name: test failed_whenhosts: node1tasks:- shell: /root/adduserregister: command_resultfailed_when: "'failed' in command_result.stdout"​​

环境准备:

[root@node1 ~ 15:15:37]# vim /root/adduser[root@node1 ~ 15:16:06]# chmod +x /root/adduser[root@node1 ~ 15:16:11]# cat /root/adduser #!/bin/bashuseradd devops &> /dev/nullif [ $? -eq 0 ];thenecho add user devops successelseecho add user devops failedfi
  • 当devops用户不存在时,shell模块跳过执行。

  • 当devops用户存在时,shell模块执行失败。

[yuxb@controller web 15:09:49]$ ansible-playbook playbook.yml ​PLAY [test failed_when] *****************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [shell] ****************************************************************************************fatal: [node1]: FAILED! => {"changed": true, "cmd": "/root/adduser", "delta": "0:00:00.005987", "end": "2025-08-14 15:16:36.903010", "failed_when_result": true, "rc": 0, "start": "2025-08-14 15:16:36.897023", "stderr": "", "stderr_lines": [], "stdout": "add user devops failed", "stdout_lines": ["add user devops failed"]}​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

changed_when

指明什么条件下,判定任务执行结果为changed。

示例1:

[yuxb@controller web 15:11:24]$ vim playbook.yml [yuxb@controller web 15:17:58]$ cat playbook.yml ---- name: changed_whenhosts: node1tasks:- name: upgrade-databaseshell: /usr/local/bin/upgrade-databaseregister: resultchanged_when: "'Success' in result.stdout"notify:- restart_databasehandlers:- name: restart_databaseservice:name: mariadbstate: restarted

环境准备:

[root@node1 ~ 15:18:25]# yum install -y mariadb-server已加载插件:fastestmirrorLoading mirror speeds from cached hostfile* base: mirrors.aliyun.com* extras: mirrors.aliyun.com* updates: mirrors.aliyun.com软件包 1:mariadb-server-5.5.68-1.el7.x86_64 已安装并且是最新版本无须任何处理[root@node1 ~ 15:18:27]# systemctl enable mariadb --now​[root@node1 ~ 15:18:27]# vim /usr/local/bin/upgrade-database[root@node1 ~ 15:18:49]# cat /usr/local/bin/upgrade-database#!/bin/bashmysql -e 'create user yuxb@"%" identified by "123";' && mysql -e 'GRANT ALL PRIVILEGES on *.* TO yuxb@"%";' && echo update database Success​[root@node1 ~ 15:19:08]# chmod +x /usr/local/bin/upgrade-database​​[yuxb@controller web 15:20:07]$ ansible-playbook playbook.yml ​PLAY [changed_when] *********************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node1]​TASK [upgrade-database] *****************************************************************************fatal: [node1]: FAILED! => {"changed": false, "cmd": "/usr/local/bin/upgrade-database", "delta": "0:00:00.037942", "end": "2025-08-14 15:20:26.929733", "msg": "non-zero return code", "rc": 1, "start": "2025-08-14 15:20:26.891791", "stderr": "ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)", "stderr_lines": ["ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)"], "stdout": "", "stdout_lines": []}​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

对于command模块和shell模块,只要命令正常执行,结果状态通常都是changed。可以通过返回码和输出结果来判定它们是否做出更改。

关键字 changed_when: false ,让任务结果状态不为changed,只能报告为ok或failed。

示例2:

[yuxb@controller web 15:18:01]$ vim playbook.yml [yuxb@controller web 15:22:09]$ cat playbook.yml ---- name: Test Whenhosts: node1gather_facts: notasks:- name: test changed_whenshell: cat /etc/redhat-releasechanged_when: false[yuxb@controller web 15:20:27]$ ansible-playbook playbook.yml ​PLAY [Test When] ************************************************************************************​TASK [test changed_when] ****************************************************************************ok: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[yuxb@controller web 15:22:20]$ vim playbook.yml [yuxb@controller web 15:24:49]$ cat playbook.yml ---- name: testhosts: node1,node2tasks:- name: show /etc/myhostsshell: cat /etc/hostschanged_when: false- name: echo enddebug:msg: echo end​[yuxb@controller web 15:22:13]$ ansible-playbook playbook.yml ​PLAY [test] *****************************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node2]ok: [node1]​TASK [show /etc/myhosts] ****************************************************************************ok: [node2]ok: [node1]​TASK [echo end] *************************************************************************************ok: [node1] => {"msg": "echo end"}ok: [node2] => {"msg": "echo end"}​PLAY RECAP ******************************************************************************************node1                      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   node2                      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Ansible block

多个任务作为block子条目,block作为多个任务整体。

Ansible 的 block 是一种语法结构,可以让你将多个任务组合在一起,并对这些任务统一地使用:

  • when 条件判断

  • become 权限提升

  • rescue 错误处理

  • always 最终操作(无论成功或失败都执行)

示例1:在所有受管节点上创建符合以下要求的逻辑卷:

  • 在research卷组中创建逻辑卷:

    • 逻辑卷名称为data

    • 逻辑卷大小为4000MiB

    • 使用ext4文件系统格式化逻辑卷

    • 将逻辑卷挂载到/data目录

    • 如果无法创建请求的逻辑卷大小,应显示错误信息:Could not create logical volume of that size 并且应改为使用大小800MiB。

  • 如果卷组research不存在,应显示错误信息:Volume does not exist

环境准备

# node1:添加一块 20G sata 硬盘[root@node1 ~ 15:36:13]# vgcreate research /dev/sdbPhysical volume "/dev/sdb" successfully created.Volume group "research" successfully created​# node2:添加一块 20G sata 硬盘[root@node2 ~ 15:37:04]# parted /dev/sdb unit MiB mklabel msdos信息: You may need to update /etc/fstab.​[root@node2 ~ 15:37:04]# parted /dev/sdb unit MiB mkpart primary 1 1025   信息: You may need to update /etc/fstab.​[root@node2 ~ 15:37:11]# vgcreate research /dev/sdb1                      Physical volume "/dev/sdb1" successfully created.Volume group "research" successfully created​

playbook.yaml内容如下:

[yuxb@controller web 16:31:17]$ cat playbook.yml ---- name: create logical volumehosts: alltasks:- name: create lvblock:- name: Create a logical volume of 4000mlvol:vg: researchlv: datasize: 4000rescue:- name: Could not create logical volume of that sizedebug:msg: Could not create logical volume of that size- name: Create a logical volume of 800mlvol:vg: researchlv: datasize: 800always:- name: Create a ext4 filesystemfilesystem:fstype: ext4dev: /dev/research/data- name: Create a directoryfile:path: /datastate: directory- name: Mount up devicemount:path: /datasrc: /dev/research/datafstype: ext4state: mountedwhen: ansible_lvm.vgs.research is defined- name: Volume does not existdebug:msg: Volume does not existwhen: ansible_lvm.vgs.research is not defined[yuxb@controller web 16:30:01]$ ansible-playbook playbook.yml ​PLAY [create logical volume] ************************************************************************​TASK [Gathering Facts] ******************************************************************************ok: [node2]ok: [controller]ok: [node3]ok: [node1]ok: [node4]​TASK [Create a logical volume of 4000m] *************************************************************skipping: [controller]skipping: [node3]skipping: [node4][WARNING]: The value 4000 (type int) in a string field was converted to u'4000' (type string). Ifthis does not look like what you expect, quote the entire value to ensure it does not change.fatal: [node2]: FAILED! => {"changed": false, "err": "  Volume group \"research\" has insufficient free space (255 extents): 1000 required.\n", "msg": "Creating logical volume 'data' failed", "rc": 5}changed: [node1]​TASK [Could not create logical volume of that size] *************************************************ok: [node2] => {"msg": "Could not create logical volume of that size"}​TASK [Create a logical volume of 800m] **************************************************************[WARNING]: The value 800 (type int) in a string field was converted to u'800' (type string). If thisdoes not look like what you expect, quote the entire value to ensure it does not change.changed: [node2]​TASK [Create a ext4 filesystem] *********************************************************************skipping: [controller]skipping: [node3]skipping: [node4]changed: [node2]changed: [node1]​TASK [Create a directory] ***************************************************************************skipping: [controller]skipping: [node3]skipping: [node4]changed: [node2]changed: [node1]​TASK [Mount up device] ******************************************************************************skipping: [controller]skipping: [node3]skipping: [node4]changed: [node2]changed: [node1]​TASK [Volume does not exist] ************************************************************************ok: [controller] => {"msg": "Volume does not exist"}skipping: [node1]skipping: [node2]ok: [node3] => {"msg": "Volume does not exist"}ok: [node4] => {"msg": "Volume does not exist"}​PLAY RECAP ******************************************************************************************controller                 : ok=2    changed=0    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0   node1                      : ok=5    changed=4    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   node2                      : ok=6    changed=4    unreachable=0    failed=0    skipped=1    rescued=1    ignored=0   node3                      : ok=2    changed=0    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0   node4                      : ok=2    changed=0    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0
# 验证[root@node1 ~ 16:33:32]# df /data/文件系统                    1K-块  已用    可用 已用% 挂载点/dev/mapper/research-data 3966144 15992 3728968    1% /data[root@node1 ~ 16:33:39]# df /data -h文件系统                   容量  已用  可用 已用% 挂载点/dev/mapper/research-data  3.8G   16M  3.6G    1% /data​

部署文件到受管主机

修改文件并将其复制到主机

file 模块

示例1:创建文件或修改文件属性

[yuxb@controller web 16:31:19]$ vim playbook.yml [yuxb@controller web 17:08:29]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- name: Touch a file and set permissionsfile:path: /tmp/testfileowner: yuxbgroup: wheelmode: 0640state: touch[yuxb@controller web 16:31:07]$ ansible-playbook playbook.yml ​PLAY [node1] ****************************************************************************************​TASK [Touch a file and set permissions] *************************************************************changed: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0​[root@node1 ~ 17:13:27]# ls -l /tmp/testfile -rw-r----- 1 yuxb wheel 0 8月  14 17:13 /tmp/testfile

示例2:删除文件

state: absent ​[yuxb@controller web 17:23:51]$ ansible-playbook playbook.yml​[root@node1 ~ 17:13:48]# ls -l /tmp/testfile ls: 无法访问/tmp/testfile: 没有那个文件或目录​

lineinfile 模块

示例1:确保文件中存在特定行

[yuxb@controller web 17:08:32]$ vim playbook.yml [yuxb@controller web 18:44:27]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- name: add linelineinfile:path: /tmp/testfileline: 'Add this line to file'state: presentcreate: yes[yuxb@controller web 17:24:19]$ ansible-playbook playbook.yml ​PLAY [node1] ****************************************************************************************​TASK [add line] *************************************************************************************changed: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0​[root@node1 ~ 17:24:26]# ls -l /tmp/testfile -rw-r--r-- 1 root root 22 8月  14 18:44 /tmp/testfile[root@node1 ~ 18:45:06]# cat /tmp/testfile Add this line to file

还可以在特定位置插入:

[yuxb@controller web 18:47:41]$ vim playbook.yml [yuxb@controller web 18:48:08]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- name: add linelineinfile:path: /tmp/testfileline: myinsertbefore: filestate: presentcreate: yes[yuxb@controller web 18:44:52]$ ansible-playbook playbook.yml​[root@node1 ~ 18:45:13]# cat /tmp/testfile myAdd this line to file

替换文本行:

[yuxb@controller web 18:49:13]$ vim playbook.yml [yuxb@controller web 18:49:42]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- name: add linelineinfile:path: /tmp/testfileline: myregexp: filestate: presentcreate: yes[yuxb@controller web 18:47:45]$ ansible-playbook playbook.yml ​[root@node1 ~ 18:47:47]# cat /tmp/testfile mymy

replace 模块

[yuxb@controller web 18:53:54]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- name: add linereplace:path: /tmp/testfilereplace: hello worldregexp: my[yuxb@controller web 18:53:22]$ ansible-playbook playbook.yml​[root@node1 ~ 18:49:49]# cat /tmp/testfile hello worldhello world​

blockinfile 模块

[yuxb@controller web 18:53:55]$ vim playbook.yml [yuxb@controller web 18:59:17]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- name: add lineblockinfile:path: /tmp/testfileblock: |line 1 in fileline 2 in filestate: present​​[yuxb@controller web 18:53:58]$ ansible-playbook playbook.yml        [root@node1 ~ 18:54:14]# cat /tmp/testfile hello worldhello world# BEGIN ANSIBLE MANAGED BLOCKline 1 in fileline 2 in file# END ANSIBLE MANAGED BLOCK

copy 模块

示例1:将控制节点上文件拷贝到受管理节点,类似于Linux中scp命令。

[yuxb@controller web 18:59:18]$ vim playbook.yml [yuxb@controller web 19:01:19]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- name: copy /tmp/testfile to remote nodecopy:src: /tmp/testfiledest: /tmp​[yuxb@controller web 19:03:34]$ echo "hello from controller" > /tmp/testfile[yuxb@controller web 19:04:04]$ ansible-playbook playbook.yml ​PLAY [node1] ****************************************************************************************​TASK [copy /tmp/testfile to remote node] ************************************************************changed: [node1]​PLAY RECAP ******************************************************************************************node1                      : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   ​[root@node1 ~ 19:02:47]# cat /tmp/testfile hello from controller​

stat 模块

stat 模块检索文件的信息,类似于Linux stat命令。参数提供检索文件属性、确定文件校验和等功能。

stat 模块返回一个包含文件状态数据的值的散列字典,允许您使用单独的变量引用各条信息。

示例:

[yuxb@controller web 19:01:20]$ vim playbook.yml [yuxb@controller web 19:04:59]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- stat:path: /tmp/testfilechecksum_algorithm: md5register: result- debug:msg: "/tmp/testfile md5 is {{ result.stat.checksum }}"- debug:var: result​[yuxb@controller web 19:05:05]$ ansible-playbook playbook.yml​PLAY [node1] ****************************************************************************************​TASK [stat] *****************************************************************************************ok: [node1]​TASK [debug] ****************************************************************************************ok: [node1] => {"msg": "/tmp/testfile md5 is 610c7f16071ca402c0cba45e4b2af437"}​TASK [debug] ****************************************************************************************ok: [node1] => {"result": {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "failed": false, "stat": {"atime": 1755169454.854485, "attr_flags": "", "attributes": [], "block_size": 4096, "blocks": 8, "charset": "us-ascii", "checksum": "610c7f16071ca402c0cba45e4b2af437", "ctime": 1755169447.1454144, "dev": 64768, "device_type": 0, "executable": false, "exists": true, "gid": 0, "gr_name": "root", "inode": 67588143, "isblk": false, "ischr": false, "isdir": false, "isfifo": false, "isgid": false, "islnk": false, "isreg": true, "issock": false, "isuid": false, "mimetype": "text/plain", "mode": "0644", "mtime": 1755169446.892412, "nlink": 1, "path": "/tmp/testfile", "pw_name": "root", "readable": true, "rgrp": true, "roth": true, "rusr": true, "size": 22, "uid": 0, "version": "1806842840", "wgrp": false, "woth": false, "writeable": true, "wusr": true, "xgrp": false, "xoth": false, "xusr": false}}}​PLAY RECAP ******************************************************************************************node1                      : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   ​

fetch 模块

从受管节点检索文件,例如将被管理节点文件先取到控制节点,然后用于分发到其他节点。诸如SSH公钥之类的文件。

示例:

[yuxb@controller web 19:05:02]$ vim playbook.yml [yuxb@controller web 19:07:28]$ cat playbook.yml ---- hosts: node1gather_facts: notasks:- name: fetch file from remote nodefetch:src: /tmp/testfiledest: /tmp[yuxb@controller web 19:05:06]$ ansible-playbook playbook.yml​[yuxb@controller web 19:08:08]$ tree /tmp/node1//tmp/node1/└── tmp└── testfile​1 directory, 1 file​

http://www.dtcms.com/a/333644.html

相关文章:

  • 分布式锁的具体实现和原理分析
  • 无线收发模块高效协同:EMS系统监控、交互、执行端同步通讯
  • SpringCloud学习
  • 现金流分析与预测提示词设计指南:从基础到复杂场景的实用框架
  • IO多路复用底层原理
  • Python中推导式和表达式
  • 基本电子元件:碳膜电阻器
  • 代码随想录二刷之“字符串”~GO
  • 集合车位租售、充电桩共享、二手市场、便民服务的家政服务平台,带源码
  • 数说故事发布全新AI产品:Social Research,免费洞察各行各业趋势,提升营销效率
  • 20250815日记
  • 智慧零碳园区——解读2025 零碳产业园区实施路径规划【附全文阅读】
  • pytorch学习笔记-模型的保存与加载(自定义模型、网络模型)
  • 大白话解析 Solidity 中的防重放参数
  • USENIX Security ‘24 Fall Accepted Papers (1)
  • 归并排序和统计排序
  • 用matlab实现的svdd算法
  • 2025年机械制造、机器人与计算机工程国际会议(MMRCE 2025)
  • gnu arm toolchain中的arm-none-eabi-gdb.exe的使用方法?
  • C#WPF实战出真汁05--左侧导航
  • 日常反思总结
  • 异步开发:协程、线程、Unitask
  • 线性代数 · 直观理解矩阵 | 空间变换 / 特征值 / 特征向量
  • 树莓派开机音乐
  • 模板引用(Template Refs)全解析2
  • CVE-2025-8088复现
  • 汽车行业 AI 视觉检测方案(二):守护车身密封质量
  • 【总结】Python多线程
  • 华清远见25072班C语言学习day10
  • 342. 4的幂