变量的命名应该符以下合两个规范:html
例如:host_port、HOST_PORT、var5是符合命名规范的,foo-port、 foo port、foo.port 、12都不符合命名规范。node
变量的定义一般是YAML形式,在inventory host文件中也可使用INI形式。python
ansible变量不只能够支持简单的key=value格式,并且也支持更复杂数据结构,例如字典类型等。c++
变量的做用域能够分为四种:redis
接下来咱们根据变量的做用域,详细分析下ansible变量的定义、使用和调用顺序。shell
ansible配置文件会定义一些变量信息,主要是对执行环境、链接信息变量的定义。json
例如inventory目录、library目录、与目的主机链接方式、越权信息、链接超时时间等等。缓存
在ansible链接到目的主机时,会以non-login shell登录到目的主机,此时目的主机的/etc/bashrc和~/.basrc的环境变量会被加载,因此这两个文件中设置的环境变量会做用于playbook全局。bash
咱们能够在执行playbook的命令行指定变量,须要注意的是,命令行指定的变量在全部其余变量中优先级是最高的。也就是说若是命令行指定的变量和其余地方指定的变量有冲突时,那么ansible最终会采用命令行定义的变量。数据结构
命令行指定变量示例以下:
ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"
vars语句定义全局变量
咱们能够在playbook中使用「vars」语句定义变量,该变量做用于整个play。
例如:
---
# inventory/playbooks/test.yaml - hosts: node1 vars: http_port: 80
上面示例中中「http_port」是一个做用于整个play的变量,对这个play里的tasks、roles、import、include等等之下定义的task均生效。
引用变量文件
除了将变量写在playbook中,咱们也能够将变量放在一个单独的YAML文件中,经过「vars_files」语句来导入。
「vars_files」变量只能做用于play全局,不能在某个task中单独被引用。「vars_files」参数可使用系统绝对路径或playbook文件的相对路径。
举个🌰:
咱们在playbooks目录下建立一个vars-files.yaml文件:
--- # playbooks/vars-files.yaml age: 100
在playbook中使用vars_files语句引用该变量文件:
--- # playbooks/test.yaml - hosts: node1 vars_files: ./vars-files.yaml tasks: - debug: msg: "My age is {{ age }}"
default变量位于roles/defaults/main.yml文件中,该变量做用于role里的全部play,一般做为模版或模块里的默认参数。
default变量与ansible filter变量 「{{ some_variable | default("some_value") }}」具备一样的做用,在全部ansible变量中优先级最低。
dependencies变量位于roles/meta/main.yaml文件中,该变量与「role」语句同级缩进,做用于自己的role和dependencies role。
举个🌰:
role_A 和 role_B定义了相同的task,debug出「age」变量:
--- # tasks file for role_B - debug: var: age
--- # tasks file for role_B - debug: var: age
role_A/meta/main.yaml定义role_A依赖role_B,并指定「age」变量等于26:
--- dependencies: - role: role_B vars: age: 27
写playbook,引用role_A:
--- # playbooks/test.yaml - hosts: node1 roles: - role: role_A
执行结果以下:
➜ lab-ansible ansible-playbook playbooks/test.yaml PLAY [node1] ******************************************************************************************** TASK [Gathering Facts] ********************************************************************************** ok: [node1] TASK [role_B : debug] *********************************************************************************** ok: [node1] => { "age": 27 } TASK [role_A : debug] *********************************************************************************** ok: [node1] => { "age": 27 } PLAY RECAP ********************************************************************************************** node1 : ok=3 changed=0 unreachable=0 failed=0
输出结果显示,dependencise变量「age」在role_A和role_B均生效。
vars变量位于roles/vars/main.yml,该变量做用于role里的全部模块。一般将除了默认变量的其余的变量放在这个文件内。
register方法可以将一个task的执行结果注册为一个变量。书写格式要与模块名称对齐,该变量做用于整个play。
一般register变量和when语句联合使用,以达到知足某些条件才运行task的目的。
with modules
咱们能够为某个模块定义变量,该变量做用于这个task。
举个🌰,示例中为「debug」模块定义了「name」和「age」变量并在「msg」参数后使用了这两个变量:
--- # playbooks/test.yaml - hosts: node1 tasks: - debug: msg: "My name is {{ name }} and I'm {{ age }} years old" vars: name: Maurice age: 27
with import*/include*
在使用import_playbook、import_tasks、include_tasks、import_role、include_role时能够在import*/include*的同级位置指定变量,该变量做用于导入的全部play。
使用import_role举个🌰:
playbook导入role_A,并定义变量「age」,这样role_A内的play就可使用「age」变量了:
--- # playbooks/test.yaml - hosts: node1 tasks: - import_role: name: role_A vars: age: 1000
其余import*/include*的语句使用方法相似,只要记住缩进与import*/include*语句保持一致便可。
with roles
在playbook中使用roles语句来导入role时也能够定义变量,该变量做用于role包含的全部play。
举个🌰:
playbook使用roles语句导入role_A,并定义变量「age」:
--- # playbooks/test.yaml - hosts: node1 roles: - role: role_A vars: age: 1000
经过上面两个示例咱们发现,roles和import_role语句定义变量写法上很类似,其实import_role和include_role是新版本的语法,功能上彻底能够代替roles语句。若是你使用的ansible版本>=2.4,建议使用include_role和import_role语句。
指的是在tasks/main.yaml或handlers/main.yaml内书写task时指定的变量,该变量做用于某个task,这个变量类型和上述章节中「5.1playbook中的变量—with modules」相似,这里就再也不举例说明。
ansible中有个特殊的变量,这些变量不是开发者定义的,而是ansible根据目的主机环境信息自动收集的,称之为fact变量。
fact变量很实用,和「when」语句配合使用会让你的代码更加健壮。
举个🌰,若是当前的操做系统为「RedHat」类型,则经过yum安装须要的软件包:
--- # playbooks/test.yaml - hosts: node1 tasks: - yum: name: firewalld state: present when: ansible_os_family == 'RedHat'
在执行playbook时,咱们发如今「Gathering Facts」步骤时总会卡住一会,若是定义的play多了,会很是耗时。其实这步就是ansible在收集目的主机的facts信息。
若是咱们定义的playbook中并无使用到fact变量,那么咱们能够选择将其关闭,只需添加「gather_facts: false」便可。
若是必需要使用facts信息,咱们能够将fact信息缓存到redis服务或本地json文件中,这样当咱们第二次执行playbook时,ansible就会读取缓存信息,从而加快运行速度。
假设本地redis服务正常运行,咱们只需更改ansible配置文件便可达到缓存fact的目的。
redis缓存:
[defaults] gathering = smart fact_caching = redis fact_caching_timeout = 86400
json文件缓存:
[defaults] gathering = smart fact_caching = jsonfile fact_caching_connection = /path/to/cachedir fact_caching_timeout = 86400
关于主机和主机组变量,咱们在「ansible基础-安装与配置:3.1 主机与主机组」中有介绍,当时介绍了组和主机变量的定义方法、变量的分离、优先级等知识点。其实主机变量的知识点不复杂,这里作下总结。主机变量是指做用在某一台主机上的变量。位置能够与主机定义写在一块儿也能够写在inventory/host_vars/a_host_name.yaml文件里。一般前者使用使用INI格式,后者使用YAML格式。这里要注意一下YAML的语法,在「:」后面要留有一个空格。若是组变量和主机变量都对同一个主机定义了相同的变量,那么ansible最终会采用主机变量而放弃组变量。主机变量示例:INI格式:
# inventory/hosts [nodes] node1 node2 node3 [nodes:vars] http_port=80 database_port=3306
转换为YAML格式:
--- # inventory/hosts nodes: hosts: node1: node2: node3: vars: http_port: \'80\'
database_port: \'3306\'
不含节点定义的主机变量定义:
--- # inventory/host_vars/node1.yaml http_port: \'80\'
database_port: \'3306\'
和主机变量相似,组变量做用于主机组,即多个主机。位置能够与主机组定义写在一块儿也能够写在inventory/group_vars/a_group_name.yaml文件里。一般前者使用使用INI格式,后者使用YAML格式。
INI格式:
# inventory/hosts [nodes] node1 node2 node3 [nodes:vars] http_port=80 database_port=3306
转换为YAML格式:
--- # inventory/hosts nodes: hosts: node1: node2: node3: vars: http_port: \'80\'
database_port: \'3306\'
定义一个字典变量,位于inventory/group_vars/nodes.yaml:
--- # 一位职工记录 name: Maurice job: Developer skill: Develop program employed: True foods: - Apple - Orange languages: shell: Elite python: Elite c++: Lame
将上面示例转换为一行:
--- # 一位职工记录 {name: Maurice,job: Developer,skill: Develop program,employed: True,foods: [\'Apple\',\'Orange\'],languages: {shell: Elite,python: Elite,c++: Lame}}
很显然,YANL格式分行来写会更加直观和美观。
经过上面描述,咱们发现ansible可以定义变量的地方真的是太多太多了,我我的以为ansible变量这块的设计有点复杂和冗余。
在生产中,咱们要读懂别人的代码或者让本身的代码更加健壮,就必须清楚的知道ansible最终会使用哪一个变量。这里我总结下ansible的调用变量的顺序,当小伙伴迷茫时能够回来看下这个列表(越靠后变量优先级越高,越会被ansible采用)
一个变量被定义后,在它的做用域内的play能够直接调用,例如:
咱们定义了整个play做用域的变量「name」和「age」,那么在以后的两个debug模块内能够直接调用。
--- # playbooks/test.yaml - hosts: node1 vars: name: Maurice age: 27 tasks: - debug: msg: "My name is {{ name }} and I'm {{ age }} years old"
- debug: msg: "Hello Maurice" when: name == 'Maurice'
输出结果展现:
➜ lab-ansible ansible-playbook playbooks/test.yaml PLAY [node1] ******************************************************************************************** TASK [Gathering Facts] ********************************************************************************** ok: [node1] TASK [debug] ******************************************************************************************** ok: [node1] => { "msg": "My name is Maurice and I'm 27 years old" } TASK [debug] ******************************************************************************************** ok: [node1] => { "msg": "Hello Maurice" } PLAY RECAP ********************************************************************************************** node1 : ok=3 changed=0 unreachable=0 failed=0
变量被频繁使用的还有roles里的模版,位于roles/template/xxx.j2,该模版使用python的Jinja2模版语法。
roles模版多被用于生成服务的配置文件,因此会调用不少的变量。
示例以下:
"customerMonthInfo": "{{ cmp_server_customerMonthInfo }}", "type_black_list": [{% for type_black in cmp_server_type_black_list %}"{{ type_black }}"{{ '' if loop.last else ',' }}{% endfor %}],
上述示例中「customerMonthInfo」的参数比较简单,就是变量「cmp_server_customerMonthInfo」的值
「type_black_list」参数从列表变量「cmp_server_type_black_list」中获取,执行结果是个字符串,字符串由该列表的元素以逗号为间隔组成,最后一个参数后没有逗号。
欢迎你们关注个人公众号: