1
2
3
4
5
作者:李晓辉

微信联系:Lxh_Chat

联系邮箱: 939958092@qq.com

在 Ansible 里,变量是让任务、角色和 playbook 更灵活、可重复使用的关键。它们还可以帮助你根据不同系统之间的配置差异来做调整。你可以在好几个地方设置变量哦,比如:

  • 在角色的 defaults/main.ymlvars/main.yml 文件里。
  • 在清单文件中,作为主机变量或组变量。
  • 在 playbook 或清单的 group_vars/host_vars/ 目录下的变量文件里。
  • 直接在 play、角色或任务中定义变量。

不过我们要注意,不要到处放变量,避免后期搞不清,我们最好遵守下面的基本原则。

变量管理的基本原则

1. 保持简单

尽量将变量在一个地方集中定义

2. 不要重复

如果一个组里多个主机都有一样的变量,考虑group_vars目录的方式定义

3. 在可读的⼩⽂件中组织变量

如果有⼀个包含许多主机组和变量的⼤型项⽬,则应将变量定义拆分成多个⽂件,可以使⽤⼦⽬录,⽽不使⽤ host_vars/ 和 group_vars/ ⽬录中的⽂件

例如,有⼀个⽤于组 webserver 的 group_vars/webserver/firewall.yml的⽂件,其中仅包含与防⽕墙配置相关的变量。 该⽬录还可以包含⽤于配置组中服务器的其他组件的其他组变量⽂件

变量合并和优先级

如果你在不同地方设置了同一个变量,Ansible 会根据优先级规则来决定使用哪个值。这个规则的意思是,优先级越高的值会覆盖优先级低的值。下面是优先级从低到高的排序:

  1. 在命令行中用 ansible-navigator run 提供的选项优先级最低,但如果你用 -e 参数传递变量,这个优先级会比较高。例如,--user 可以设置远程用户,但 ansible_user 会覆盖它。

  2. 角色的 defaults/main.yml 文件中设置的变量优先级也较低。

  3. 主机和组的变量优先级:主机变量优先级高于组变量。所以最好不要到处乱设置变量,免得优先级混乱。

    组变量的优先级从低到高是:

    • 直接在清单文件或动态清单脚本中设置
    • group_vars/all 中设置的
    • 在 playbook 中的 group_vars/all 设置的
    • 在清单中其他组的 group_vars/ 目录下设置的
    • 在 playbook 中其他组的 group_vars/ 设置的

    主机变量的优先级从低到高是:

    • 直接在清单文件或动态清单脚本中设置
    • host_vars/ 目录中设置的
    • 在 playbook 中的 host_vars/ 设置的
    • 主机事实和缓存事实
  4. Play 变量优先级:Play 的变量优先级高于主机、组变量或角色的默认值。优先级从低到高排序是:

    • 在 Play 的 vars 部分设置的
    • 通过 Play 的 vars_prompt 提示用户输入的
    • 通过 Play 的 vars_files 部分加载的外部文件
    • 由角色设置的 rolename/vars/main.yml 中的变量
    • 在当前块(block)的 vars 部分设置的
    • 在当前任务的 vars 部分设置的
    • 通过 include_vars 动态加载的
    • 通过 set_factregister 记录任务结果设置的变量
    • 在 Play 的 role 部分加载时或通过 include_role 加载的角色变量
    • 通过 include_tasks 加载的任务中的变量
  5. 额外的变量:如果你用 ansible-navigator run 命令的 --extra-vars(或 -e)选项设置了额外变量,这些变量的优先级总是最高的。

总结来说,最重要的是:你在命令行 -e 传的变量最有话语权,其他变量会根据优先级来决定最终的值!

将变量与清单分开放

将变量从清单文件中转移到单独的变量文件是一个很好的做法,这样能让你的配置更加清晰且易于管理。每个主机组可以有自己专属的变量文件,这些文件就以主机组的名字命名,并包含该组的相关变量定义。

比如说,如果你有一个名为 web_servers 的主机组,那么你可以为它创建一个名为 web_servers.yml 的变量文件,文件里可以放置这个组的所有变量。这样做的好处是:

  1. 清晰明了:每个组的变量都在一个地方,便于查找和管理。
  2. 更易于维护:每个组都有独立的变量文件,修改变量时不会影响其他组。
  3. 提升可重复使用性:你可以轻松地重用这些变量文件,避免重复定义。

举例来说,你可以在group_vars中,创建不同的文件:

1
2
3
4
group_vars/
├── db_servers.yml
├── lb_servers.yml
└── web_servers.yml

在多样化的和大型环境中,为了保持良好的组织结构,可以在 group_vars/ 目录下为每个主机组创建子目录。这种方式不仅能让你的变量更加有序,而且可以根据主机组来合理地组织不同的配置文件。

Ansible 会自动分析这些子目录中的所有 YAML 文件,并根据它们的父目录自动将变量与对应的主机组关联。这样一来,所有与该组相关的变量就会在一个集中的地方进行管理,清晰且易于扩展。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
group_vars/
├── all/
│ └── common.yml
├── db_servers/
│ ├── mysql.yml
│ └── firewall.yml
├── lb_servers/
│ ├── firewall.yml
│ ├── haproxy.yml
│ └── ssl.yml
└── web_servers/
├── firewall.yml
├── webapp.yml
└── apache.yml

使⽤特殊清单变量

ansible_connection

⽤于访问受管主机的连接插件。 默认情况下,Ansible 将 ssh 插件⽤于除 localhost 之外的所有主机;对于后者,Ansible 使⽤ local 插件。

ansible_host

实际 IP 地址或完全限定域名

ansible_port

Ansible ⽤于连接受管主机的端⼝

ansible_user

Ansible ⽤于连接受管主机的⽤⼾

ansible_become_user

Ansible 连接到受管主机后,将使⽤ ansible_become_method(默认情况下为 sudo)切换
到此⽤⼾

ansible_python_interpreter

Ansible 应在受管主机上使⽤的 Python 可执⾏⽂件的路径

优化清单主机名

可以给清单主机名分配任意名称,然后使用刚才的特殊变量指定具体的IP等信息,比如,下面的主机名就是给了一个对我有意义但和实际并不相符的名称

1
2
3
4
5
6
7
8
9
10
11
12
web_servers:
hosts:
webserver_1:
ansible_host: server100.example.com
webserver_2:
ansible_host: server101.example.com
webserver_3:
ansible_host: server102.example.com
lb_servers:
hosts:
loadbalancer:
ansible_host: server103.example.com

使⽤变量来识别当前主机

在运行 play 的时候,您可以使用几个变量和事实来帮助识别当前正在执行任务的受管主机的名称:

  • inventory_hostname:这是当前正在处理的受管主机的名称,它来自于清单文件。

  • ansible_host:这个变量是用来连接到受管主机的实际 IP 地址或主机名。

  • ansible_facts[‘hostname’]:这是从受管主机收集到的短格式(非限定)主机名,作为事实的一部分。

  • ansible_facts[‘fqdn’]:这是从受管主机收集到的完全限定域名 (FQDN),也作为事实的一部分。