05. 变量
1. 创建合规的变量名⚓
变量名由字母、数字和下划线
组成。总是由一个字母
作为开头。
YAML 支持使用字典定义变量:
foo:
field1: one
field2: two
后续可通过两种方式引用:
foo['field1']
foo.field1
但使用点来访问会有一些问题,最好使用第一种方式。
2. 在 inventory 中定义变量⚓
3. 在 playbook 中定义变量⚓
- hosts: webservers
vars:
http_port: 80
4. 在 included 时定义变量⚓
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_prompt
和 vars_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. 变量的优先级⚓
优先级由低到高的顺序为:
- command line values (eg “-u user”)
- role defaults [1]
- inventory file or script group vars [2]
- inventory group_vars/all [3]
- playbook group_vars/all [3]
- inventory group_vars/* [3]
- playbook group_vars/* [3]
- inventory file or script host vars [2]
- inventory host_vars/* [3]
- playbook host_vars/* [3]
- host facts / cached set_facts [4]
- play vars
- play vars_prompt
- play vars_files
- role vars (defined in role/vars/main.yml)
- block vars (only for tasks in block)
- task vars (only for the task)
- include_vars
- set_facts / registered vars
- role (and include_role) params
- include params
- 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。