目录
3.3、魔法变量hostvars、group_names、groups、inventory_hostname
一、管理变量
1.1、变量的基本用法
Ansible 支持利用变量来存储值,并在 Ansible 项目的所有文件中重复使用这些值。变量的名称必须以字母开头,并且只能含有字母、数字和下划线
定义变量范围:
- 全局范围:从命令行或 Ansible 配置设置的变量
- Play 范围:在 play 和相关结构中设置的变量
- 主机范围:由清单、事实收集或注册的任务、在主机组和个别主机上设置的变量
变量优先级,如果在多个级别上定义了相同名称的变量,则采用优先级别最高的变量。常用的(需要我们记住的)优先级:命令行中定义的变量 > playbook 定义的变量 > 清单定义的变量
不需要我们记住的(用时候再查文档)优先级,从上到下优先级由高到低
1、ansible-playbook 命令中的变量,ansible-playbook -e var=value |
2、task 变量 |
3、block 变量 |
4、role 中定义的变量 和 include 变量 |
5、set_fact |
6、registered 变量 |
7、vars_files |
8、var_prompt |
9、play 变量 |
10、host facts |
11、playbook 中设置的 host_vars |
12、playbook 中设置的 group_vars |
13、inventory 中设置的 host_vars |
14、inventory 中设置的 group_vars |
15、inventory 变量 |
16、role 中 defaults/main.yml 中定义的变量 |
常用的定义变量方法一:通过 vars 直接定义变量
- hosts: all
vars:
db_name: foo_db
db_user: foo_user
常用的定义变量方法二:通过 vars_files 外部文件引入变量
- hosts: all
vars_files: vars/dbs.yml
# vars/dbs.yml 内容
db_name: foo_db
db_user: foo_user
通过 {{ 变量名 }} 引用变量。当变量用作开始一个值的第一元素时,必须使用引号。
vars:
db_name: foo_db
tasks:
- name: Create database
mysql_db:
name: "{{ db_name }}"
state: present
常用的定义变量方法三:主机变量、组变量是应用于特定主机、组的变量。使用目录填充主机和组变量的推荐做法:是在与清单文件或目录相同的工作目录中,创建 group_vars 和 host_vars 两个目录。这两个目录分别包含用于定义组变量和主机变量的文件。比如,
- 为了定义用于 servera.lab.example.com 主机的主机变量,需要创建名为 host_vars/servera.lab.example.com 的YAML文件,然后设置变量
- 为了定义用于 webservers 组的组变量,需要创建名为 group_vars/webservers 的 YAML文件,然后设置变量
1.2、使用已注册变量捕获命令输出
可以使用 register 语句捕获命令输出。输出保存在一个临时变量中,稍 后在 playbook中 可用于调试用途或者达成其他目的。比如,我们把访问网页的输出注册为web_content,把访问mysql数据库的输出注册为db_content。然后在debug的时候输出,注册变量的内容包括多个字段,我们只显示我们需要的内容。
[student@workstation ansible]$ cat web_test.yml
---
- name: Test web page
hosts: webservers
tasks:
- name: Access url get http200
uri:
url: http://serverc.lab.example.com/
status_code: 200
return_content: yes
register: web_content
- name: Show web page
debug:
var: web_content.content
- name: Test mariadb
hosts: dev
tasks:
- name: Show databases
shell: 'mysql -uroot -e "show databases;"'
register: db_content
- name: Show databases result
debug:
var: db_content.stdout_lines
二、管理加密
Ansible可能需要访问密码或API密钥等敏感数据,以便能配置受管主机。Ansible Vault可以加密和解密任何由Ansible使用的结构化数据文件。可通过一个名为 ansible-vault 的命令行工具创建、编辑、加密、解密和查看文件。Ansible Vault并不实施自有的加密函数,而是使用外部Python工具集。采用对称加密。
2.1、ansible-vault常用场景
使用ansibl-vault命令创建、编辑、查看文件,分别用create、edit、view。修改密码使用rekey。
[student@workstation ansible]$ ansible-vault create users.yml
[student@workstation ansible]$ ansible-vault edit users.yml
[student@workstation ansible]$ ansible-vault view users.yml
[student@workstation ansible]$ ansible-vault rekey users.yml
使用ansible-vault对文件加解密,使用encrypt、decrypt。比如对明文temp.yml进行加密,再解密成明文temp2.yml。
[student@workstation ansible]$ ansible-vault encrypt temp.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[student@workstation ansible]$ cat temp.yml
$ANSIBLE_VAULT;1.1;AES256
34623033613639643331383834333939623633343261613865306666623662666266336362646365
3031376464323862386134616136326630613536666166630a666635633834336436636230323461
63633163653232623333333037356234333132386239653835383565343236663561303765323266
3161366338313930620a616364366236303065653632663031376665653832383230323164633835
63396133626334373339313264666531306335343538333264323166633562306662326465353563
6531613731306166303866653330623064373230643164363965
[student@workstation ansible]$ ansible-vault decrypt temp.yml --output=temp2.yml
Vault password:
Decryption successful
[student@workstation ansible]$ cat temp2.yml
---
- hosts: all
vars_files:
- users.yml
如果 playbook 使用 的所有 vault 加密文件都使用同一密码,则可以使用 --ask-vault-pass 选项以交互方式提供 vault 密码。也可使用 --vault-password-file 选项指定以纯文本存储加密密码的文件。比如,playbook里面引用了加密的变量文件users.yml,我们把密码放在vpass.txt文件里。
- hosts: all
vars_files:
- users.yml
[student@workstation ansible]$ ansible-vault view users.yml --vault-password-file=vpass.txt
users:
- name:joe
password:redhat
- name:jane
password:centos
[student@workstation ansible]$ ansible-playbook temp.yml --vault-password-file=vpass.txt
如果playbook使用的 vault 加密文件密码不同,那么可以使用 --vault-id @prompt 选项逐个交互输入密码。比如,playbook引用两个密码不一样的变量文件users.yml、databases.yml。
---
- hosts: all
vars_files:
- users.yml
- databases.yml
[student@workstation ansible]$ ansible-playbook temp.yml --vault-id one@prompt --vault-id two@prompt
Vault password (one):
Vault password (two):
管理变量加密的推荐做法是:可将敏感变量和所有其他变量保存在相互独立的文件中。包含敏感变量的文件用 ansible-vault 命令进行加密。使用 group_vars 管理组变量,host_vars 管理主机变量。
三、管理事实
3.1、事实基本用法
Ansible 事实是 Ansible 在受管主机上自动检测到的变量。事实中含有与主机相关的信息。为受管主机收集的一些事实可能包括
- 主机名称
- 内核版本
- 网络接口
- IP地址
- 操作系统版本
- 各种环境变量
- CPU数量
- 提供的或可用的内存
- 可用磁盘空间
通常,每个 play 在执行第一个任务之前会先自动运行 setup 模块来收集事实。 在 Ansible 中 报告为 Gathering Facts 任务。
查看事实,可以运行一个收集事实的task,并使用 debug 模块显示 ansible_facts 变量。运行这个 playbook 之后,playbook 将以 JSON 格式显示 ansible_facts 变量的内容。
[student@workstation ansible]$ vim print_facts.yml
- name: Print facts
hosts: dev
tasks:
- name: Print all facts of dev
debug:
var: ansible_facts
ansible_facts 可以见名知意,常用的有:
- ansible_facts.hostname 主机名
- ansible_facts.fqdn FQDN
- ansible_facts.default_ipv4.address IP地址
- ansible_facts.devices /dev目录下的块设备/dev/sda、/dev/sda1、lvm等
- ansible_facts.kernel 内核
收集事实可能耗费时间。在不需要收集事实的 playbook 中可以通过 gather_facts 关闭事实收集。在需要的时候,通过一个 setup 模块的任务即可手动收集。
[student@workstation ansible]$ vim facts.yml
---
- name: Facts
hosts: dev
gather_facts: no
tasks:
- name: Here no facts
debug:
msg: "Here no facts"
- name: Gather facts mannually
setup:
- name: Here is facts
debug:
msg: " {{ ansible_facts.kernel }}"
[student@workstation ansible]$ ansible-playbook facts.yml
PLAY [Facts] ***********************************************************************************
TASK [Here no facts] ***************************************************************************
ok: [servera.lab.example.com] => {
"msg": "Here no facts"
}
TASK [Gather facts mannually] ******************************************************************
ok: [servera.lab.example.com]
TASK [Here is facts] ***************************************************************************
ok: [servera.lab.example.com] => {
"msg": " 4.18.0-240.el8.x86_64"
}
3.2、创建自定义事实
自定义事实采用JSON格式编写,一般命名为 xxxx.fact ,使用时将自定义事实文件放在受管主机的 /etc/ansible/facts.d/ 目录。执行 setup 模块时,自定义事实放在 ansible_facts.ansible_local.xxxx 变量中,用法和默认事实一样。
举例,在控制节点上编辑 myfact.fact 自定义事实,受管主机上创建 /etc/ansible/facts.d/ 目录并安装自定义事实 myfact.fact ,使其具有自定义事实ansible_facts.ansible_local.myfact。
[student@workstation ansible]$ vim myfact.json
{
"users": {
"user1": "tom",
"user2": "jerry",
},
"packages": {
"db_pkg": "mariadb-server",
"web_pkg": "httpd",
},
}
[student@workstation ansible]$ vim myfact.yml
---
- name: Custom facts
hosts: webservers
vars:
remote_dir: /etc/ansible/facts.d/
facts_file: myfact.json
tasks:
- name: Create directory
file:
path: "{{ remote_dir }}"
state: directory
recurse: yes
- name: Install custom facts
copy:
src: "{{ facts_file }}"
dest: "{{ remote_dir }}"
[student@workstation ansible]$ ansible webservers -m setup | less
......
...skipping...
"ansible_local": {
"myfact": {
"packages": {
"db_pkg": "mariadb-server",
"web_pkg": "httpd"
},
"users": {
"user1": "tom",
"user2": "jerry"
}
}
},
.......
3.3、魔法变量hostvars、group_names、groups、inventory_hostname
有些变量并不通过 setup 模块来获取,由ansible自动配置,可以获取特定受管主机信息。
hostvars 包含受管主机的变量,可以在一个受管主机上获取另一个受管主机的变量。比如,在test组上获取servera的事实。或者为 webservers 组主机生成 /etc/hosts 文件,里面包含所有受管主机的 IP地址、主机名、FQDN。
[student@workstation ansible]$ ansible test -m debug -a 'var=hostvars["servera.lab.example.com"]'
group_names 当前受管主机所属的所有组。比如,servera属于dev组,serverc属于prod、webservers这两个组。
[student@workstation ansible]$ ansible servera.lab.example.com -m debug -a "var=group_names"
servera.lab.example.com | SUCCESS => {
"group_names": [
"dev"
]
}
[student@workstation ansible]$ ansible serverc.lab.example.com -m debug -a "var=group_names"
serverc.lab.example.com | SUCCESS => {
"group_names": [
"prod",
"webservers"
]
}
groups 列出清单中所有组和主机。比如,使用 groups.all 可以遍历所有主机。
[student@workstation ansible]$ ansible dev -m debug -a "var=groups"
servera.lab.example.com | SUCCESS => {
"groups": {
"all": [
"servera.lab.example.com",
"serverb.lab.example.com",
"serverc.lab.example.com",
"serverd.lab.example.com"
],
"dev": [
"servera.lab.example.com"
],
"prod": [
"serverc.lab.example.com",
"serverd.lab.example.com"
],
"test": [
"serverb.lab.example.com"
],
"ungrouped": [],
"webservers": [
"serverc.lab.example.com",
"serverd.lab.example.com"
]
}
}
inventory_hostname 当前受管主机在 inventory 中的主机名。这个名字可能和主机的hostname不一样。
[student@workstation ansible]$ ansible dev -m debug -a "var=inventory_hostname"
servera.lab.example.com | SUCCESS => {
"inventory_hostname": "servera.lab.example.com"
}