如何在 Ansible Playbook 中使用变量

在上一篇文章中,我们讨论了什么 Ansible 剧本 是以及如何通过剧本创建和运行任务。 在本文中,我们将更进一步,学习如何在 Ansible playbook 中使用变量。

什么是 Ansible 变量?

变量 是所有编程语言中的基本概念,用于存储数据,然后在代码中使用。 同样,ansible 有存储一些值的变量,它们稍后会在 playbook 中用于不同的处理。

Ansible 支持在多个位置声明变量,例如 playbook、host_vars 和 group_vars 文件以及命令行参数。

在接下来的部分中,我们将讨论如何在不同的地方定义变量并了解变量优先级。

变量 – 键、值映射

变量可以在播放级别和任务级别使用“vars” 关键字。关键字 vars 之后,给出了带有 key 和 value 的变量。这些变量可以被 play 中的所有任务访问。

我创建了一项任务,该任务使用调试模块通过变量值打印消息。 变量应该用双花括号括起来 {{ 多变的 }}.

如何在 Ansible Playbook 中使用调试模块

- name: Print vars
  hosts: m1
  gather_facts: false

  vars:
    os_name: "PoP!_OS Desktop"
    version: "21.10"

  tasks:
    - name: Task1 - Substitute variables
      debug:
        msg: "My current desktop OS is {{ os_name }} - {{ version }}"
Key-value variable Mapping

现在要运行 playbook,请在终端中运行以下命令。

$ ansible-playbook playbook_name.yml

从下图中,您可以看到我的两个变量都被替换为它们的值 味精 打印到标准输出。

任务输出

变量 – 元素列表

您可以在变量中创建元素列表。 如果您看一下下面的定义,我已经通过两种方式创建了一个列表变量。

  • 定义项目/元素列表的标准 YAML 方式。 在这里,我将变量名称指定为 “top_linux_desktops”.
  • 用于创建项目/元素列表的 Python 语法。 在这里,我将变量名称指定为 “top_desktops”.
  vars:
    
    top_linux_desktops:
      - MXlinux
      - pop-os
      - Linux Mint
      - Manjaro
      - Fedora

    top_desktops: [MXLinux, pop-os, Linux Mint, Manjaro, Fedora]

您可以使用变量名称打印列表中的所有元素。 我创建了两个任务。 第一个任务将打印来自 top_linux_desktops 变量和第二个任务将打印元素 top_desktops 多变的。

  tasks:
    - name: Task1 - List of elements
      debug:
        msg: "My fav linux desktops are {{ top_linux_desktops }}"

    - name: Task2 - List of elements using Python syntax
      debug:
        msg: "My fav linux desktops are {{ top_desktops }}"    
元素列表

在列表中,您还可以使用其索引位置访问单个元素,类似于从 python 列表中访问元素的方式。 有两种方法可以做到这一点。

  • 使用点表示法(variable.index)
  • Python 表示法(变量[index])

我创建了两个任务。 第一个任务使用点表示法,第二个任务使用 python 表示法从第一个和第二个位置打印元素。

  tasks:    

    - name: Task3 - Accessing List element using dot notation
      debug:
        msg: "My fav linux desktops are {{ top_linux_desktops.1 }} and {{ top_desktops[2] }}"

    - name: Task4 - Accessing List element using python notation(list[i])
      debug:
        msg: "My fav linux desktops are {{ top_linux_desktops[1] }} and {{ top_desktops[2] }}"
使用索引位置打印元素使用索引位置打印元素

变量 – 字典

您可以创建一个字典对象并将其分配给变量。 这类似于 python 字典。 可以通过两种方式创建字典。

  • 定义字典的标准 YAML 语法
  • Python 字典符号

如果您可以看到下面的剧本片段,我已经创建了两个字典变量。 第一个变量 “发布信息” 遵循 YAML 语法方法和第二个变量 “new_release_info” 遵循python字典语法。

  vars:
    release_info:
      name: PoP!_OS Desktop
      version: 22.04
      release_month: April, 2022
    
    new_release_info: { name: PoP!_OS Desktop, version: 22.04, release_month: "April, 2022"}

您可以使用其键从变量或特定字典元素中获取所有值。 与列表类似,字典也遵循点和 python 表示法来打印键的值。

我创建了两个任务,第一个任务将使用 点符号 从字典中获取元素,第二个任务将使用 蟒蛇符号 抓住元素。

  tasks:

    - name: Task1 - Accessing dictionary values using its key with dot notation(dict.key)
      debug:
        msg: "{{ release_info.name }} version {{ release_info.version }} is released on {{ release_info.release_month }}"

    - name: Task2 - Accessing dictionary values using its key with python notation(dict['key'])
      debug:
        msg: "{{ new_release_info['name'] }} version {{ new_release_info['version'] }} is released on {{ new_release_info['release_month'] }}"
字典变量 - 输出字典变量 – 输出

播放与任务级别优先级

可以在任务级别和游戏级别定义变量,但在任务级别定义的变量优先于在游戏级别定义的变量。

在下面 example,我在游戏级别和任务级别创建了具有相同变量名称的变量。 现在,当我运行剧本时,它将使用任务变量名称。

  vars:
    os_name: "PoP!_OS Desktop"
    version: "21.10"

  tasks:
    - name: Task1 - Substitute variables
      vars:
        os_name: "Linux Mint"
        version: "20.03"
      debug:
          msg: "My current desktop OS is {{ os_name }} - {{ version }}"
任务与游戏 - 优先级任务与游戏 – 优先级

剧本与命令行参数优先级

您可以通过使用覆盖剧本中传递的变量 -e 旗帜。 通过的变量具有更高的优先级 -e 旗帜。

我正在运行上一节中的相同剧本,再次使用 -e 旗帜。

$ ansible-playbook 4_var_precedence.yml -e "os_name=fedora" -e "version=35"
使用命令行参数的变量使用命令行参数的变量

您可以将变量传递给 -e 标志在 Json, YAML 或者 ini 格式。

# INI FORMAT
$ ansible-playbook 4_var_precedence.yml -e "os_name=fedora" -e "version=35"

# JSON FORMAT
$ ansible-playbook 4_var_precedence.yml -e '{"os_name": "fedora"}' -e '{"version": 35}'

# YAML FORMAT
$ ansible-playbook 4_var_precedence.yml -e "{os_name: fedora}" -e "{version: 35}"

您还可以为变量创建一个单独的文件并将其传递 -e 旗帜。 语法如下。 在这里,我创建了一个名为 vars.yml 并将我所有的变量分组。 现在,当文件传递给 -e 标记所有变量都导入到剧本中。

$ ansible-playbook 4_var_precedence.yml -e @vars.yml

变量文件

您可以创建一个文件并在文件中声明所有变量,而不是在 playbook 中定义变量。 我创建了一个名为 vars.yml 并将我们在前几节中讨论过的所有变量分组到这个文件中。

文件中声明的变量文件中声明的变量

而不是使用关键字 变量,你应该使用 vars_files 在剧本中并传递文件名。 现在,当您运行 playbook 时,ansible 将从文件中选择变量。 该文件可以位于任何路径中。

剧本中的 Var_files 关键字剧本中的 Var_files 关键字
文件中定义的变量文件中定义的变量

主机和组变量

您可以在清单文件中定义主机级别和组级别变量。 您可以参考以下文章,其中我们简要讨论了如何创建主机级和组级变量。

Ansible 清单和配置文件

作为最佳实践,您不应该在清单文件中定义变量,而是可以为 host_varsgroup_vars ansible 会自动选择目录中的文件。 创建一个名为 host_vars.

$ mkdir host_vars

里面 host_vars 目录,您可以定义主机级变量,即您可以创建 INI、YAML 或 JSON 格式文件并存储特定主机的变量。 如果您查看下面的清单文件,我有两个名为“ubuntu”和“rocky”的主机,并为每个主机创建了变量文件。

小心:文件的名称应与清单文件中的主机/别名名称相同。

# Inventory file
[m1]
ubuntu ansible_host=ubuntu.anslab.com 

[m2]
rocky ansible_host=rocky.anslab.com
$ mkdir host_vars/ubuntu.yml
$ echo "message: This variable is read from host_vars/ubuntu.yml file" > host_vars/ubuntu.yml"

$ mkdir host_vars/rocky.yml
$ echo "message: This variable is read from host_vars/rocky.yml file" > host_vars/rocky.yml

我添加了一个名为 message 在两个变量文件中。 现在,如果我运行我的剧本,将从这两个文件中获取变量。

Host_vars - 变量定义Host_vars – 变量定义

同样,您也可以为组创建变量文件。 创建目录 group_vars 并根据清单文件创建一个具有组名的文件。

[m1]
ubuntu ansible_host=ubuntu.anslab.com 

[m2]
rocky ansible_host=rocky.anslab.com

[servers:children]
m1
m2

我创建了一个名为的子组 “服务器”,所以我将文件名创建为 servers.yml.

$ mkdir group_vars
$ mkdir group_vars/servers.yml
$ echo "message: This variable is read from group_vars/servers.yml file" > group_vars/servers.yml

现在,如果我运行剧本,它将读取 servers.ymlgroup_vars.

组变量组变量

小心: 如果两个都有 host_varsgroup_varsansible 将首先搜索 host_vars 定义,如果找不到,它将转到 group_vars.

魔术变量

Ansible 提供了一些内部变量,这些变量的状态在您运行 playbook 时定义。 我们可以通过剧本使用这些变量。 要获取可用特殊变量的列表,您可以参考以下链接。

Ansible 特殊变量

为了 example,有一个变量叫做 inventory_dir 它存储 playbook 使用的清单文件的绝对路径。

    - name: Magic Variables - Get inventory directory path
      debug:
        msg: "{{ inventory_dir }}"
魔术变量魔术变量

一个重要的魔法变量是 hostvars. 该变量将以 json 格式打印一些魔术变量的集合。

      - name: Magic Variables - hostvars
        debug:
          msg: "{{ hostvars }}"
HostVars 输出HostVars 输出

输出包含 str、list 和字典格式的信息。 假设我想检查我的 ubuntu 主机在哪个组中,那么我可以通过以下方式获取它。 我在这里使用 python 语法符号。

      - name: Magic Variables 
        debug:
          msg: "{{ hostvars['ubuntu']['group_names'] }}"
组名组名

并非所有魔术变量在日常操作中都有用。 查看所有魔术变量,看看哪个适合您的用例。

变数的事实

当您运行 playbook 时,ansible 将使用 setup 模块并从目标主机收集事实并将输出保存在内存中,以便可以在 playbook 中使用。 事实也称为剧本变量。

首先,了解事实输出,以便获取特定属性。 运行以下命令,该命令将收集事实输出并将其存储在文件中。

$ ansible all -m setup --tree /tmp/facts_result

将为每个主机创建单独的输出文件。 如果你看一下输出,它只是 JSON 格式的输出。

事实输出事实输出

事实输出中的属性将采用 List、Dictionary 和 AnsibleUnsafeText 格式。 下面是几个不同类型的例子。

      - name: Facts output - AnsibleUnsafeText
        debug:
          msg: "{{ discovered_interpreter_python }}"

      - name: Facts output - List
        debug:
          msg: "{{ ansible_all_ipv4_addresses }}"

      - name: Facts output - Dictionary
        debug:
          msg: "{{ ansible_python }}"
事实输出1事实输出

事实收集了大量信息,因此请花点时间查看输出结果,看看什么符合您的要求。

结论

在这篇文章中,我们讨论了什么是ansible变量以及如何在不同的地方声明变量。 声明变量时,变量优先级非常重要,本文将对此进行介绍。 我们还讨论了魔法变量及其用例。 最后,我们介绍了什么是事实以及如何将事实输出用作变量。