Skip to content

05. 变量

1. 创建合规的变量名

变量名由字母、数字和下划线组成。总是由一个字母作为开头。

YAML 支持使用字典定义变量:

foo:
  field1: one
  field2: two

后续可通过两种方式引用:

foo['field1']
foo.field1

但使用点来访问会有一些问题,最好使用第一种方式。

2. 在 inventory 中定义变量

参考《02. inventory》

3. 在 playbook 中定义变量

- hosts: webservers
  vars:
    http_port: 80

4. 在 included 时定义变量

参考《04.2 playbooks_roles》

5. 通过 Jinja2 使用变量

My amp goes to {{ max_amp_value }}

关于 Jinja2 参考 Templating (Jinja2)

Warning

ansible 允许在模板中使用 Jinja2 的循环和条件,但在 playbooks 中,我们不使用它们。

5.1 一个 YAML 缺陷

如果使用了 {{ foo }} 作为开头,就必须引用整行:

- hosts: app_servers
  vars:
       app_path: "{{ base_path }}/22"

6. 从系统中获取变量:Facts

facts 是从远程计算机获取的系统信息。你可以在 ansible_facts 变量中获取完整的信息,大部分 facts 都被加上了 ansible_ 前缀作为顶级变量。

在 play 中查看:

tasks:
  - debug: 
    var: ansible_facts

在命令行中查看收集到的信息:

ansible hostname -m setup

使用:

{{ ansible_facts['devices']['xvda']['model'] }}

6.1 关闭 facts

- hosts: whatever
  gather_facts: no

6.2 本地 facts

上述的 facts 都是通过 setup 模块获取的,但也可以自定义 facts。

在远程主机的 /etc/ansible/facts.d目录下创建以.fact结尾的文件,这些文件可以是 JSON、INI 或 返回 JSON 的可执行文件。还可以通过 play 中的关键字 fact_path 来指定扫描的自定义 facts 文件夹。

在远程主机编写文件:

[root@docker1 ~]# cat /etc/ansible/facts.d/test.fact 
[Any]
A=1
b=2

在管理端获取:

[root@dev playbooks]# ansible -i inventory dockers -m setup -a "filter=ansible_local"
192.168.75.21 | SUCCESS => {
    "ansible_facts": {
        "ansible_local": {
            "test": {
                "Any": {
                    "a": "1", 
                    "b": "2"
                }
            }
        }, 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false
}

使用:

{{ ansible_local['test']['Any']['a'] }}

Note

ansible_local 中的 key=value 行式的 key 会被转换成小写!

若你在一个 playbook 中复制了自定义的 fact,那么你需要重新运行它才能在此 play 中使用;否则只能在下一个收集 facts 的 play 中使用:

- hosts: webservers
  tasks:
    - name: create directory for ansible custom facts
      file: state=directory recurse=yes path=/etc/ansible/facts.d
    - name: install custom ipmi fact
      copy: src=ipmi.fact dest=/etc/ansible/facts.d
    - name: re-read facts after adding custom fact
      setup: filter=ansible_local

6.3 缓存 facts

该功能可以让你获取其他主机的 facts:

{{ hostvars['asdf.example.com']['ansible_facts']['os_family'] }}

若不开启“Fact Caching”,也想拥有这样的效果,那么 ansible 必须在该 play 或 在该 playbook 的更高层的 play 已经和'asdf.example.com'通信过了。

Ansible 1.8 让你在 playbook 之间运行时保存 facts,但是需要手动开启。

对于具有数千个主机的超大型基础结构,facts 高速缓存可以配置为每晚运行。少量服务器的配置可以全天临时运行或定期运行。

改变缓存 facts 的行为,可以在 ansible.cfg 中设置 gathering

  • smart - gather by default, but don't regather if already gathered
  • implicit - gather by default, turn off with gather_facts: False,默认值
  • explicit - do not gather by default, must say gather_facts: True

6.3.1 缓存插件

当前,Ansible附带了两个持久性缓存插件:redis 和 jsonfile。

6.3.1.1 redis

安装 redis:

yum install redis
service redis start
# python 的 redis 库需要从 pip 安装,因为 EPEL 中的太老了
pip install redis

ansible.cfg

[defaults]
gathering = smart
fact_caching = redis
fact_caching_timeout = 86400
# seconds
6.3.1.2 jsonfile
[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /path/to/cachedir
fact_caching_timeout = 86400
# seconds

7. 注册变量

使用 register 语句注册一个变量:

- hosts: web_servers
  tasks:
     - shell: /usr/bin/foo
       register: foo_result
       ignore_errors: True
     - shell: /usr/bin/bar
       when: foo_result.rc == 5

结果在不同的模块之间会变化。每个模块的文档都包含一个 RETURN 章节描述了模块的返回值。使用-v选项就可以看到一个任务的返回值。

与 facts 的异同:

  • 和 facts 一样,已注册的变量是主机层面的;
  • 但是只存储在内存中;
  • 已注册的变量仅在主机上对当前 playbook 的剩余部分有效;
  • 优先级不同

Warning

若某个 task 失败或跳过了,变量仍然会使用失败或跳过的状态进行注册。唯一避免变量被注册的方法是使用 tags。

8. 使用 magic 变量获取其他主机信息

无论你是否定义了变量,你都可以使用 ansible 提供的 特殊变量,包括“magic”变量,facts 和 连接变量。

magic 变量名和 environment 是保留变量,自定义的变量名不要与它们一致。

下面介绍几个常见的 magic 变量。

hostvars 使您可以访问其他主机的变量。

{{ hostvars['test.example.com']['ansible_facts']['distribution'] }}

groups 是 inventory 中的所有组及所有主机。

{% for host in groups['app_servers'] %}
   {{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }}
{% endfor %}

group_names 是当前主机所在的所有组。

{% if 'webserver' in group_names %}
   # some part of a configuration file that only applies to webservers
{% endif %}

inventory_hostname 是 inventory 中配置的主机的主机名。这在你关闭了 gather_facts 时或不想使用 ansible_hostname 时很有用。

inventory_hostname_short 用于获取主机名中的主机部分,不会包含域名。

9. 在文件中定义变量

出于隐私考虑,你可以将变量的定义放在其他文件中;或仅仅只是为了分离:

---

- hosts: all
  remote_user: root
  vars:
    favcolor: blue
  vars_files:
    - /vars/external_vars.yml

  tasks:

  - name: this is just a placeholder
    command: /bin/echo foo
---
# in the above example, this would be vars/external_vars.yml
somevar: somevalue
password: magic

10. 在命令行传递变量

除了 vars_promptvars_files,可以在命令行使用 --extra-vars (or -e) 对变量进行设置。

key=value 格式:

ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"

JSON 自符串格式:

ansible-playbook release.yml --extra-vars '{"version":"1.23.45","other_variable":"foo"}'
ansible-playbook arcade.yml --extra-vars '{"pacman":"mrs","ghosts":["inky","pinky","clyde","sue"]}'

JSON 或 YAML 文件:

ansible-playbook release.yml --extra-vars "@some_file.json"

Warning

key=value 格式会把 value 解析为字符串,若想要解析为其他类型,使用其他两种格式。

11. 变量的优先级

优先级由低到高的顺序为:

  1. command line values (eg “-u user”)
  2. role defaults [1]
  3. inventory file or script group vars [2]
  4. inventory group_vars/all [3]
  5. playbook group_vars/all [3]
  6. inventory group_vars/* [3]
  7. playbook group_vars/* [3]
  8. inventory file or script host vars [2]
  9. inventory host_vars/* [3]
  10. playbook host_vars/* [3]
  11. host facts / cached set_facts [4]
  12. play vars
  13. play vars_prompt
  14. play vars_files
  15. role vars (defined in role/vars/main.yml)
  16. block vars (only for tasks in block)
  17. task vars (only for the task)
  18. include_vars
  19. set_facts / registered vars
  20. role (and include_role) params
  21. include params
  22. extra vars (always win precedence)

Important

连接变量会覆盖配置文件、命令行和 play/role/task 的指定选项与关键字

11.1 变量的作用域

你可以根据你期望的作用域来设置变量。ansible 有三个主要的作用域:

  • Global:通过 配置文件、环境变量和命令行设置;
  • Play:每个 play 和 包含的结构,变量条目(vars; vars_files; vars_prompt),角色的默认变量及变量;
  • Host:直接关联到主机的变量,例如 inventory, include_vars, facts or registered task outputs。