ansible基础-变量

一 变量的命名规范

变量的命名应该符以下合两个规范:html

  • 变量应该由字母、数字、下划线组成
  • 变量应该以字母开头

例如:host_port、HOST_PORT、var5是符合命名规范的,foo-port、 foo port、foo.port 、12都不符合命名规范。node

变量的定义一般是YAML形式,在inventory host文件中也可使用INI形式。python

ansible变量不只能够支持简单的key=value格式,并且也支持更复杂数据结构,例如字典类型等。c++

二 变量的做用域

 变量的做用域能够分为四种:redis

  • 做用于全局的变量
  • 做用于play的变量
  • 做用于task的变量
  • 做用于host的变量

接下来咱们根据变量的做用域,详细分析下ansible变量的定义、使用和调用顺序。shell

三 做用于全局的变量

3.1 配置文件变量

ansible配置文件会定义一些变量信息,主要是对执行环境、链接信息变量的定义。json

例如inventory目录、library目录、与目的主机链接方式、越权信息、链接超时时间等等。缓存

3.2 系统环境变量

在ansible链接到目的主机时,会以non-login shell登录到目的主机,此时目的主机的/etc/bashrc和~/.basrc的环境变量会被加载,因此这两个文件中设置的环境变量会做用于playbook全局。bash

3.3 命令行变量

咱们能够在执行playbook的命令行指定变量,须要注意的是,命令行指定的变量在全部其余变量中优先级是最高的。也就是说若是命令行指定的变量和其余地方指定的变量有冲突时,那么ansible最终会采用命令行定义的变量。数据结构

命令行指定变量示例以下:

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

四 做用于play的变量

4.1 playbook中的变量

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 }}"

4.2 roles中的变量

4.2.1 default变量 

default变量位于roles/defaults/main.yml文件中,该变量做用于role里的全部play,一般做为模版或模块里的默认参数。

default变量与ansible filter变量 「{{ some_variable | default("some_value") }}」具备一样的做用,在全部ansible变量中优先级最低。

4.2.2 dependencies变量

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均生效。

4.2.3 vars变量

vars变量位于roles/vars/main.yml,该变量做用于role里的全部模块。一般将除了默认变量的其余的变量放在这个文件内。

4.3 register变量

register方法可以将一个task的执行结果注册为一个变量。书写格式要与模块名称对齐,该变量做用于整个play。

一般register变量和when语句联合使用,以达到知足某些条件才运行task的目的。

五 做用于task的变量 

5.1 playbook中的变量

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语句。

5.2 roles中的变量

指的是在tasks/main.yaml或handlers/main.yaml内书写task时指定的变量,该变量做用于某个task,这个变量类型和上述章节中「5.1playbook中的变量—with modules」相似,这里就再也不举例说明。

六 做用于host的变量

6.1 系统变量Facts

6.1.1 facts变量

ansible中有个特殊的变量,这些变量不是开发者定义的,而是ansible根据目的主机环境信息自动收集的,称之为fact变量。

fact变量很实用,和「when」语句配合使用会让你的代码更加健壮。

举个🌰,若是当前的操做系统为「RedHat」类型,则经过yum安装须要的软件包:

--- # playbooks/test.yaml - hosts: node1 tasks: - yum: name: firewalld state: present when: ansible_os_family == 'RedHat'

6.1.2 facts缓存

在执行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

6.2 inventory中的变量

6.2.1 主机变量

关于主机和主机组变量,咱们在「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\'

6.2.2 组变量 

和主机变量相似,组变量做用于主机组,即多个主机。位置能够与主机组定义写在一块儿也能够写在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采用)

  • 命令行参数(非-e指定的参数,eg: "-u user -b yes")
  • roles defaults目录下的变量
  • 组变量:inventory 文件
  • 组变量:inventory/group_vars/all
  • 组变量:playbook/group_vars/all
  • 组变量:inventory/group_vars/*
  • 组变量:playbook/group_vars/*
  • 主机变量:inventory 文件
  • 主机变量:inventory/group_vars/*
  • 主机变量:playbook/group_vars/*
  • facts变量
  • play变量:vars定义的
  • play变量:vars_prompt定义的
  • play变量:vars_files导入的
  • roles vars目录下的变量
  • block中task定义的变量
  • playbook中task定义的变量
  • include_vars导入的变量
  • set_facts/register注册的变量
  • 使用roles/include_role/import_role语句时定义的变量
  • 使用include语句(ansible旧版本)时定义的变量
  • 命令行-e参数指定的额外变量(优先级最高)

八 变量的使用

8.1 模块使用变量

一个变量被定义后,在它的做用域内的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

8.2 模版使用变量

变量被频繁使用的还有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」中获取,执行结果是个字符串,字符串由该列表的元素以逗号为间隔组成,最后一个参数后没有逗号。

九 本节应该掌握的技能

  • 掌握变量的命名规范
  • 掌握变量定义的方法
  • 掌握变量的做用域及调用顺序
  • 会在模块和模版里使用变量
  • 熟悉Jinja2模版的语法规则

十 参考连接

  • https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#passing-variables-on-the-command-line
  • https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
  • https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
  • 红帽DO407 Automation with Ansible 教材

 

欢迎你们关注个人公众号:

相关文章
相关标签/搜索