管理变量variables、机密vault、事实fact
1、管理变量
1.1 变量的介绍
在ansible中使用变量,能让我们的工作变得更加灵活,变量的使用方式有很多种。通过变量,可以轻松地在Ansible项目中管理给定环境的动态值。例如:
- 要创建的用户
- 要安装的软件包
- 要重新启动的服务
- 要删除的文件
- 要从互联网检索的存档
变量的作用:
- 存储数据
- 引用数据
命名变量:
变量的名称必须以字母开头,并且只能包含字母、数字和下划线这三种。
无效的变量名称 | 有效的变量名称 |
---|---|
web server | web_server |
wjm.file | wjm_file |
定义变量
可以在Ansible项目中的多个位置定义变量。不过,这些变量大致可简化为三个范围级别:
- 全局范围:从命令行或Ansible配置设置的变量
- Play范围:在play和相关结构中设置的变量
- 主机范围:由清单、事实收集或注册的任务,在主机组和个别主机上设置的变量
如果在多个xeklh定义了相同名称的变量,则采用优先级别最高的变量。窄范围优先于更广泛的范围:由清单定义的变量将被playbook定义的变量覆盖,后者将被命令行中定义的变量覆盖。
1.2 变量优先级
命令行定义的变量 > playbook中的变量( playbook中vars_file > playbook中vars变量) > 清单定义的变量(host_vars>group_vars)
1.3 playbook中的变量
Playbook变量可以通过多种方式定义。一种常见的方式是将变量放在playbook开头的vars块中:
---
- name: 创建用户
hosts: httpd
vars:
name: wjm
uid: 4000
tasks:
- name:
user:
name: "{{ name }}"
uid: "{{ uid }}"
state: present
另外一种方式是不在play中定义变量,而是在和这个playbook文件同级别的文件中定义变量,然后在playbook中变量指向这个路径即可。
---
- name: 创建用户
hosts: httpd
vars_files: //定义变量的文件
- /etc/ansible/vars/content.yml //定义变量文件的具体位置
tasks:
- name: 输出一段话
shell: echo {{ content }} > /etc/123 // 向屏幕输出 “content”,并把输出的内容重定向到httpd主机的/etc/123文件中。 >:覆盖
//如果引用的内容直接跟在模块后面是需要加引号的,如果模块的后面是命令+引用是不用添加引号的。列子 user模块 name: '{{ name }}'
[root@localhost ansible]# cat vars/content.yml
content: '向屏幕输出一段话'
[root@localhost ~]# cat /etc/123
向屏幕输出一段话
注意:当变量用作开始一个值的第一元素时,必须使用引号。这可以防止Ansible将变量引用视为YAML字典的开头。
1.4 主机变量和组变量
直接应用于主机的清单变量分为两在类:
- 主机变量:应用于主机
- 组变量:应用于组
主机变量优先于组变量,但playbook中定义的变量的优先级比这两者更高。
playbook > 主机变量 > 组变量 越详细具体优先级就越高
下面先介绍一下比较旧的主机和组的变量定义方式,但不建议采用。
定义129主机的用户名变量
[httpd]
192.168.252.129 ansible_user=root ansible_passwd=1
定义组整个组的用户变量
[httpd] //http组
192.168.252.129
192.168.252.130
[httpd:vars] //httpd组中的所有主机的变量定义
user=root
定义servers组的user组变量,该组由两个主机组成,每个主机组有两个服务器:
[httpd1]
node1.example.com
node2.example.com
[httpd2]
node3.example.com
node4.example.com
[httpd:children] //包含了httpd1和httpd2组。 children:孩子
servers1
servers2
[servers:vars] //httpd组中4台主机的用户变量定义
user=joe
1.4.1 使用目录填充主机和组变量
定义主机和主机组的变量的首选做法是在与清单文件或目录相同的工作目录中,创建group_vars和host_vars两个目录。这两个目录分别包含用于定义组变量和主机变量的文件。
建议的做法是使用host_vars和group_vars目录定义清单变量,而不直接在清单文件中定义它们。
主机变量
例子:现在要设置httpd组中某一台主机user的变量
在与清单文件同级别的目录下创建一个名为hosts_vars目录,在里面创建一个与你要设置某一台主机的ip或名相同的YAML文件,在里面定义变量
[root@localhost ansible]# tree
.
├── ansible.cfg
├── hosts
├── host.sh
├── host_vars //主机变量
│ └── 192.168.252.129 //129主机的变量定义
├── inventory //清单文件
├── roles
├── vars
│ └── content.yml
└── wjm.yml
[root@localhost ansible]# cat inventory
[httpd]
192.168.252.129
[root@localhost ansible]# cat host_vars/192.168.252.129
ansible_user=root
组变量
[root@localhost ansible]# tree
.
├── ansible.cfg
├── group_vars //组的变量定义
│ └── httpd //httpd组中所有主机的变量
├── hosts
├── host.sh
├── host_vars
│ └── 192.168.252.129
├── inventory
├── roles
├── vars
│ └── content.yml
└── wjm.yml
[root@localhost ansible]# cat inventory
[httpd]
192.168.252.123
[root@localhost ansible]# cat group_vars/httpd
ansible_user=wjm
1.5 从命令行覆盖变量
在playbook中指定变量,但不定义变量,当使用命令覆盖变量的时候playbook中的变量将被命令的方式替换,优先执行命令中的定义
---
- name: 创建用户
hosts: httpd
vars:
name: wjm
uid: 4000
tasks:
- name:
user:
name: '{{ user }}'
uid: '{{ uid }}'
state: present
[root@localhost ansible]# ansible-playbook -e "user= W123 uid=2100" wjm.yml
//虽然playbook中user是wjm uid是4000 但是如果使用了命名覆盖的方式那么命令中变量的定义优先级比play中高!!!
[root@localhost ~]# id www
uid=2000(www) gid=2000(www) 组=2000(www)
1.6 使用数组作为变量
用于提取数组中某一段信息
---
- name: 创建用户
hosts: httpd
vars_files:
- vars/shuzhu.yml
tasks:
- name:
shell: echo '{{ info.www }}'> /etc/123 //建议使用中括号的方式,不然可能会和Python冲突。推荐用法:{{ info ['www'] }}
推荐使用这种方式
---
- name: 创建用户
hosts: httpd
vars_files:
- vars/shuzhu.yml
tasks:
- name:
shell: echo {{ info ['www'] }} > /etc/123 //推荐使用括号
[root@localhost ansible]# cat vars/shuzhu.yml
info:
www:
first_name: jm
last_name: w
age: 100
[root@localhost ansible]# ansible-playbook wjm.yml
[root@localhost ~]# cat /etc/123
{first_name: jm, last_name: w, age: 100} //字典方式显示
2、管理机密
2.1 ansible-vault 加密
一个公司很多的数据,这些数据里面有一些是普通数据,还要一部分是比较敏感的数据,可能是用户的信息等等。而这个时候就需要给这些放数据的文件进行加密,进而保护用户的隐私。而现在介绍的就是ansible中的一种加密方式叫 ansible-vault
。
2.2 ansible-vault的用法
命令 | 介绍 |
---|---|
ansible-vault create [文件名] | 创建一个加密文件 |
ansible-vault view [文件名] | 查看加密文件的内容,但是要输入密码 |
ansible-vault edit [文件名] | 编辑现有的加密文件内容,这种方式也是需要输入密码的 |
ansible-vault encrypt [文件名] | 给现有的文件进行加密 |
ansible-vault decrypt [文件名] | 解密现有的文件 |
ansible-vault [文件名1] --output=[文件名2] | 解密文件名1,并且设置解密后文件名1 变成文件名2,简单的说就是给解密的后的文件重命名 |
ansible-vault rekey [文件名] | 更改加密文件的密码 |
创建一个加密文件: create
[root@localhost ansible]# ansible-vault create wjmjiami
New Vault password:
Confirm New Vault password:
wjmjiami //wjmjiami文件的内容
[root@localhost ansible]# ll
-rw-------. 1 root root 484 7月 25 00:24 wjmjiami
//此时我们查看这个加密文件,都是轮眉,文件内容被加密了
[root@localhost ansible]# cat wjmjiami
$ANSIBLE_VAULT;1.1;AES256
32353938616661623262363131326339366438326530373166303431393461366530316434333666
3330613362386533366662663136626562363038313234630a626539303166616364616235303533
39303030316435653439613362346430653632656535386539346430643134663135323734356237
6631373132346131350a663239623764333138303037623730633830636530353734313862616139
31643661333435643333656162313437336632633665653839633838396661643161323231653832
3262393133613033663533383032313831636137333139373362
我们还可以用vault密码文件来存储vault密码,而不是通过标准输入途径输入vault密码。
[root@localhost ansible]# vim vault-passwd
123456
[root@localhost ansible]# ansible-vault create --vault-password-file=vault-passwd wjm123
//创建一个加密文件叫wjm123 加密的密码放在了vault-passwd。
查看加密的文件: view
[root@localhost ansible]# ansible-vault view wjmjiami
Vault password: //输入加密文件的密码
创建的一共加密文件的内容 //加密文件的内容
编辑现有的加密文件: edit
[root@localhost ansible]# ansible-vault edit wjmjiami
Vault password:
编辑现有的加密文件,更改里面的内容!//编辑过后的加密文件内容
加密现有的文件:encrypt
要加密已存在的文件
[root@localhost ansible]# ansible-vault encrypt 123
New Vault password: //设置密码123
Confirm New Vault password:
Encryption successful
解密现有的:decrype
要加密已存在的文件,请使用ansible-vault encrypt filename命令。此命令可取多个欲加密文件的名称作为参数。
[root@localhost ansible]# ansible-vault decrypt 123
Vault password:
Decryption successful
更改加密文件的密码: rekey
使用ansible-vault rekey filename命令更改加密文件的密码
[root@localhost ansible]# ansible-vault rekey wjm
Vault password: //旧密码
New Vault password: //新密码
Confirm New Vault password: //再输入一次新密码
Rekey successful
2.3 ansible-vault在playbook中的使用
先在ansible目录中创建一个playbook文件,在playbook中定义变量的位置在/var/name.yml。然后到目录/var/下创建一个与playbook变量名一样的文件,在里面定义变量。随后在当前目录中创建一个隐藏的文件 里面记录着一会要加密变量文件的密码,然后用这个隐藏文件对变量文件进行加密。最后在执行playbook时,把加密的密码文件指出即可。
[root@localhost ansible]# tree
.
├── ansible.cfg
├── apache.yml
├── hosts
├── host.sh
├── host_vars
│ └── apache.yml
├── inventory
├── jiami.yml
├── var
│ └── name.yml
├── vars
│ └── shuzhu.yml
└── wjm.yml
[root@localhost ansible]# cat jiami.yml
---
- name:
hosts: httpd
vars_files:
- /etc/ansible/var/name.yml //定义变量文件的位置
tasks:
- name:
user:
name: "{{ name }}"
state: present
[root@localhost var]# vim name.yml //创建定义变量的文件
name: wjm123
[root@localhost var]# ll -a
总用量 8
drwx------. 2 root root 36 7月 25 01:33 .
drwxr-xr-x. 5 root root 172 7月 25 01:36 ..
-rw-r--r--. 1 root root 4 7月 25 01:32 .jiami //创建 加密的密码文件
-rw-------. 1 root root 355 7月 25 01:33 name.yml
[root@localhost var]# cat .jiami
123 //加密的密码
[root@localhost var]# ansible-vault encrypt name.yml --vault-password-file=.jiami
//用当前目录下的.jiami文件对变量文件进行加密
Encryption successful
[root@localhost ansible]# ansible-playbook jiami.yml --vault-password-file=var/.jiami
//执行playbook并指定密码文件位置
[WARNING]: Found variable using reserved name: name
PLAY [httpd] *********************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************
ok: [192.168.252.129]
TASK [user] **********************************************************************************************************************************
ok: [192.168.252.129]
PLAY RECAP ***********************************************************************************************************************************
192.168.252.129 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost ansible]#
3、事实
3.1 事实介绍
所谓“事实”,就是已经存在的,已经被定义好的。
事实包括:主机名称、内核版本、网络接口、IP地址等 。
ansible_facts
是系统定义过的变量,直接可以使用。可以显示对面主机的ip、CPU、内核、Python版本等。
---
- name: shishi
hosts: httpd
tasks:
- name:
debug:
var: ansible_facts
~
借助事实,可以方便地检索受管主机的状态,并根据该状态确定要执行的操作。例如:
- 可以根据含有受管主机当前内核版本的事实运行条件任务,以此来重启服务器
- 可以根据通过事实报告的可用内存来自定义MySQL配置文件
- 可以根据事实的值设置配置文件中使用的IPv4地址
Ansible事实的示例
事实 | 变量 |
---|---|
短主机名 | ansible_facts[‘hostname’] |
完全限定域名 | ansible_facts[‘fqdn’] |
IPv4地址 | ansible_facts[‘default_ipv4’][‘address’] |
所有网络接口的名称列表 | ansible_facts[‘interfaces’] |
/dev/vda1磁盘分区的大小 | ansible_facts[‘dns’][‘nameservers’] |
当前运行的内核版本 | ansible_facts[‘kernel’] |
---
- name: shishi
hosts: httpd
tasks:
- name:
debug:
msg: >
The default IPv4 address of {{ ansible_facts.fqdn}}
is {{ ansible_facts.default_ipv4.address }}
[root@localhost ansible]# ansible-playbook shishi.yml
......
......
TASK [debug] *******************************************************************
ok: [192.168.252.129] => {
"msg": "The default IPv4 address of localhost.localdomain is 192.168.252.129\n"
}
PLAY RECAP *********************************************************************
192.168.252.129 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3.2Ansible事实作为变量注入
在Ansible2.5之前,事实是作为前缀为字符串ansible_的单个变量注入,而不是作为ansible_facts变量的一部分注入。例如,ansible_facts[‘distribution’]事实会被称为ansible_distribution。
许多较旧的playbook仍然使用作为变量注入的事实,而不是在ansible_facts变量下创建命名空间的新语法。我们可以使用临时命令来运行setup模块,以此形式显示所有事实的值。以下示例中使用一个临时命令在受管主机172.16.103.129上运行setup模块:
ansible 172.16.103.129 -m setup
选定的Ansible事实名称对比
ansible_facts形式 | 旧事实变量形式 |
---|---|
ansible_facts[‘hostname’] | ansible_hostname |
ansible_facts[‘fqdn’] | ansible_fqdn |
ansible_facts[‘default_ipv4’][‘address’] | ansible_default_ipv4[‘address’] |
ansible_facts[‘interfaces’] | ansible_interfaces |
ansible_facts[‘dns’][‘nameservers’] | ansible_dns[‘nameservers’] |
ansible_facts[‘kernel’] | ansible_kernel |
3.4 创建自定义事实
除了使用系统捕获的事实外,我们还可以自定义事实,并将其本地存储在每个受管主机上。这些事实整合到setup模块在受管主机上运行时收集的标准事实列表中。它们让受管主机能够向Ansible提供任意变量,以用于调整play的行为。
自定义事实可以在静态文件中定义,格式可为INI文件或采用JSON。它们也可以是生成JSON输出的可执行脚本,如同动态清单脚本一样。
有了自定义事实,我们可以为受管主机定义特定的值,供play用于填充配置文件或有条件地运行任务。动态自定义事实允许在play运行时以编程方式确定这些事实的值,甚至还可以确定提供哪些事实。
默认情况下,setup模块从各受管主机的/etc/ansible/facts.d目录下的文件和脚本中加载自定义事实。各个文件或脚本的名称必须以.fact结尾才能被使用。动态自定义事实脚本必须输出JSON格式的事实,而且必须是可执行文件。
以下是采用INI格式编写的静态自定义事实文件。INI格式的自定义事实文件包含由一个部分定义的顶层值,后跟用于待定义的事实的键值对:
[packages]
web_package = httpd
db_package = mariadb-server
[users]
user1 = joe
user2 = jane
同样的事实可能以JSON格式提供。以下JSON事实等同于以上示例中INI格式指定的事实。JSON数据可以存储在静态文本文件中,或者通过可执行脚本输出到标准输出:
{
"packages": {
"web_package": "httpd",
"db_package": "mariadb-server"
},
"users": {
"user1": "joe",
"user2": "jane"
}
}
自定义事实文件不能采用playbook那样的YAML格式。JSON格式是最为接近的等效格式。
自定义事实由setup模块存储在ansible_facts.ansible_local变量中。
事实按照定义它们的文件的名称来整理。例如,假设前面的自定义事实由受管主机上保存为/etc/ansible/facts.d/custom.fact的文件生成。在这种情况下,ansible_facts.ansible_local[‘custom’][‘users’][‘user1’]的值为joe。