文章目录
管理变量、机密和事实
1.Ansible变量简介
- 变量:variables
机密:vault
事实:facts
Ansible支持利用变量来存储值,并在Ansible项目的所有文件中重复使用这些值。这可以简化项目的创建和维护,并减少错误的数量。
通过变量,可以轻松地在Ansible项目中管理给定环境的动态值。例如,变量可能包含下面这些值:
- 要创建得用户
- 要安装得软件包
- 要重新启动得服务
- 要删除得文件
- 要从互联网检索得文档
2.命令变量
变量的名称必须以字母开头,并且只能包含字母、数字和下划线。
下面是无效的名称和有效的名称实例:
无效的变量名称 | 有效的变量名称 |
---|---|
web server | web_server |
remote.file | remote_file |
1st file | file_1 file1 |
remoteserver$1 | remote_server_1 remote_server1 |
[root@localhost ~]# docker_user_fto_ll //我们用下划线是正确的
[root@localhost ~]# docker user fto ll //这样子就是无效的变量名称
3.定义变量
可以在Ansible项目中的多个位置定义变量。不过,这些变量大致可简化为三个范围级别:
-
全局范围:从命令行或Ansible配置设置的变量
-
Play范围:在play和相关结构中设置的变量
-
主机范围:由清单、事实收集或注册的任务,在主机组和个别主机上设置的变量
如果在多个级别定义了相同名称的变量,则采用优先级别最高的变量。窄范围优先于更广泛的范围:由清单定义的变量将被playbook定义的变量覆盖,后者将被命令行中定义的变量覆盖
4.playbook中的变量
变量在Ansible Playbook中发挥着重要作用,因为它们可以简化playbook中变量数据的管理。
5.在playbook中定义变量
编写playbook时,可以定义自己的变量,然后在任务中调用这些值。例如,名为web_package的变量可以使用值httpd来定义。然后,任务可以使用yum模块调用该变量来安装httpd软件包。
Playbook变量可以通过多种方式定义。一种常见的方式是将变量放在playbook开头的vars块中:
[root@node1 ansible]# cat node/test.yml
---
- hosts: 192.168.100.147
vars: //变量
IP: 192.168.100.148
NAME: node2
tasks:
- name: test
lineinfile:
path: /etc/hosts //受管主机etc/hosts
line: "{{IP}} {{NAME}}" //插入变量IP \NAME.在这里注意我们必须打上引号,不然报错
state: present
[root@node1 ansible]#
[root@node1 ansible]# ansible-playbook node/test.yml //执行没有报错
PLAY [192.168.100.147] *********************************************************************************************
TASK [Gathering Facts] *********************************************************************************************
ok: [192.168.100.147]
TASK [test] ********************************************************************************************************
changed: [192.168.100.147]
PLAY RECAP *********************************************************************************************************
192.168.100.147 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost ~]# cat /etc/hosts //此时查看。加入成功,这是在playbook中的变量
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.100.148 node2
[root@localhost ~]#
line: haha {{IP}} {{NAME} //如果我们把上面这一行去掉引号,我们可以往前面加一个名字也可运行
[root@localhost ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.100.148 node2
haha 192.168.100.148 node2 //我们发现没有引号也可以运行,但是前面必须要名。
[root@localhost ~]#
也可以在外部文件中定义playbook变量。此时不使用playbook中的vars块,可以改为使用vars_files指令,后面跟上相对于playbook位置的外部变量文件名称列表:
[root@node1 node]# cat sss/runtime.yml //我们在外边创建一个文件,并且写入相应变量的值
IP: 192.168.100.50
NAME: node3
[root@node1 node]#
[root@node1 node]# cat test.yml
---
- hosts: 192.168.100.147
vars_files: //改为vars_files指令
- sss/runtime.yml //这是里路径,我们刚刚创建了一个sss,并在里面写了一个runtime.yml的文件,这也是第二种定义变量的方式,定义到一个文件里面
tasks:
- name: test
lineinfile:
path: /etc/hosts
line: haha {{IP}} {{NAME}}
state: present
[root@node1 node]#
[root@node1 ansible]# ansible-playbook node/test.yml //执行成功
PLAY [192.168.100.147] *********************************************************************************************
TASK [Gathering Facts] *********************************************************************************************
ok: [192.168.100.147]
TASK [test] ********************************************************************************************************
changed: [192.168.100.147]
PLAY RECAP *********************************************************************************************************
192.168.100.147 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node1 ansible]#
[root@localhost ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.100.148 node2
haha 192.168.100.148 node2
haha 192.168.100.50 node3 //刚刚我们在外边创建的内容,发现已经过来了。
[root@localhost ~]#
6.在playbook中使用变量
声明了变量后,可以在任务中使用这些变量。若要引用变量,可以将变量名放在双大括号内。在任务执行时,Ansible会将变量替换为其值。
[root@node1 ansible]# cat node/test.yml
---
- hosts: 192.168.100.147
vars_files:
- sss/runtime.yml
tasks:
- name: test
lineinfile:
path: /etc/hosts
line: haha {{IP}} {{NAME}}
state: present
[root@node1 ansible]#
注意:当变量用作开始一个值的第一元素时,必须使用引号。这可以防止Ansible将变量引用视为YAML字典的开头。上面已经讲过,我们不在这里多解释。
7.主机变量和组变量
直接应用于主机的清单变量分为两在类
- 主机变量,应用于特定主机
- 组管理,应用于一个主机组或一组主机组中的所有主机
主机变量优先于组变量,但playbook中定义的变量的优先级比这两者更高。
若要定义主机变量和组变量,一种方法是直接在清单文件中定义。这是较旧的做法,不建议采用,但你可能会在未来的工作当中遇到。
定义192.168.100.147的ansible_user主机变量:
[webservers]
[apache]
192.168.100.147 ansible_user=root ansible_password=1 //这也是我们之前做过的,也就是给清单一个用户和密码
定义webserver主机组的user组变量(第二种方法)
[root@node1 ansible]# cat shen //这种方法就像上面说的,一般不建议这样用,比较麻烦
[webservers]
[apache]
192.168.100.147
[webserver:vars]
ansible_user=root
ansible_password=1
[root@node1 ansible]#
定义servers组的user组变量,该组由两个主机组成,每个主机组有两个服务器:
[servers1]
node1.example.com
node2.example.com
[servers2]
node3.example.com
node4.example.com
[servers:children]
servers1
servers2
[servers:vars]
user=joe
此做法存在一些缺点,它使得清单文件更难以处理,在同一文件中混合提供了主机和变量信息,而且采用的也是过时的语法。
8.使用目录填充主机和组变量
定义主机和主机组的变量的首选做法是在与清单文件或目录相同的工作目录中,创建group_vars和host_vars两个目录。这两个目录分别包含用于定义组变量和主机变量的文件。
建议的做法是使用host_vars和group_vars目录定义清单变量,而不直接在清单文件中定义它们。
为了定义用于servers组的组变量,需要创建名为group_vars/servers的YAML文件,然后该文件的内容将使用与playbook相同的语法将变量设置为值:
下面举例填充主机
[root@node1 ansible]# cd node/
[root@node1 node]# mkdir group_vars //创建group_vars
[root@node1 node]# mkdir host_vars //创建host_vars
[root@node1 node]# ls
ahh.yml group_vars host_vars midengxing.yml shunzichishi sss test.yml vsftpd. vsftpd.yml
[root@node1 node]# vim host_vars/192.168.100.147 //在host_vars下面创建192.168.100.147
[root@node1 node]# cat host_vars/192.168.100.147
ansible_user: root //写变量用户
ansible_password: 1 //写变量值
[root@node1 node]# cd ..
[root@node1 ansible]# vim shen
[root@node1 ansible]# cat shen //这里是原来的写法
[webservers]
[apache]
192.168.100.147
[webserver:vars]
ansible_user=root
ansible_password=1
[root@node1 ansible]#
[root@node1 ansible]# cat shen //我们将里面的删掉
[webservers]
[apache]
192.168.100.147
[root@node1 ansible]#
[root@node1 ansible]# ansible apache -m ping //能ping通对面,
192.168.100.147 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
[root@node1 ansible]#
注意:类似的,为了定义用于特定主机的主机变量,需要在host_vars目录中创建名称与主机匹配的文件来存放主机变量。
如果需要为两个数据中心的所有服务器定义一个通用值,可以为datacenters主机组设置一个组变量:
[root@localhost ~]# mkdir ~/project/groupo_vars
[root@localhost ~]# vim ~/project/groupo_vars/datacenters
package: httpd
如果要为每个数据中心定义不同的值,可以为每个数据中心主机组设置组变量:
[root@localhost ~]# vim ~/project/groupo_vars/datacenter1
package: httpd
[root@localhost ~]# vim ~/project/groupo_vars/datacenter2
package: apache2
如果要为每一数据中心的各个主机定义不同的值,则在单独的主机变量文件中定义变量:
[root@localhost ~]# mkdir ~/project/host_vars
[root@localhost ~]# vim ~/project/host_vars/node1.example.com
package: httpd
[root@localhost ~]# vim ~/project/host_vars/node2.example.com
package: apache2
[root@localhost ~]# vim ~/project/host_vars/node3.example.com
package: mariadb-server
[root@localhost ~]# vim ~/project/host_vars/node4.example.com
package: mysql-server
以上是在project下操作的,而我们是在ansible下面操作的,下面是结构图,
[root@node1 ansible]# tree /etc/ansible
/etc/ansible
├── ansible.cfg
├── fei
│ ├── httpd.conf
│ ├── index.php
│ ├── lamp.yml
│ └── www.conf
├── hosts
├── long
│ ├── chongqi.yml
│ ├── httpd.yaml
│ ├── mysql.yml
│ └── php.yml
├── node
│ ├── ahh.yml
│ ├── group_vars
│ ├── host_vars
│ │ └── 192.168.100.147
│ ├── midengxing.yml
│ ├── shunzichishi
│ │ └── vsftpd.conf
│ ├── sss
│ │ └── runtime.yml
│ ├── test.yml
│ ├── vsftpd.
│ └── vsftpd.yml
└── shen
7 directories, 19 files
[root@node1 ansible]#
9.从命令行覆盖变量
清单变量可被playbook中设置的变量覆盖,这两种变量又可通过在命令行中传递参数到ansible或ansible-playbook命令来覆盖。在命令行上设置的变量称为额外变量。
当需要覆盖一次性运行的playbook的变量的已定义值时,额外变量非常有用。例如
[root@node1 node]# vim host_vars/192.168.100.147
[root@node1 node]# cat host_vars/192.168.100.147 //我们主机变量里面是写了一个IP地址和名字的
ansible_user: root
ansible_password: 1
ip: 10.10.10.10
name: node3
[root@node1 node]#
[root@node1 node]# vim test.yml
[root@node1 node]# cat test.yml //然后我在playbook文件中写了一个变量ip地址和名字与上面主机变量里面一致,也就是重复了,此时的规矩是playbook中的最大
---
- hosts: 192.168.100.147
vars:
ip: 10.10.10.10
name: node3
tasks:
- name: test
lineinfile:
path: /etc/hosts
line: haha {{IP}} {{NAME}}
state: present
[root@node1 node]#
10.使用数组作为变量
除了将同一元素相关的配置数据(软件包列表、服务列表和用户列表等)分配到多个变量外,也可以使用数组。这种做法的一个好处在于,数组是可以浏览的。
例如,假设下列代码片段:
user1_first_name: Bob //这种做法不建议,如果用户多,写都写不完
user1_last_name: Jones
user1_home_dir: /users/bjones
user2_first_name: Anne
user2_last_name: Cook
user2_home_dir: /users/acook
这将可以改写成名为users的数组:
users:
bjones:
first_name: Bob
last_name: jones
home_dir: /users/bjones
acook:
first_name: Anne
last_name: Cook
home_dir: /users/acook
例:
[root@node1 node]# vim host_vars/192.168.100.147
[root@node1 node]# cat host_vars/192.168.100.147
ansible_user: root
ansible_password: 1
info:
node4: //写入用户地址和域名
ip: 4.4.4.4
domain: abc.example.com
node5:
ip: 5.5.5.5
domain: web.example.com
[root@node1 node]# vim test.yml
[root@node1 node]# cat test.yml
---
- hosts: 192.168.100.147
vars:
ip: 10.10.10.10
tasks:
- name: test
lineinfile:
path: /etc/hosts
line: "{{info.node4.ip}} {{info.node4.domain}}" //更改这里,我先定义一个
state: present
[root@node1 node]#
root@node1 ansible]# ansible-playbook node/test.yml //执行
PLAY [192.168.100.147] *********************************************************************************************
TASK [Gathering Facts] *********************************************************************************************
ok: [192.168.100.147]
TASK [test] ********************************************************************************************************
changed: [192.168.100.147]
PLAY RECAP *********************************************************************************************************
192.168.100.147 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node1 ansible]#
[root@localhost ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.100.148 node2
4.4.4.4 abc.example.com //已经加入成功
[root@localhost ~]#
注意:由此这出,变量它是比较灵活的。而且有很多比较复杂,也有很多比较简单
如果键名与python方法或属性的名称(如discard、copy和add)相同,点表示法可能会造成问题。使用中括号表示法有助于避免冲突和错误。
但要声明的是,上面介绍的两种语法都有效,但为了方便故障排除,建议在任何给定Ansible项目的所有文件中一致地采用一种语法,不要混用。
11.使用已注册变量捕获命令输出
可以使用register语句捕获命令输出。输出保存在一个临时变量中,然后在playbook中可用于调试用途或者达成其他目的,例如基于命令输出的特定配置。
以下playbook演示了如何为调试用途捕获命令输出:
[root@node1 node]# cat buhuo.yml
---
- name: q11
hosts: 192.168.100.147
tasks:
- name: bbb
yum:
name: vsftpd
state: present
register: install_result
- debug: var=install_result
[root@node1 node]#
运行该playbook时,debug模块用于将install_result注册变量的值转储到终端。
[root@node1 ansible]# ansible-playbook node/buhuo.yml
PLAY [q11] *******************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************
ok: [192.168.100.147]
TASK [bbb] *******************************************************************************************************
changed: [192.168.100.147]
TASK [debug] *****************************************************************************************************
ok: [192.168.100.147] => {
"install_result": {
"changed": true,
"failed": false,
"msg": "",
"rc": 0,
"results": [
"Installed: vsftpd-3.0.3-34.el8.x86_64"
]
}
}
PLAY RECAP *******************************************************************************************************
192.168.100.147 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
12.管理机密(ansible vault)
Ansible可能需要访问密码或API密钥等敏感数据,以便能配置受管主机。通常,此信息可能以纯文本形式存储在清单变量或其他Ansible文件中。但若如此,任何有权访问Ansible文件的用户或存储这些Ansible文件的版本控制系统都能够访问此敏感数据。这显示存在安全风险。
Ansible提供的Ansible Vault可以加密和解密任何由Ansible使用的结构化数据文件。若要使用Ansible Vault,可通过一个名为ansible-vault的命令行工具创建、编辑、加密、解密和查看文件。Ansible Vault可以加密任何由Ansible使用的结构化数据文件。这可能包括清单变量、playbook中含有的变量文件、在执行playbook时作为参数传递的变量文件,或者Ansible角色中定义的变量。
13.创建加密文件
要创建新的加密文件,可使用ansible-vault create filename命令。该命令将提示输入新的vault密码,然后利用默认编辑器vi打开文件。我们可以设置和导出EDITOR环境变量,通过设置和导出指定其他默认编辑器。例如,若要将默认编辑器设为nano,可设置为export EDITOR=nano
[root@node1 node]# ansible-vault create runtime.yml //创建加密文件
New Vault password: //输入新密码
Confirm New Vault password: //再次输入
[root@node1 node]# ls
ahh.yml buhuo.yml runtime.yml//可以看见有这个文件 shunzichishi sss test.yml vsftpd. vsftpd.yml
[root@node1 node]# cat runtime.yml //查看里面我们看不懂是个啥,因为加密了
$ANSIBLE_VAULT;1.1;AES256
65323633386164396165326362383937663831306261353934333433316238663432386637363536
3764356365316334363235313232363837303336306138360a616362366638313631333838363865
62633531626162303134373363366663363739396532383231313165303338663130643962666365
6239353130636332340a353761656566323330393434333465666461326266636439316238376132
66303038313830313165643331306534646235666536353036633761643865383935613264663934
6237643933323630396365366365333364643738653135616630
[root@node1 node]#
我们还可以用vault密码文件来存储vault密码,而不是通过标准输入途径输入vault密码。这样做需要使用文件权限和其他方式来严密保护该文件。
ansible-vault create --vault-password-file=vault-pass secret.yml
14.查看加密的文件
可以使用ansible-vault view filename命令查看Ansible Vault加密的文件,而不必打开它进行编辑。
[root@node1 node]# ansible-vault view runtime.yml //查看加密文件用view
Vault password: //但是在这里要密码,只有自己才能查看, 别人不能
ansible_user=root
ansible_password=1
[root@node1 node]#
15.编辑现有加密的文件
要编辑现有的加密文件,Ansible Vault提供了ansible-vault edit filename命令。此命令将文件解密为一个临时文件,并允许编辑。保存时,它将复制其内容并删除临时文件。
[root@node1 node]# ansible-vault edit runtime.yml //能进去编辑,但是要密码
Vault password:
[root@node1 node]# ansible-vault view runtime.yml
Vault password:
ansible_user=root fsafgafafaf //这是刚刚编写的内容
ansible_password=1
[root@node1 node]#
注意:编辑时需要输入加密文件的加密密码
edit子命令始终重写文件,因此只应在进行更改时使用它。要查看文件的内容而不进行更改时,应使用view子命令。
16.加密现有文件
要加密已存在的文件,请使用ansible-vault encrypt filename命令。此命令可取多个欲加密文件的名称作为参数。
[root@node1 node]# vim shen.yml
[root@node1 node]# ansible-vault encrypt shen.yml //注意这里是给已有的文件加密
New Vault password:
Confirm New Vault password:
Encryption successful
[root@node1 node]#
使用**–output=OUTPUT_FILE选项,可将加密文件保存为新的名称。只能通过–output**选项使用一个输入文件
17.解密现有文件
现有的加密文件可以通过ansible-vault decrypt filename命令永久解密。在解密单个文件时,可使用**–output**选项以其他名称保存解密的文件。
[root@node1 node]# ansible-vault decrypt shen.yml //这里是解密现有文件,前提是得知道密码
Vault password:
Decryption successful
[root@node1 node]# cat shen.yml
oiahirhiahfiah
[root@node1 node]#
18.更改加密文件的密码
使用ansible-vault rekey filename命令更改加密文件的密码。此命令可一次性更新多个数据文件的密钥。它将提示提供原始密码和新密码。
[root@node1 node]# ansible-vault rekey shen.yml
Vault password: //原来的密码
New Vault password: //输入新密码
Confirm New Vault password: //再次确认
Rekey successful
[root@node1 node]#
解密现有文件
现有的加密文件可以通过ansible-vault decrypt filename命令永久解密。在解密单个文件时,可使用**–output**选项以其他名称保存解密的文件。
[root@node1 node]# ansible-vault decrypt shen.yml //这里是解密现有文件,前提是得知道密码
Vault password:
Decryption successful
[root@node1 node]# cat shen.yml
oiahirhiahfiah
[root@node1 node]#
18.更改加密文件的密码
使用ansible-vault rekey filename命令更改加密文件的密码。此命令可一次性更新多个数据文件的密钥。它将提示提供原始密码和新密码。
[root@node1 node]# ansible-vault rekey shen.yml
Vault password: //原来的密码
New Vault password: //输入新密码
Confirm New Vault password: //再次确认
Rekey successful
[root@node1 node]#