目录
管理变量与事实
一,变量
1,变量命名
2,变量优先级(高--低)
3,命令行引用
4, 引用playbook中的变量
5, 在主机清单中定义变量
6, 在自定义变量文件中定义变量
7,在目录中定义清单变量
8,使用数组作为变量
9,系统变量register
二,使用ansible vault加密文件
1,创建加密文件(create)
2,查看加密文件内容(view)
3,使用文件内容作为加密密码(--vault-password-file=密码文件)
4,解密加密文件(decrypt)
5,将加密文件解密到指定文件中(--output 指定文件)
6,更改加密文件的密码(rekey)
7,使用文件更改加密文件的密码(rekey --new-vault-password-file=密码文件)
8,通过剧本加载加密文件(--vault-id @prompt )
三,管理事实
1,描述ansible事实
2,ansible事实实例
3,受管主机收集事实的方式
4,接收事实收集的方法
5,关闭事实收集
6,创建自定义事实
管理变量与事实
事实:主机上的默认定义的变量信息
一,变量
1,变量命名
变量名称必须是以字母开头,并且只能含有字母、数字和下划线。
2,变量优先级(高--低)
- (1)全局范围:从命令行或ansible配置设置的变量
- (2)play范围:在play和相关结构中设置的变量
- (3)主机范围:由清单、事实收集或注册的任务,在主机和个别主机上设置的变量
- 命令行定义变量--> yaml文件中的变量(vars_file ---> vars)--->主机清单中单独定义主机变量--->主机清单公共变量
3,命令行引用
变量要用两个花括号引起来,变量作为键值对的值必须用引号引起来
(1)在/day04/playbook目录下创建var_test.yml文件
此时的受控主机上node1没有vsftp软件包
[root@node1 ~]# rpm -qa | grep vsftpd
(2)在var_test.yml文件中安装软件包,在命令行把要安装的软件包传入到剧本中的变量
- name: play1
hosts: all
tasks: 装包
- name: task1
yum:
name: "{{ pkname }}"
state: present
(3)在命令行给变量传入变量值,并执行var_test.yml文件,在node1上安装vsftpd
[root@server playbook]# ansible-playbook -e "pkname=vsftpd" var_test.yml
(4)此时在node1主机上查看vsftpd,已经安装成功
[root@node1 ~]# rpm -qa | grep vsftpd
4, 引用playbook中的变量
(1)此时的node1主机上有vsftpd和bind
[root@node1 ~]# rpm -qa | grep vsftpd
[root@node1 ~]# rpm -qa | grep bind
(2) 在var_test.yml中定义变量 vars
在var_test.yml中定义vars
---
- name: play1
hosts: test1
vars:
pkname: vsftpd
tasks:
- name: task1
yum:
name: "{{ pkname }}"
state: absent
(3)在命令行定义变量为bind的同时在playbook中定义变量为vfstpd
[root@server playbook]# ansible-playbook -e "pkname=bind" var_test.yml
(4)执行完命令后,再次查看bind和vfstpd包,发现bind被删除了,但是vfstpd包还在
说明命令行中变量的优先级大于yaml文件中变量的优先级
[root@node1 ~]# rpm -qa | grep bind
[root@node1 ~]# rpm -qa | grep vsftpd
注: 引用变量中间有无空格都可以,变量用作开始一个值得第一元素时,必须使用引号防止ansible将变量引用视为yaml字典的开头。
5, 在主机清单中定义变量
(1)查看此时匹配到的主机清单文件
[root@server playbook]# ansible --version
(2)此时的node1主机与node2主机都有httpd与vsftpd
[root@node1 ~]# rpm -qa | grep httpd
[root@node1 ~]# rpm -qa | grep vsftpd
[root@node2 ~]# rpm -qa | grep vsftpd
[root@node2 ~]# rpm -qa | grep httpd
(3)打开主机清单文件,定义变量,对单个主机node1卸载httpd;对主机组node1与node2卸载vsftpd
node1 pkname=httpd
[test]
node1
node2
[test:vars]
pkname=vsftpd
(4)在剧本中定义变量
---
- name: play1
hosts: all
# vars:
# pkname: vsftpd
tasks:
- name: task1
yum:
name: "{{ pkname }}"
state: absent
(5)执行剧本var_test.yml
[root@server playbook]# ansible-playbook var_test.yml
(6)此时在node1主机上查看httpd与vsftpd;发现httpd已经被卸载了
[root@node1 ~]# rpm -qa | grep httpd
[root@node1 ~]# rpm -qa | grep vsftpd
(7)在node1主机上查看httpd与vsftpd;发现vsftpd已经被卸载了
[root@node2 ~]# rpm -qa | grep httpd
[root@node2 ~]# rpm -qa | grep vsftpd
说明主机清单中的变量优先匹配单个主机变量,其次匹配主机组中的变量,最后匹配嵌套主机组定义的变量值
6, 在自定义变量文件中定义变量
1,导入var_files文件定义变量
(1)此时的node1主机与node2主机上均存在bind
[root@node2 ~]# rpm -q bind
[root@node1 ~]# rpm -q bind
(2)在packages文件中定义变量(按照yml的语法格式定义)
[root@server playbook]# vim packages
pkname: bind
(3)把变量文件vars_files导入var_test.yml剧本中
---
- name: play1
hosts: all
# vars:
# pkname: vsftpd
vars_files:
- packages
tasks:
- name: task1
yum:
name: "{{ pkname }}"
state: absent
(4)执行剧本文件var_test.yml
[root@server playbook]# ansible-playbook var_test.yml
(5)此时在node1与node2主机上查看bind,发现已经被卸载
[root@node1 ~]# rpm -q bind
[root@node2 ~]# rpm -q bind
2,定义变量信息的同时导入变量文件
(1)此时的node1主机与node2主机上均没有bind与httpd
[root@node1 ~]# rpm -q bind
[root@node1 ~]# rpm -q httpd
[root@node2 ~]# rpm -q bind
[root@node2 ~]# rpm -q httpd
(2)在var_test.yml文件中定义变量使其安装httpd并导入变量文件packages
---
- name: play1
hosts: all
vars_files:
- packages
vars:
pkname: httpd
tasks:
- name: task1
yum:
name: "{{ pkname }}"
state: present
---
- name: play1
hosts: all
vars_files:
- packages
vars:
pkname: httpd
tasks:
- name: task1
debug:
msg: pkname={{ pkname }}
(3)编辑变量文件packages
[root@server playbook]# vim packages
pkname: bind
(3)执行var_test.yml剧本文件
[root@server playbook]# ansible-playbook var_test.yml
(8)在node1主机上与node2主机上查看httpd与bind;发现bind已经安装;
[root@node1 ~]# rpm -q httpd
[root@node1 ~]# rpm -q bind
[root@node2 ~]# rpm -q httpd
[root@node2 ~]# rpm -q bind
说明yaml文件中的变量(vars_file ---> vars)
总的来说:命令行定义变量--> yaml文件中的变量(vars_file ---> vars)--->主机清单中单独定义主机变量--->主机清单公共变量
3,一次性安装软件包httpd;vsftps;firewalld
(1)可以使用下列方法一次性传入多个参数
---
- name: play1
hosts: all
vars:
pkname:
- httpd
- vsftpd
- firewalld
tasks:
- name: task1
debug:
msg: pkname={{ pkname }}
(2)执行剧本文件var_test.yml
[root@server playbook]# ansible-playbook var_test.yml
注意:这种做法存在一些缺点,它是清单文件更难处理,在同一文件中混合提供了主机和变量信息,而且采用的也是过时的语法。
使用目录填充主机和组变量-----重要!!!
7,在目录中定义清单变量
建议的做法是使用host_vars和group_vars目录定义清单变量,而不直接在清单文件中定义。
---
- name: play1
hosts: all
tasks:
- name: task1
debug:
msg: pkname={{ pkname }}
(1)创建host_vars主机的变量目录和group_vars主机组的变量目录 目录定义清单变量
[root@server playbook]# mkdir host_vars group_vars
(2)在主机目录下面创建主机变量文件(针对node1主机创建变量文件)
[root@server playbook]# vim host_vars/node1
pkname: httpd
[root@server playbook]# mkdir group_vars/test
[root@server playbook]# vim group_vars/test/var.yml
pkname: vsftpd
(3)查看创建的目录的结构
[root@server playbook]# tree
(4)执行var_test.yml剧本文件
[root@server playbook]# ansible-playbook var_test.yml
(1)创建host_vars/node2目录并编辑文件var.yml
[root@server playbook]# mkdir host_vars/node2
[root@server playbook]# vim host_vars/node2/var.yml
pkname: mod_ssl
(2)查看目录及文件的结构
[root@server playbook]# tree
(3)执行剧本文件var_test.yml
[root@server playbook]# ansible-playbook var_test.yml
8,使用数组作为变量
数组(Array)是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数 组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数据元素的集合称为数组。
数组是用于储存多个相同类型数据的集合。
(1)创建目录
[root@server ~]# mkdir /day05/var_test -pv
(2)在目录/day05/var_test下创建文件ansible.cfg与inventory文件
[root@server var_test]# cp /day04/playbook/ansible.cfg .
[root@server var_test]# cp /day04/playbook/inventory .
(3)查看ansible.cfg文件以及inventory文件
[root@server var_test]# cat ansible.cfg
[defaults]
inventory=./inventory
[root@server var_test]# cat inventory
node1
[test]
node1
node2
(4)在目录/day05/var_test下面创建playbook.yml文件
[root@server var_test]# vim playbook.yml
变量引用方法一:
---
- name: play1
vars:
student:
zhangsan:
yuwen: 80
shuxue: 81
yingyu: 79
lisi:
yuwen: 90
shuxue: 91
yingyu: 92
hosts: test
tasks:
- name: task1
debug:
msg: 语文成绩是:{{ student.zhangsan.yuwen }}
(5)执行剧本
[root@server var_test]# ansible-playbook playbook.yml
变量引用方法二:
---
- name: play1
vars:
student:
zhangsan:
yuwen: 80
shuxue: 81
yingyu: 79
lisi:
yuwen: 90
shuxue: 91
yingyu: 92
hosts: test
tasks:
- name: task1
debug:
msg: 数学成绩是:{{ student['lisi']['shuxue'] }}
执行剧本playbook.yml
[root@server var_test]# ansible-playbook playbook.yml
方法一:
国家:
省份:
城市:
县:
镇:
方法二:
{{ 国家.省份.城市.县.镇 }}
方法三:
{{ 国家['省份']['城市']['县']['镇'] }}
msg 和 var 引用变量的区别:
var后面直接跟变量,不需要双引号与花括号
var: student['lisi']['shuxue']
msg后面需要花括号引用变量
msg: {{ student['lisi']['shuxue'] }}
9,系统变量register
使用register已注册变量捕获命令输出
管理员可以使用register语句捕获命令输出,输出保存在一个临时变量中,稍后再playbook中可用于调试用途或者达成其他目的。
注:msg 和var的区别msg 引用变量{{ }} ,var后面直接跟变量名名 |
eg: |
(1)在目录/day05/var_test下面编辑文件playbook1.yml
---
- name: play1
hosts: test
tasks:
- name: task1
copy:
dest: /file
content: "this is a file\n"
(2)执行剧本并没有显示详细信息
[root@server var_test]# ansible-playbook playbook1.yml
(3)使用register捕获详细信息存储到results变量中,并在debug模块捕获并显示
---
- name: play1
hosts: test
tasks:
- name: task1
copy:
dest: /file
content: "this is a file\n"
register: results
- name: task2
debug:
msg: "{{ results }}"
(4)执行剧本playbook1.yml可以看到捕获到的详细信息如下所示
[root@server var_test]# ansible-playbook playbook1.yml
(5)显示上面捕获到的详细信息中的size的信息
---
- name: play1
hosts: test
tasks:
- name: task1
copy:
dest: /file
content: "this is a file\n"
register: results
- name: task2
debug:
msg: "{{ results }}"
register: cmd_results
- name: task3
debug:
msg: "{{ cmd_results.msg.size }}"
(6)此时执行剧本playbook1.yml就能看到task3捕获到的size大小
二,使用ansible vault加密文件
ansible可能需要访问密码或者API秘钥等敏感数据,以便能配置受管主机。通常,此信息可能以纯文本形式存储在清单变量或其他ansible文件中。但若如此,任何有权访问ansible文件的用户或存储这些ansible文件的版本控制系统都能访问如此敏感数据。这显然存在安全风险。
使用ansible随附的ansible vault 可以加密和解密任何由ansible使用的结构化数据文件。若要使用ansible vault,可通过一个名为ansible-vault的命令行共计创建、编辑、加密、解密和查看文件。Ansible vault可以加密任何由ansible使用的结构化数据文件。这可能包括清单变量、playbook中含有的变量文件、在执行playbook时作为参数传递的变量文件,或者ansible角色中定义的变量。
注:ansible-vault并不实施自有的加密函数,而是使用外部python工具。文件通过利用AES256的对称加密(将密码用作机密秘钥)加以保护,这种方式并未得到第三方正式审核。
创建加密文件的常用参数:
creat: 创建加密文件
decrypt: 解密
edit: 进入编辑
view: 显示文件信息
encrypt: 加密
encrypt_string: 加密字符串
rekey: 重置
在目录/day05/playbook下面创建playbook2.yml文件
---
- name: play1
hosts: test
vars_files:
- user_var.yml
tasks:
- name: task1
user:
name: "{{ username }}"
password: "{{ pass }}"
state: present
1,创建加密文件(create)
(1)创建加密文件user_var.yml并输入加密文件的密码
[root@server var_test]# ansible-vault create user_var.yml
(2)生成加密后的密码
[root@node1 ~]# python3
>>> import crypt
>>> crypt.crypt('123456')
'$6$K37gjva7lG7U4Z0N$.F9RPUC4iHRtH35P/4Y2RhoYm47dwnQeGcNTMi/6eFs8eQYS.WtEkWKP0uWVaIQzl5nUADw3EIbYdXsL3WSJ90'
(3) 在加密文件中定义变量
username: xiao1
pass: '$6$K37gjva7lG7U4Z0N$.F9RPUC4iHRtH35P/4Y2RhoYm47dwnQeGcNTMi/6eFs8eQYS.WtEkWKP0uWVaIQzl5nUADw3EIbYdXsL3WSJ90'
(4)输入密码后会利用默认的编辑器vi打开文件进行编辑。也可通过EDITOR环境变量更改默认编辑器。
例如:将默认编辑器设置为vim,则设置export EDITOR=vim
[root@server var_test]# export EDITOR=vim
(5)此时查看问价user_var.yml会看到文件已经被加密
[root@server var_test]# cat user_var.yml
2,查看加密文件内容(view)
(1)输入加密文件的密码查看加密文件user_var.yml的内容
[root@server var_test]# ansible-vault view user_var.yml
3,使用文件内容作为加密密码(--vault-password-file=密码文件)
(1)创建文件p1
[root@server var_test]# vim p1
(2) 将p1文件的内容作为加密的密码
[root@server var_test]# ansible-vault create --vault-password-file=p1 v.yml
(3)查看加密文件v.yml文件的内容,用p1文件自动输入密码
[root@server var_test]# ansible-vault view --vault-password-file=p1 v.yml
4,解密加密文件(decrypt)
(1)对加密文件user_var.yml进行解密
[root@server var_test]# ansible-vault decrypt user_var.yml
(2)此时查看文件user_var.yml会看到文件未被加密的内容
[root@server var_test]# cat user_var.yml
5,将加密文件解密到指定文件中(--output 指定文件)
(1)将加密文件user_var.yml解密到vvv.yml文件中
[root@server var_test]# ansible-vault decrypt user_var.yml --output vvv.yml
(2)查看文件vvv.yml的内容
[root@server var_test]# cat vvv.yml
(3)注意:此时的文件user_var.yml并未被解密,
[root@server var_test]# cat user_var.yml
6,更改加密文件的密码(rekey)
将加密文件user_var.yml的密码由123456改为111111
[root@server var_test]# ansible-vault rekey user_var.yml
Vault password: 输入原来的密码
New Vault password: 输入修改后的密码
Confirm New Vault password: 再次确认密码
Rekey successful
7,使用文件更改加密文件的密码(rekey --new-vault-password-file=密码文件)
(1)将加密文件v.yml 文件的密码由p1文件的123456改为p2文件的111111
[root@server var_test]# vim p2
111111
(2)可以手动输入旧密码确认
[root@server var_test]# ansible-vault rekey --new-vault-password-file=p2 v.yml
(3)也可以通过文件p1确认旧密码
[root@server var_test]# ansible-vault rekey --vault-password-file=p1 --new-vault-password-file=p2 v.yml
8,通过剧本加载加密文件(--vault-id @prompt )
(1)可以看到playbook2.yml文件中需要加载文件user_var.yml;
[root@server var_test]# vim playbook2.yml
(2)而user_var.yml文件为加密文件
[root@server var_test]# cat user_var.yml
(3)此时,剧本无法直接加载文件playbook2.yml
[root@server var_test]# ansible-playbook playbook2.yml
(4)需要输入文件的密码才能加载文件,执行剧本文件
[root@server var_test]# ansible-playbook --vault-id @prompt playbook2.yml
Vault password (default): 需要手动输入文件user_var.yml的密码
(5)查看剧本的执行结果
[root@node1 ~]# id xiao1
三,管理事实
1,描述ansible事实
ansible事实是ansible在受管主机上自动检测到的变量。事实中含有主机相关的信息,可以像play中的常规变量、条件、循环或者依赖于受管主机收集的任何其他语句那样使用。(收集的系统属性)
受管主机的事实有(主机名称、内核版本、网络接口、ip地址、操作系统版本、各种变量、CPU数量、提供的或可用的内存、可用磁盘等)
借助事实我们可以方便检索主机的状态,并根据状态确定要执行的操作。
例如:
1.根据不同的内核版本事实运行条件任务,以此来重新启动服务。
2.根据事实报告的可能内存情况来定义mysql配置文件。
3.可根据事实的值设置配置文件中使用的ipv4的地址。
2,ansible事实实例
- 在Ansible2.5之前,事实是作为前缀为字符串ansible_的单个变量注入,而不是作为ansible_facts变量的一部分注入
- ansible_facts['distribution']事实会被称为ansible_distribution
ansible_facts形式 | 旧事实变量形式 |
ansible_facts['hostname'] | ansible_hostname |
ansible_facts['fqdn'] | ansible_fqdn |
ansible_facts'default_ipv4' | ansible_default_ipv4['address'] |
ansible_facts['interfaces'] | ansible_interfaces |
ansible_facts'devices''partitions'['size'] | ansible_devices'vda''vda1' |
ansible_facts'dns' | ansible_dns['nameservers'] |
ansible_facts['kernel'] | ansible_kernel |
ansible事实的事例
事实 | 变量 |
短主机名 | ansible_facts['hostname'] |
完全限定域名 | ansible_facts['fqdn'] |
主机ipv4地址 | ansible_facts'default_ipv4' ==== ansibe_facts.default_ipv4.address |
网络接口名称列表 | ansibel_facts['interfaces'] |
/dev/vda1磁盘分区大小 | ansible_facts'devices''partitions'['size'] |
DNS服务器列表 | ansible_facts'dns' ===ansible_facts'dns' |
当前运行的内核版本 | ansible_facts['kernel'] |
1,显示短的主机名
msg: "{{ ansible_facts.hostname }}"
执行剧本playbook3.yml文件,可以看到短的主机名
[root@server var_test]# ansible-playbook playbook3.yml
2,显示长的主机名
msg: "{{ ansible_facts.fqdn }}"
执行剧本playbook3.yml文件,可以看到长的主机名
[root@server var_test]# ansible-playbook playbook3.yml
3,显示ipv4地址
msg: "{{ ansible_facts.default_ipv4.address }}"
执行剧本playbook3.yml文件,可以看到ipv4的地址
[root@server var_test]# ansible-playbook playbook3.yml
4,显示网络接口名称列表
msg: "{{ ansible_facts.interfaces }}"
执行剧本playbook3.yml文件,可以看到网络接口名称列表
[root@server var_test]# ansible-playbook playbook3.yml
3,受管主机收集事实的方式
1. setup模块(变量信息 内置系统中的变量信息)
(1)系统的默认值,不能手动修改
[root@server var_test]# ansible node1 -m setup | less
(2)编辑playbook3.yml文件
[root@server var_test]# vim playbook3.yml
(3)过滤出ipv4的地址的值
匹配事实时,可以省略第一个相同的单词
---
- name: play1
hosts: node1
gather_facts: yes # 默认开启接收事实
tasks:
- name: task1
debug:
msg: "{{ ansible_facts.default_ipv4.address }}"
(4)执行剧本playbook3.yml,可以看到过滤出来的ipv4地址为192.168.206.111
[root@server var_test]# ansible-playbook playbook3.yml
4,接收事实收集的方法
方法一:gather_ facts: yes
方法二:
- name: task0
setup:
5,关闭事实收集
gather_facts: no
执行剧本文件playbook3.yml
[root@server var_test]# ansible-playbook playbook3.yml
如果不想从fact中获取变量,或者说整个playbook当中都没有使用到fact变量,可以通过如下方法关闭fact以提升执行效率:
也可以在ansible.cfg中添加如下配置:
[defaults]
gathering = explicit (明确的)
ansible的配置文件中可以修改'gathering'的值为smart、implicit或者explicit。
(1)smart 表示默认收集facts,但facts已有的情况下不会收集,即使用缓存facts;
(2)implicit 表示默认收集facts ;
(3)explicit 则表示默认不收集;
6,创建自定义事实
默认情况下setup模块从受管主机的/etc/ansible/facts.d目录下的文件和脚本中加载自定义事实。各个文件名必须以.fact结尾才能使用。动态自定义事实脚本必须输出JSON格式的事实,而且必须是可执行文件。
INI和JSON格式编写的静态自定义事实文件。INI格式的自定义事实文件包含由一部分定义的顶层值,后跟用于待定义事实的键值对。
(1)在受控主机node1上创建目录/etc/ansible/facts.d并在此目录下创建abc.fact结尾的文件
[root@node1 ~]# mkdir /etc/ansible/facts.d -pv
(2)在目录/etc/ansible/facts.d下面创建文件abc.fact
[root@node1 facts.d]# touch abc.fact
(3)编辑文件abc.fact内容
[users]
user1 = joe
user2 = jane
(4)在控制端主机server上捕获node1主机的uers1
msg: "{{ ansible_facts.ansible_local.abc.users.user1 }}"
(5)执行剧本playbook3.yml查看信息捕获到的use1的信息
[root@server var_test]# ansible-playbook playbook3.yml
(6)过滤出ansible_local对象下所有的值
[root@server var_test]# ansible node1 -m setup -a 'filter=ansible_local'