ansible基础-变量

ansible基础-变量

作者/魏萌 图片/使用Xmind

目录结构

一 变量的命名规范

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

变量应该由字母、数字、下划线组成

变量应该以字母开头

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

变量的定义通常是YAML形式,在inventory host文件中也可以使用INI形式。

ansible变量不仅可以支持简单的key=value格式,而且也支持更复杂数据结构,例如字典类型等。

二 变量的作用域

变量的作用域可以分为四种:

作用于全局的变量

作用于play的变量

作用于task的变量

作用于host的变量

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

三 作用于全局的变量

3.1 配置文件变量

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

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

3.2 系统环境变量

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

3.3 命令行变量

我们可以在执行playbook的命令行指定变量,需要注意的是,命令行指定的变量在所有其他变量中优先级是最高的。也就是说如果命令行指定的变量和其他地方指定的变量有冲突时,那么ansible最终会采用命令行定义的变量。

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

四 作用于play的变量

4.1 playbook中的变量

vars语句定义全局变量

我们可以在playbook中使用「vars」语句定义变量,该变量作用于整个play。

例如:

上面示例中中「http_port」是一个作用于整个play的变量,对这个play里的tasks、roles、import、include等等之下定义的task均生效。

引用变量文件

除了将变量写在playbook中,我们也可以将变量放在一个单独的YAML文件中,通过「vars_files」语句来导入。

「vars_files」变量只能作用于play全局,不能在某个task中单独被引用。「vars_files」参数可以使用系统绝对路径或playbook文件的相对路径。

举个:

我们在playbooks目录下创建一个vars-files.yaml文件:

在playbook中使用vars_files语句引用该变量文件:

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」变量:

role_A/meta/main.yaml定义role_A依赖role_B,并指定「age」变量等于26:

写playbook,引用role_A:

执行结果如下:

输出结果显示,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」参数后使用了这两个变量:

withimport*/include*

在使用import_playbook、import_tasks、include_tasks、import_role、include_role时可以在import*/include*的同级位置指定变量,该变量作用于导入的所有play。

使用import_role举个:

playbook导入role_A,并定义变量「age」,这样role_A内的play就可以使用「age」变量了:

其他import*/include*的语句使用方法类似,只要记住缩进与import*/include*语句保持一致即可。

with roles

在playbook中使用roles语句来导入role时也可以定义变量,该变量作用于role包含的所有play。

举个:

playbook使用roles语句导入role_A,并定义变量「age」:

通过上面两个示例我们发现,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安装需要的软件包:

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缓存:

json文件缓存:

6.2 inventory中的变量

6.2.1 主机变量

关于主机和主机组变量,我们在「

ansible基础-安装与配置

:3.1 主机与主机组」中有介绍,当时介绍了组和主机变量的定义方法、变量的分离、优先级等知识点。其实主机变量的知识点不复杂,这里做下总结。

主机变量是指作用在某一台主机上的变量。位置可以与主机定义写在一起也可以写在inventory/host_vars/a_host_name.yaml文件里。通常前者使用使用INI格式,后者使用YAML格式。这里要注意一下YAML的语法,在「:」后面要留有一个空格。

如果组变量和主机变量都对同一个主机定义了相同的变量,那么ansible最终会采用主机变量而放弃组变量

主机变量示例:

INI格式:

转换为YAML格式:

不含节点定义的主机变量定义:

6.2.2 组变量

和主机变量类似,组变量作用于主机组,即多个主机。位置可以与主机组定义写在一起也可以写在inventory/group_vars/a_group_name.yaml文件里。通常前者使用使用INI格式,后者使用YAML格式。

INI格式:

转换为YAML格式:

定义一个字典变量,位于inventory/group_vars/nodes.yaml:

将上面示例转换为一行:

很显然,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模块内可以直接调用。

输出结果展示:

8.2 模版使用变量

变量被频繁使用的还有roles里的模版,位于roles/template/xxx.j2,该模版使用python的Jinja2模版语法。

roles模版多被用于生成服务的配置文件,所以会调用很多的变量。

示例如下:

上述示例中「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 教材

- END -

没点关注的童鞋点一波关注

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181106G1RR2L00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券