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

7.Ansible自动化之-实施任务控制

7.Ansible.实施任务控制

一、环境搭建

详细步骤

# 创建名为web的工作目录(用于存放后续的Playbook、配置等文件),并进入该目录
[bq@controller ~]$ mkdir web && cd web# 创建Ansible配置文件ansible.cfg,用于设置默认运行参数
[bq@controller web]$ cat > ansible.cfg <<'EOF'
[defaults]
remote_user = bq           # 默认使用bq用户登录远程节点(无需每次指定用户名)
inventory = ./inventory    # 指定节点清单文件路径为当前目录的inventory[privilege_escalation]
become = True              # 允许执行提权操作(需要时切换到root用户)
become_user = root         # 提权的目标用户为root(获取最高权限)
become_method = sudo       # 提权方式使用sudo(Linux常用的权限提升工具)
become_ask_pass = False    # 提权时不询问密码(前提:已在远程节点配置bq用户的sudo免密)
EOF# 创建节点清单文件inventory,记录需要管理的所有节点名称或IP
[bq@controller web]$ cat > inventory <<'EOF'
controller    # 控制节点自身(也可作为被管理节点)
node1         # 受管节点1(需提前配置与控制节点的免密登录)
node2         # 受管节点2
node3         # 受管节点3
node4         # 受管节点4
EOF

编写循环任务

循环的核心作用:用一个任务处理多个相似操作(比如一次性创建 10 个用户,或安装 5 个软件),避免重复编写几乎一样的任务。Ansible 通过 loop 关键字实现循环,每次循环时用 item 变量表示当前处理的元素。

简单循环

场景:在 node1 节点上创建 jane 和 joe 两个用户,并将他们加入 wheel 组(wheel 组通常用于 sudo 权限管理)。

实验流程

  1. 先编写不含循环的 Playbook(直观感受重复任务的冗余);
  2. loop 改写 Playbook(简化任务,减少重复代码);
  3. 执行 Playbook 并验证用户是否成功创建。

详细步骤

  1. 不含循环的 Playbook(对比用)
    每次创建用户都需要写一个独立任务,用户数量越多,代码越冗余。

    ---
    - name: 不使用循环创建用户hosts: node1    # 目标节点为node1gather_facts: no # 不收集主机信息(加快任务执行速度)tasks:- name: 创建用户janeuser:name: "jane"    # 用户名groups: "wheel" # 加入wheel组state: present  # 确保用户存在(如果不存在则创建)- name: 创建用户joeuser:name: "joe"state: presentgroups: "wheel"
    ...
    
  2. loop 改写的 Playbook
    用一个任务配合 loop 列表,一次性处理多个用户。

    - name: 使用loop循环创建用户hosts: node1gather_facts: notasks:- name: 批量创建用户user:name: "{{ item }}"  # item自动引用loop列表中的当前元素(第一次是jane,第二次是joe)groups: "wheel"state: presentloop:  # 循环列表:需要创建的用户名- jane- joe
    
  3. 通过变量定义循环列表
    把循环列表存到变量中,方便后续修改(比如新增用户只需改变量)。

    - name: 用变量存储循环列表hosts: node1gather_facts: notasks:- name: 批量创建用户user:name: "{{ item }}"groups: "wheel"state: presentloop: "{{ users }}"  # 引用变量users作为循环列表vars:  # 定义变量users,值为需要创建的用户名列表users:- jane- joe
    
  4. 执行与验证

    # 执行Playbook(假设文件名为user_loop.yml)
    ansible-playbook user_loop.yml# 登录node1节点,验证jane和joe是否存在(id命令可查看用户信息)
    ssh node1 'id jane; id joe'
    
循环字典列表

场景:创建用户时,每个用户需要单独指定所属组(例如:jane 加入 wheel 组,joe 加入 root 组)。

原理:循环列表中的元素可以是 “字典”(键值对形式,类似 “姓名:张三,年龄:20”),通过 item.键名 即可引用对应的值(如 item.name 取用户名,item.groups 取所属组)。

实验流程

  1. 定义包含用户信息的字典列表(每个字典存一个用户的名称和所属组);
  2. 编写循环任务,通过 item.键名 引用字典中的具体信息;
  3. 执行 Playbook 并验证用户组配置是否正确。

详细步骤

---
- name: 循环字典列表创建用户hosts: node1gather_facts: novars:  # 定义用户信息字典列表:每个元素是一个用户的详细配置users:- name: jane    # 第一个用户:名称为janegroups: wheel # 所属组为wheel- name: joe     # 第二个用户:名称为joegroups: root  # 所属组为roottasks:- name: 批量创建用户(带组配置)user:name: "{{ item.name }}"   # 引用字典中的name键(即用户名)state: presentgroups: "{{ item.groups }}"  # 引用字典中的groups键(即所属组)loop: "{{ users }}"  # 循环变量users(字典列表)
...

验证

# 在node1上检查用户所属组(groups命令可查看用户的所有组)
ssh node1 'groups jane; groups joe'
旧版循环关键字(仅供了解)

Ansible 2.5 之前常用 with_* 格式的循环(如 with_items),现在官方推荐用 loop(功能更统一)。以下为常见旧语法示例(不建议新环境使用):

  1. with_items(类似 loop,但会自动展开嵌套列表)

    ---
    - name: 旧语法with_itemshosts: node1tasks:- name: 创建用户user:name: "{{ item }}"groups: wheelwith_items:  # 等价于loop,但会展开嵌套列表(例如[[1,2],3]会变成1,2,3)- jane- joe
    ... 
    
  2. with_together(并行遍历多个列表)

    ---
    - name: 并行遍历列表hosts: node1tasks:- name: 输出配对结果debug:msg: "数字{{ item.0 }}对应字母{{ item.1 }}"with_together:  # 按索引位置配对两个列表(索引0配索引0,索引1配索引1)- [1, 2, 3]   # 第一个列表:数字- [a, b, c]   # 第二个列表:字母
    # 输出结果:
    # "msg": "数字1对应字母a"
    # "msg": "数字2对应字母b"
    # "msg": "数字3对应字母c"
    ...
    
  3. with_sequence(生成数字序列)

    ---
    - name: 生成数字序列hosts: node1tasks:- name: 输出1-5的数字debug:msg: "{{ item }}"with_sequence:start=1  # 起始值end=5    # 结束值stride=1 # 步长(每次增加1)
    # 输出结果:1,2,3,4,5
    ...
    
Do-Until 循环(轮询等待)

场景:等待 node2 节点恢复网络连接(每隔 1 秒检测一次,最多尝试 20 次,直到 ping 通为止)。

原理until 定义 “终止条件”(满足条件则停止循环),retries 定义最大重试次数,delay 定义每次重试的间隔时间(秒)。

- name: 轮询检测node2是否可达hosts: node1  # 在node1节点上执行ping命令(检测node2)gather_facts: notasks:- shell: ping -c1 -w 2 node2  # ping node2:发送1个包(-c1),超时2秒(-w2)register: result  # 将命令执行结果保存到变量result中until: result.rc == 0  # 终止条件:命令返回码为0(rc=0表示成功,即ping通)retries: 20  # 最多重试20次delay: 1    # 每次重试间隔1秒
...
循环与注册变量(register

场景:循环执行命令并收集每个迭代的结果(例如:循环输出多条信息,然后分别查看每条的执行结果)。

---
- name: 循环执行命令并收集结果hosts: node1gather_facts: notasks:- name: 循环输出信息shell: "echo 这是第{{ item }}个元素"  # 执行echo命令,输出当前元素loop:- one- tworegister: result  # 将所有迭代的结果保存到result变量(result.results是所有结果的列表)- name: 打印所有结果debug:var: result  # 查看result的完整结构(包含每个迭代的stdout、rc等信息)- name: 提取每个迭代的输出debug:msg: "命令输出:{{ item.stdout }}"  # 从result.results中取每个迭代的stdout(命令输出)loop: "{{ result.results }}"  # 循环所有迭代的结果列表
...

编写条件任务

条件任务用于满足特定条件时才执行任务(例如:只在 CentOS 系统上安装 httpd,在 Ubuntu 上不执行;或内存大于 2G 时才部署应用)。通过 when 关键字定义条件。

基础条件判断

常见判断场景

条件类型示例说明
变量是否定义username is defined若变量 username 已定义(无论值是什么),则条件为真
等于(字符串)ansible_machine == "x86_64"若主机架构是 x86_64(64 位),则条件为真
数值比较min_memory > 256若内存大于 256MB,则条件为真
包含关系"wheel" in result.stdout若命令输出中包含 “wheel” 字符串,则条件为真
任务执行结果result is succeeded若前序任务执行成功,则条件为真

实验 1:根据布尔变量执行任务
通过 true/false 变量控制任务是否执行。

---
- name: 布尔变量控制任务执行hosts: node1gather_facts: novars:run_task: true  # 布尔变量(true:执行任务;false:不执行)tasks:- name: 条件执行的任务debug:msg: "任务执行了!"when: run_task  # 当run_task为true时,才执行该任务
...

实验 2:判断文件是否存在
通过 is file 检查路径是否为普通文件。

---
- name: 检查文件是否存在hosts: node1gather_facts: novars:file_path: /etc/hosts  # 要检查的文件路径(/etc/hosts是系统默认文件,通常存在)tasks:- name: 输出文件状态debug:msg: "{{ file_path }}是普通文件"when: file_path is file  # 当路径是普通文件时,执行该任务
...
多条件组合

通过 and/or 和括号组合多个条件,推荐用 “列表格式”(每个条件占一行,可读性更高)。

示例
只在 “系统是 CentOS” 且 “内存大于 1024MB” 时,才安装 httpd。

- name: 多条件判断hosts: node1tasks:- name: 特定系统且内存足够时安装软件yum:name: httpdstate: presentwhen:- ansible_distribution == "CentOS"  # 条件1:系统为CentOS- ansible_memtotal_mb > 1024        # 条件2:总内存大于1024MB# 只有两个条件同时满足,才会执行安装任务
...
循环与条件结合

场景:只对 “根目录(/)可用空间大于 300MB” 的主机安装 mariadb-server。

---
- name: 结合循环和条件安装软件hosts: node1tasks:- name: 根目录空间足够时安装mariadbyum:name: mariadb-serverstate: latestloop: "{{ ansible_mounts }}"  # 循环所有挂载点信息(从facts中获取,包含每个挂载点的路径、可用空间等)when: - item.mount == "/"        # 只处理根目录(/)的挂载点- item.size_available > 300000000  # 可用空间>300MB(单位:字节,300*1024*1024≈300000000)
...

Ansible Handlers(事件触发任务)

Handlers 用于当任务发生变更时执行后续操作(例如:修改 httpd 配置文件后,自动重启 httpd 服务使其生效)。

  • 特点 1:默认在所有任务执行完后运行(而非触发后立即运行)。
  • 特点 2:多次触发同一 Handler,最终只执行一次(避免重复操作,例如多次修改配置文件,只重启一次服务)。
基础用法

实验流程

  1. 安装 httpd 和 httpd-manual 软件;
  2. notify 关键字在软件安装(发生变更)时,触发 Handler 重启 httpd;
  3. 执行 Playbook 验证 Handler 是否生效(首次安装会重启,已安装则不重启)。

详细步骤

---
- name: 部署web服务并触发Handlerhosts: node1tasks:- name: 安装httpdyum:name: httpdstate: presentnotify:  # 当该任务发生变更(如httpd从无到有安装),则通知Handler- 重启并启用apache- name: 安装httpd手册yum:name: httpd-manualstate: presentnotify:  # 再次通知同一个Handler(若该任务也变更,仍只触发一次)- 重启并启用apache- debug: msg: 所有任务执行完毕(Handler还未运行)  # 验证Handler默认在任务后执行handlers:  # 定义Handler(名称需与notify中的名称一致)- name: 重启并启用apacheservice:name: httpdstate: restarted  # 重启服务(使配置生效)enabled: yes      # 设置开机自启
...

验证

  • 第一次执行:httpd 未安装,两个安装任务都会发生变更,Handler 被触发,最终执行一次(重启 httpd)。
  • 第二次执行:httpd 已安装,任务无变更,Handler 不会执行(避免无效重启)。
强制立即执行 Handler(meta 模块)

默认 Handler 在所有任务结束后运行,若后续任务依赖 Handler 的结果(例如:安装数据库后需立即启动,才能创建数据库用户),可用 meta: flush_handlers 强制立即执行已触发的 Handler。

---
- name: 立即执行Handlerhosts: node1tasks:- name: 安装mariadbyum:name: mariadb-serverstate: presentnotify:- 启动mariadb  # 安装完成后通知启动数据库- meta: flush_handlers  # 强制立即执行已触发的Handler(此时启动mariadb)- name: 创建数据库用户(依赖mariadb已启动)mysql_user:  # 该模块需要数据库服务已运行,否则会失败name: bqpassword: 123handlers:- name: 启动mariadbservice:name: mariadbstate: started
...

错误处理

Ansible 默认会在任务失败时终止整个 Playbook 的执行。通过以下方式可自定义错误处理逻辑(例如:忽略不重要的错误,或失败后执行回滚)。

忽略错误(ignore_errors

场景:任务可能失败,但不影响后续流程(例如:检测一个可能不存在的文件,即使不存在也继续执行)。

---
- name: 忽略任务错误hosts: node1tasks:- name: 尝试读取不存在的文件shell: cat /etc/not_exist  # /etc/not_exist通常不存在,该命令会失败(返回非0退出码)ignore_errors: yes  # 忽略该任务的错误,继续执行后续任务register: result    # 保存命令结果(包含失败信息)- name: 输出错误信息(如果失败)debug:msg: "文件不存在"when: result is failed  # 若前序任务失败,则执行该提示任务
...
自定义失败条件(failed_when

场景:命令执行成功(返回码为 0),但输出包含 “失败” 标识时,需判定为任务失败(例如:自定义脚本执行成功,但输出 “failed” 表示逻辑失败)。

---
- name: 自定义失败条件hosts: node1tasks:- name: 执行自定义脚本shell: /root/adduser  # 假设脚本执行成功(返回码0),但输出可能是"success"或"failed"register: resultfailed_when: "'failed' in result.stdout"  # 若输出含"failed",则强制判定为任务失败
...
块任务(block)与异常处理

block 用于将多个任务分组,结合 rescue(异常处理,任务失败时执行)和 always(始终执行,无论成功失败)实现复杂逻辑(例如:升级失败则回滚,无论成败都重启服务)。

场景:更新数据库,失败则回滚,无论成功与否都重启服务。

---
- name: 数据库更新与异常处理hosts: node1tasks:- block:  # 主任务块(正常执行的逻辑)- name: 升级数据库shell: /usr/local/bin/upgrade-db  # 执行升级脚本rescue:  # 主任务块失败时执行(异常处理/回滚)- name: 回滚数据库shell: /usr/local/bin/rollback-db  # 执行回滚脚本always:  # 无论主任务块成功或失败,都执行(收尾操作)- name: 重启数据库服务service:name: mariadbstate: restarted
...

实施 Tags(任务标签)

Tags 用于只执行 Playbook 中的部分任务(例如:Playbook 包含 “安装软件”“配置文件”“启动服务” 多个任务,可通过标签只执行 “安装软件”)。

基础用法

实验流程

  1. 给不同任务打标签(如 webserver 对应 web 服务相关任务,mailserver 对应邮件服务任务);
  2. 执行 Playbook 时,通过 --tags 指定只运行的标签,或 --skip-tags 指定排除的标签。

详细步骤

---
- name: 带标签的任务示例hosts: node1gather_facts: notasks:- name: 安装httpdyum:name: httpdstate: latesttags: webserver  # 打标签webserver(表示该任务属于web服务)- name: 安装postfixyum:name: postfixstate: latesttags: mailserver  # 打标签mailserver(表示该任务属于邮件服务)- name: 输出调试信息debug:msg: "这是通用任务"  # 无标签,默认会执行
...

执行命令

# 只执行带webserver标签的任务(即只安装httpd)
ansible-playbook tags.yml --tags webserver# 执行除mailserver标签外的所有任务(安装httpd + 输出调试信息)
ansible-playbook tags.yml --skip-tags mailserver
...
特殊标签
  • always:总是执行(除非用 --skip-tags always 明确跳过)。
  • never:默认不执行(除非用 --tags never 明确指定才执行)。
- name: 特殊标签示例hosts: node1tasks:- name: 总是执行的任务debug:msg: "我一定会执行"tags: always  # 无论是否指定其他标签,该任务都会执行- name: 默认不执行的任务debug:msg: "除非指定--tags never,否则我不执行"tags: never  # 不指定--tags never时,该任务不会执行
...

如涉及版权问题请联系作者处理!!!!!

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

相关文章:

  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘imageio’问题
  • maxwell安装部署
  • 数据结构:二叉树的高度 (Height)和节点总数 (Count of Nodes)
  • SpringCloud 07 微服务网关
  • C4 架构模型
  • 说一下事件委托
  • Qt——主窗口 mainWindow
  • Django3 - 建站基础知识点总结
  • 【JAVA 核心编程】面向对象中级:封装与访问控制
  • 获取IPv6地址的三种方式
  • 【Git系列】如何从 Git 中删除 .idea 目录
  • Rust:实现仅通过索引(序数)导出 DLL 函数的功能
  • MySQL定时任务详解 - Event Scheduler 事件调度器从基础到实战
  • 学习Stm32 的第一天
  • 基于RK3588的微电网协调控制器:实现分布式能源的智能调控与优化运行
  • git stash临时保存工作区
  • 因果知识图谱:文本预处理的革命性突破
  • pytest中使用loguru的问题及解决
  • CF2121C Those Who Are With Us
  • Week 12: 深度学习补遗:RNN与LSTM
  • Vue 与 React 深度对比:设计哲学、技术差异与应用场景
  • Zemax 中的透镜设计 - 像差理论
  • Python | 解决 matplotlib 中文乱码
  • CentOS7安装部署GitLab社区版
  • 从需求到部署全套方案:餐饮服务许可证数据可视化分析系统的大数据技术实战
  • 深入浅出全面理解贝叶斯框架(Bayesian Framework)
  • jinja2模板引擎全面解析
  • Python3字符串全面指南:从基础操作到40个内建函数实战
  • Go语言并发编程 ------ 锁机制详解
  • 深入理解 uni-app 页面导航:switchTab、navigateTo、redirectTo、reLaunch 与 navigateBack