3.4 管理变量和事实
将 playbook 中的某些值使用变量代替,从而简化 playbook 的编写
3.4.1 管理变量
ansible 变量简介
变量可能包含下面这些值:
要创建的用户、
要安装的软件包、
要重启的服务、
要删除的文件、
要从互联网检索的文档
命名变量
变量名称必须以字母开头,并且只能含有字母、数字和下划线
错误 正确
web server web_server
westos.file remote_file
1file file1
定义变量
三个范围级别
全局范围:从命令行或 ansible 配置设置的变量
play 范围:在 play 和相关结构中设置的变量
主机范围:由清单、事实收集或注册的任务,在主机组和个别主机上设置的变量
‘如果多个级别上定义了相同名称的变量,优先采用级别最高的变量,窄范围优先于广范围’
3.4.2 playbook 中的变量
在 playbook 中定义变量
1.常见方式:在 playbook 开头的 vars 块中:
2.在外部文件定义 playbook 变量
cat user.yml
3.4.2 在 playbook 中使用变量
将变量名称放在大括号内即可
‘注意:当变量用作开始一个值的第一元素时,必须使用引号’
3.4.3 主机变量和组变量
直接应用于主机的清单变量分为两大类:
1.主机变量:应用于特定主机
2.组变量:应用于一个主机组或一组主机组中的所有主机
主机变量优先于组变量,但是 playbook 中定义的变量比这两者更高。
定义主机变量和组变量:
方法一(比较旧,不建议采用):
定义 server1.example.com 单用户的的 ansible_user 主机变量:
定义 dbservers 主机组的 user 组变量:
定义嵌套组 user 变量:
‘这种做法使的清单文件难以处理,在同一文件中混合提供主机和变量信息,语法也过时’
方法二:使用目录填充主机和组变量
定义主机和主机组变量的首选做法时与清单文件或目录相同的工作目录中,创建 group_vars
和 host_vars 两个目录,这两个目录分别包含用于定义组变量和主机变量的文件
创建 group_vars/servers 的 YAML 文件,设置变量为值:
user: student
同样需要在 host_vars 目录中创建名称与主机匹配的文件来存放主机变量
所以一个项目目录中包含:
ansible.cfg、group_vars、host_vars、inventory、playbook.yml
#从命令行覆盖变量
清单变量可以被 playbook 中设置的变量覆盖,两者又可通过命令行参数覆盖
#使用数组作为变量
访问方式:
users.lilei.first_name
users.hanmeimei.home_dir
变量被定义为 python 字典,可以使用替代语法:
users['lilei']['first_name']
users['hanmeimei']['home_dir']
#使用已注册变量捕获命令输出
管理员可以使用 register 语句捕获命令输出
---
- name: install
hosts: web
tasks:
- name: install http
yum:
name: httpd
state: installed
register: install_result
- debug: var=install_result
...
效果:
可以用debug看出操作的过程,其确保我们对过程的肯定。
###管理变量的练习
创建 playbook,来安装 apache 并开启,使可被访问,playbook 查询 web 服务器并确认它已经设置好并在运行。
变量名称:
web_pkg #要安装的 web 服务器软件包
firewall_pkg #要安装的防火墙软件包
web_service #要管理的 web 服务
firewall_service #要管理的防火墙服务
python_pkg #uri 模块所需软件包
rule #要打开的服务
- name: config Apache
hosts: web
vars:
web_pkg: httpd
firewall_pkg: firewalld
web_service: httpd
firewall_service: firewalld
python_pkg: python3-PyMySQL
rule: http
tasks:
- name: Install Package
yum:
name:
- "{{ web_pkg }}"
- "{{ firewall_pkg }}"
- "{{ python_pkg }}"
state: latest
- name: the {{ firewall_service }} started and enabled #确保 firewalld 和 apache 开机启动
service:
name: "{{ firewall_service }}"
enabled: true
state: started
- name: the {{ web_service }} started and enabled
service:
name: "{{ web_service }}"
enabled: true
state: started
- name: config index.html #配置默认发布页面
copy:
content: "hello westos!"
dest: /var/www/html/index.html
- name: Firewall permit http #使防火墙允许 http
firewalld:
service: "{{ rule }}"
permanent: true
state: enabled
- name: Verify the Apache #验证 apache 服务
hosts: localhost
become: false #在本机测试,不必更改身份
tasks:
- name: Curl webserver
uri:
url: http://rhe82.com
status_code: 200
#运行:
3.4.4管理机密
目标:使用 ansible-vault 加密敏感变量,并运行 vault 加密变量文件的 playbook。
介绍 ansible-vault
ansible 可能需要访问密码或者 api 密钥等敏感数据,以便配置主机。
加密解密工具:ansible-vault 命令
‘ansible vault 不实施自有的加密函数,而使用外部 python 工具集’
##创建加密文件
方法:ansible-vault create filename
需要输入密码
并且此时无法查看。
##创建加密文件同时将密码保存,westos 文件中必须先写入密码
##查看加密文件
方法:ansible-vault view filename
##编辑现有的加密文件
原理:将文件解密为一个临时文件,并编辑;保存时,复制内容并删除临时文件
‘edit 命令始终重写文件,因此只有在更改文件时使用,查看尽量使用 view’
##加密现有的文件
方法:ansible-vault encrypt filename #filename 参数可以是多个
可以使用–output=filename 将加密文件保存为新的名称,使用此参数时输入文件只能是一个
##解密现有的文件
方法:ansible-vault decrypt filename
##解密的同时改名
–output=filename
##更改加密文件密码
方法:ansible-vault rekey filename
‘可以一次更新多个文件密码’
#使用 vault 密码文件时,最好使用–net-vault-password-file
[root@workstation wsp]# ansible-vault rekey --new-vault-password-file=wsp
westos.yml
Vault password:
Rekey successful
##playbook 和 ansible-vault
#运行加密的 playbook,没有密码则报错
#交互式提供密码
‘2.4 之前的 ansible,使用–ask-vault-pass 提供交互式密码’
#也可以将秘密存在文件中(注意使用文件系统权限对文件进行保护)
ansible-playbook --vault-password-file=password user.yml
3.4.5管理事实######
事实包括:主机名称、内核版本、网络借口、IP 地址等
##描述 ansible 事实
#查看主机信息
var: ansible_facts #系统变量名,不用定义。
ansible-playbook fact.yml
##再将事实替换为动态的值
---
- name: fact
hosts : all
tasks:
- name: Print Facts
debug:
var: ansible_facts
- hosts: all
tasks:
- name: Print IP and dn
debug:
msg:
the IPv4 address of {{ ansible_facts.fqdn }} #使用字典的方式查询值
is {{ ansible_facts.all_ipv4_addresses }}
##ansible 事实作为变量注入
#使用 setup 模块显示所有事实信息
#关闭事实收集,开提升执行速度
cat user.yml
#运行
执行的时候就没有gather_facts这一项了。
##创建自定义事实
#可以使用 INI 格式或者 JSON 格式
##INI
[packages]
web_packages=httpd
da_packages=mariadb_server
[users]
user1=westos
user2=redhat
##JSON
{
"packages": {
"web_packages": "httpd",
"db_packages": "mariadb-server"
},
"users": {
"user1": "westos",
"user2": "redhat"
}
}
‘自定义格式不能使用 ymal 格式,使用最为接近ymal格式的 json 最好’
mkdir /etc/ansible/facts.d
vim /etc/ansible/facts.dcustom.fact #必须以.fact 结尾
"packages": {
"web_packages": "httpd",
"db_packages": "mariadb-server"
},
"users": {
"user1": "westos",
"user2": "redhat"
}
}
ansible localhost -m setup 查看我们定义的事实
‘自定义事实的使用方式和默认事实相同’
##使用魔法变量
常用的有四个:
hostvars | #包含受管主机的变量,可以用于获取另一台受管主机的变量的值 |
group_names | #列出 当前受管主机 所属的所有组 |
groups | #列出清单中的 所有组和主机 |
inventory_hostname | #包含 清单中配置的 当前受管主机的主机名称 |
#用途之一:使用 debug 模块报告特定主机的 hostvars 的值
ansible localhost -m debug -a 'var=hostvars["servera.lab.example.com"]'
##管理事实:练习 1
[root@workstation data-facts]# ansible rhel82.com -m setup #显示信息
可以显示。
创建自定义变量
vim westos.fact
创建 playbook
vim facts.yml
---
- name: Install fact
hosts: web
vars:
remote_dir: /etc/ansible/facts.d
facts_file: westos.fact
tasks:
- name: Create directory
file:
state: directory
recurse: yes
path: "{{ remote_dir }}"
- name: copy file facts
copy:
src: "{{ facts_file }}"
dest: "{{ remote_dir }}"
...
运行:
目录已经建立且文件传过去了。
编写主 playbook
---
- name: INstall Apache
hosts: web
tasks:
- name: Install package
yum:
name: "{{ ansible_facts['ansible_local']['westos']['westos']['package'] }}"
state: latest
- name: statr apache
service:
name: "{{ ansible_facts['ansible_local']['westos']['westos']['service'] }}"
state: "{{ ansible_facts['ansible_local']['custom']['westos']['state'] }}"
enabled: "{{ ansible_facts['ansible_local']['custom']['westos']['enabled'] }}"
#验证 httpd 服务没有在 servera 上运行
ansible servera.lab.example.com -m command -a 'systemctl status httpd'
可见82主机上并没有安装httpd服务。
#语法检测
#运行