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_port=9090"
      
  • 变量的小技巧

    • 可以用{{ 变量名 }}在任务中调用,像插卡一样灵活
    • 支持条件判断,比如 “如果是生产环境,端口用 443;测试环境用 8080”

事实(Facts):自动收集的 “系统情报”

事实就像 Ansible 派出去的 “侦察兵”,会自动收集目标主机的信息(比如 IP 地址、操作系统、内存大小等),不用你手动问。

  • 怎么看收集到的情报?
    跑个命令让侦察兵汇报:

    ansible webservers -m setup
    

    会得到一堆信息,比如:

    • ansible_facts['os_family']:操作系统类型(比如 RedHat、Debian)
    • ansible_facts['default_ipv4']['address']:主机 IP 地址
    • ansible_facts['memory_mb']['total']:总内存(MB)
  • 在 Playbook 里用事实
    比如根据操作系统选不同的安装命令:

    - hosts: alltasks:- name: 安装nginx(Debian系统)apt: name=nginx state=presentwhen: ansible_facts['os_family'] == "Debian"- name: 安装nginx(RedHat系统)yum: name=nginx state=presentwhen: 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 的varsvars_files里定义的变量,只在当前 Play 的任务中可用
  • 提权设置:当前 Play 里的become相关配置,不会影响其他 Play
  • 事实收集gather_facts的开关状态,只控制当前 Play 是否收集主机信息

比如一个 Playbook 里有两个 Play:

- name: 管理web服务器  # Play 1hosts: webserversvars:app: "nginx"  # 这个变量只在Play 1里有效tasks:- name: 安装nginxyum: name={{ app }} state=present- name: 管理数据库服务器  # Play 2hosts: dbserversvars:app: "mysql"  # 这个变量只在Play 2里有效tasks:- name: 安装mysqlyum: name={{ app }} state=present

这里两个 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: directory

2. 单独放变量文件(更整洁)

如果变量太多,就像东西太多需要用抽屉分类收纳。把变量写在单独的 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.ini"line: "db_host = {{ db_host }}"

3. 命令行临时声明(应急用)

就像临时从口袋里掏出个备用物品,适合临时修改变量值,不用改 Playbook 本身。用-e参数传递:

# 临时把端口改成9090运行
ansible-playbook deploy.yml -e "app_port=9090"

4. 主机 / 组变量(按目标分类)

如果不同主机需要不同变量(比如 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: "blog"port: 8080
    

    引用时用

    {{ app.name }}
    
    {{ app.port }}
    

简单说,vars声明就是给 Ansible 提前 “备课”—— 把需要用的信息整理好,用的时候直接喊名字就能调出来,不用重复写死,既灵活又好维护~

Host scope

主机变量应用于主机和主机组。主机变量优先级高于主机组变量。

主机清单中定义

较旧的做法是直接在清单文件中定义。不建议采用,但仍可能会遇到。

[servers]
node1 user=laoma
node2[servers:vars]
user=laowang
目录分层结构定义

在项目目录中创建如下目录:

  • group_vars,定义主机组变量。目录中文件名可以直接使用 主机组名 或者 主机组名.yaml

  • host_vars,定义主机变量。目录中文件名可以直接使用 主机名 或者 主机名.yaml

主机连接特殊变量

详情参考:主机连接特殊变量。

  • ansible_connection,与主机的连接类型,可以是 smart、ssh 或 paramiko。默认为smart。

  • ansible_host,要连接的主机的名称,默认值就是主机清单名称。

  • ansible_port,ssh 端口号,如果不是 22。

  • ansible_user,ssh 用户名。

  • ansible_ssh_pass,要使用的 ssh 密码。切勿以纯文本形式存储此变量,始终使用保管库。

  • ansible_ssh_private_key_file,ssh 使用的私钥文件。如果使用多个密钥并且您不想使用 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  # rc=0表示命令成功(进程存在)- name: 如果进程不存在,就启动nginxservice:name: nginxstate: startedwhen: nginx_status.rc != 0  # rc≠0表示命令失败(进程不存在)

这里nginx_status.rc是命令的返回码(rc即 return code),0 代表成功,非 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报告的主机名称不同。

    [laoma@controller web]$ ansible node1 -m debug -a 'var=inventory_hostname'
    node1 | SUCCESS => {"inventory_hostname": "node1"
    }
    
  • group_names,列出当前受管主机所属的所有主机组。

    [laoma@controller web]$ ansible node1 -m debug -a 'var=group_names'
    node1 | SUCCESS => {"group_names": ["webs"]
    }
    
  • groups,列出清单中的所有组,以及组中含有的主机。

    [laoma@controller web]$ ansible node1 -m debug -a 'var=groups'
    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 = explicit

play中设置

---
- name: Fact dumphosts: node1gather_facts: no

即使关闭以后,也可以随时使用setup模块收集facts。

实施任务控制

编写循环任务

利用循环,管理员无需编写多个使用同一模块的任务。例如,确保存在五个用户,不需要编写五个任务,而是只需编写一个任务来对含有五个用户的列表迭代。

Ansible支持使用 loop 关键字对一组项目迭代任务。您可以配置循环以利用列表中的各个项目、列表中各个文件的内容、生成的数字序列或更为复杂的结构来重复任务。

简单循环

简单循环对一组项目迭代任务。loop关键字添加到任务中, 将应对其迭代任务的项目列表取为值。循环变量item保存每个迭代过程中使用的值。

示例:

---
- 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循环改写:

- name: test loophosts: node1gather_facts: notasks:- name: add usersuser:name: "{{ item }}"groups: "wheel"state: 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都可通过条件来进行测试。可以使用比较字符串、数字数据和布尔值的运算符。

用例:

  1. 定义变量min_memory,判断被管理节点可用内存是否满足该值。
  2. 捕获命令输出,判定task是否执行完成,以便决定是否进行下一步操作。
  3. 被管理节点上收集到的网络facts,判定是否适合哪种绑定(bonding或者trunking)。
  4. 根据CPU的数量决定如何调优web服务器。
  5. 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_available
memory_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 task"when: 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 defined"when: 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 file"when: file_name is file
任务执行结果判断
  • succeeded,通过任务的返回信息判断,任务执行成功返回真。
  • failed,通过任务的返回信息判断,任务执行失败返回真。
  • changed,通过任务的返回信息判断,任务执行状态为changed返回真。
  • skipped,通过任务的返回信息判断,任务没有满足条件跳过执行,返回真。

示例:

---
- hosts: node1gather_facts: novars:doshell: "yes"tasks:- 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在任务中通知(notify)Handlers

- 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
执行逻辑:
  1. 执行 “修改 Nginx 配置文件” 任务:
    • 如果配置文件有变化(changed: true),则标记 “重启 Nginx 服务” 这个 Handler 为 “待执行”
    • 如果配置文件无变化(changed: false),则不通知 Handler
  2. 当 Play 中所有任务执行完毕后,Ansible 会统一执行所有被标记为 “待执行” 的 Handlers。

Handlers 的特点

  1. 延迟执行:Handlers 不会在被通知后立即执行,而是等到当前 Play 中所有任务都执行完才统一运行。

  2. 幂等性保障:即使多个任务通知同一个 Handler,它也只会执行一次。例如:

    tasks:- name: 修改配置文件Acopy: src=a.conf dest=/etc/nginx/notify: 重启Nginx服务- name: 修改配置文件Bcopy: src=b.conf dest=/etc/nginx/notify: 重启Nginx服务
    

    无论两个任务是否都触发了变更,“重启 Nginx 服务” 只会执行一次,避免多次重启。

  3. 名称唯一: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 end
ignore_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 failed
fail 模块

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"

环境准备:

[root@node1 ~]# cat /root/adduser 
#!/bin/bash
useradd devops &> /dev/null
if [ $? -eq 0 ];thenecho add user devops success
elseecho add user devops failed
fi
[root@node1 ~]# 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 failed"when: "'failed' in command_result.stdout"
changed_when

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

示例1:

- 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919180.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919180.shtml
英文地址,请注明出处:http://en.pswp.cn/news/919180.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32--寄存器与标准库函数--基本定时器

目录 前言 基本定时器概念 定时时间 定时器时钟确定 倍频锁相环被正确配置为168MHz 定时器的库函数操作 代码 定时器的寄存器操作 代码 寄存器 后言 前言 使用平台:STM32F407ZET6 使用数据手册&#xff1a;STM32F407数据手册.pdf 使用参考手册&…

PCA 实现多向量压缩:首个主成分的深层意义

PCA 实现多向量压缩 第一个主成分(components_[0])正是数据协方差矩阵中最大特征值对应的特征向量。 ,layer_attention_vector[layer] 被赋值为 pca.components_[0],这确实是一个特征向量,具体来说是 PCA 分解得到的第一个主成分(主特征向量)。 关于它的维度: 假设 c…

网络常识-DNS如何解析

DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;是互联网的“地址簿”&#xff0c;负责将人类易记的域名&#xff08;如www.example.com&#xff09;转换为计算机可识别的IP地址&#xff08;如192.168.1.1&#xff09;。其工作流程可以简单理解为“从域名到…

Java中 23 种设计模式介绍,附带示例

文章目录设计模式六大原则设计模式分类1、创建型模式&#xff08;Creational Patterns&#xff09;2、结构型模式&#xff08;Structural Patterns&#xff09;3、行为型模式&#xff08;Behavioral Patterns&#xff09;一、创建型模式&#xff08;Creational Patterns&#x…

嵌入式开发入门——电子元器件~电磁继电器、蜂鸣器

文章目录电磁继电器定义关键参数实物蜂鸣器实物内部结构分类关键参数电磁继电器 定义 概述&#xff1a;电磁继电器是利用电磁感应原理职称的一种电磁开关&#xff0c;他能通过&#xff1a;低电压、低电流的电路&#xff0c;来控制高电压、高电流的电路。 关键参数 线圈电压…

ROS2基础

1.helloworld案例1.创建功能包&#xff08;C&#xff09;终端下&#xff0c;进入ws00_helloworld/src目录&#xff0c;使用如下指令创建一个C 功能包:ros2 pkg create pkg01_helloworld_cpp --build-type ament_cmake --dependencies rclcpp --node-name helloworld执行完毕&a…

Python爬虫实战:研究pygalmesh,构建Thingiverse平台三维网格数据处理系统

1. 引言 1.1 研究背景 在数字化浪潮席卷全球的当下,三维建模技术已成为连接虚拟与现实的核心纽带,广泛渗透于工程设计、地理信息系统(GIS)、虚拟现实(VR)、增强现实(AR)、医学影像等关键领域。例如,在建筑工程中,BIM(建筑信息模型)技术依赖高精度三维网格实现施工…

开发者说 | EmbodiedGen:为具身智能打造可交互3D世界生成引擎

概述 具身智能的发展离不开高质量、多样化的可交互3D仿真环境。为突破传统构建方式的瓶颈&#xff0c;我们提出了EmbodiedGen&#xff0c;一个基于生成式AI技术的自动化3D世界生成引擎&#xff0c;助力低成本、高效率地创建真实且可交互的3D场景。用户仅需输入任务定义或场景图…

GitHub Copilot:AI编程助手的架构演进与真实世界影响

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 1. 技术背景与核心架构 GitHub Copilot 是由 GitHub 与 OpenAI 联合开…

PDF OCR + 大模型:让文档理解不止停留在识字

在企业数字化的实际场景中&#xff0c;PDF OCR 已经很普遍了&#xff1a;从扫描件提取文本、表格到生成可搜索 PDF。但这类技术往往停留在"把图片变成文字"&#xff0c;对文档背后的语义、逻辑、业务价值理解不足。 而当 OCR 遇上大语言模型&#xff08;LLM&#xff…

半敏捷卫星观测调度系统的设计与实现

半敏捷卫星观测调度系统的设计与实现 摘要 本文详细阐述了一个基于Python的半敏捷卫星观测调度系统的设计与实现过程。系统针对半敏捷卫星特有的机动能力限制&#xff0c;综合考虑了地面目标观测需求、卫星资源约束、能源管理等多重因素&#xff0c;提出了一种混合启发式算法解…

软件测试中,常用的抓包工具有哪些?抓包的原理是什么?

回答重点在软件测试中&#xff0c;常用的抓包工具主要有&#xff1a;1&#xff09;Fiddler2&#xff09;Wireshark3&#xff09;Charles4&#xff09;Postman&#xff08;它的拦截器功能也可以用于抓包&#xff09;5&#xff09;tcpdump抓包的原理大致是通过安装在本地的抓包工…

Cesium学习(二)-地形可视化处理

Cesium地形可视化是其核心功能之一&#xff0c;允许开发者在3D地球中展示真实的地形数据。以下是关于Cesium地形可视化的详细处理方法&#xff1a; 文章目录1. 启用地形可视化基本地形加载自定义地形提供者2. 地形相关操作地形高度采样地形夸张效果3. 地形可视化设置地形照明效…

《告别 if-else 迷宫:Python 策略模式 (Strategy Pattern) 的优雅之道》

《告别 if-else 迷宫:Python 策略模式 (Strategy Pattern) 的优雅之道》 大家好,我是你的朋友,一位与 Python 代码相伴多年的开发者。在我们的编程生涯中,几乎都曾与一种“代码怪兽”搏斗过,它就是那冗长、复杂、牵一发而动全身的 if-elif-else 结构。 每当一个新的需求…

Redis--day7--黑马点评--优惠券秒杀

&#xff08;以下内容全部来自上述课程&#xff09;优惠券秒杀 1. 全局唯一ID 每个店铺都可以发布优惠券:当用户抢购时&#xff0c;就会生成订单并保存到tb voucher order这张表中&#xff0c;而订单表如果使用数据库自增ID就存在一些问题: id的规律性太明显受单表数据量的限制…

Vue 与 React 深度对比:设计哲学、技术差异与应用场景

一、核心设计理念对比 特性 Vue React 设计目标 渐进式框架,降低学习曲线 构建大型应用,保持灵活性 设计哲学 “约定优于配置” “配置优于约定” 核心思想 响应式数据绑定 函数式编程 + 虚拟DOM 模板语言 HTML-based 模板 JSX(JavaScript XML) 状态管理 内置响应式系统 依…

软件开发 - foreground 与 background

foreground 与 background 1、foreground词性含义n.前景&#xff1b;最突出的位置.v使突出&#xff1b;强调# 例词in the 【foreground】&#xff08;在最显眼的位置&#xff09;【foreground】 task&#xff08;前台任务&#xff09;【foreground】 color&#xff08;前景色&a…

深度学习——03 神经网络(2)-损失函数

2 损失函数 2.1 概述作用&#xff1a;衡量模型预测结果&#xff08;y^\hat{y}y^​&#xff09;和真实标签&#xff08;yyy&#xff09;的差异&#xff0c;差异越大&#xff0c;说明模型参数“质量越差”&#xff08;需要调整&#xff09;&#xff1b;本质&#xff1a;深度学习训…

【大模型微调系列-04】 神经网络基础与小项目实战

【大模型微调系列-04】 神经网络基础与小项目实战&#x1f4a1; 本章目标&#xff1a;通过构建一个能识别手写数字的AI模型&#xff0c;让你真正理解神经网络是如何"学习"的。2-3小时后&#xff0c;你将拥有第一个自己训练的AI模型&#xff01;4.1 理论讲解&#xff…

JavaWeb前端(HTML,CSS具体案例)

前言 一直在学习B站黑马程序员苍穹外卖。现在已经学的差不多了&#xff0c;但是我学习一直是针对后端开发的&#xff0c;前端也没太注重去学&#xff08;他大部分都给课程资料嘻嘻&#x1f92a;&#xff09;&#xff0c;但我还是比较感兴趣&#xff0c;准备先把之前学JavaWeb&…