管理变量、机密和事实

1变量管理

1.1变量的作用

将playbook中的某些值使用变量代替,从而简化playbook,简化项目的创建和维护,并减少错误的数量。

总结

  1. 变量能够让playbook重复使用
  2. 可以给清单文件中的主机和主机组定义变量
  3. 可以使用事实和外部文件定义变量,也可以在命令行中定义变量
  4. register关键字可以用于捕获命令输出
  5. ansible事实是从受管主机上检测到的变量

1.2ansible变量介绍

变量可能包含下面的值

  • 要创建的用户
  • 要安装的软件包
  • 要重启的服务
  • 要删除的文件
  • 要从互联网上检索的文档

1.3变量的范围

在Ansible项目中的多个位置定义变量。不过,这些变量大致可简化为三个范围级别

级别范围
Global(全局范围)由配置环境变量和命令行设置
play(play范围)在play和相关结构中设置的变量,包括vars条目(vars; vars_files; vars_prompt),角色默认值
Host(主机范围)由清单、事实收集或注册的任务,在主机组和个别主机上设置的变量

如果多几个级别上定义相同名称的变量,优先级采用级别更高的变量,窄范围优先于更广泛的范围:由清单定义的变量将被playbook定义的变量覆盖,后者将被命令行中定义的变量覆盖

变量的优先级

  • 命令行(-e)
  • playbook(vars, vars_files)
  • host_vars
  • group_vars
  • 清单文件

1.4变量的命名

  • 只能包含字母,数字和下划线
  • 不能出现Python关键字或剧本关键字
  • 不能以数字开头
无效变量名称有效变量名称
web serverweb-server
remote.fileremote.file
1st filefile_1 file1
remoteserver$1remote_server_1 remote_server1

1.5在playbook中定义变量

1.5.1在playbook中开头的vars中定义变量

[root@ansible ansible]# cat playdemo/test.yml
---
- hosts: 192.168.25.130
  gather_facts: no
  vars:
    IP: 172.168.25.131    //在playbook开头的vars中定义变量
    NAME: node1
  tasks:
    - name: test
      lineinfile:
        path: /etc/hosts
        line: "{{ IP }} {{ NAME }}"
        state: present

[root@node1 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
 
172.168.25.131 node1

1.5.2在外部文件定义playbook变量

在外部文件中定义playbook变量不使用playbook中的vars块,改为使用vars_files指令,后面跟上相对于playbook位置的外部变量文件名称列表

[root@ansible ansible]# mkdir vars    //创建变量文件
[root@ansible ansible]# vim vars/test.yml
[root@ansible ansible]# cat vars/test.yml
IP: 192.168.25.132
NAME: node2

[root@ansible ansible]# cat playdemo/vars/test.yml 
IP: 192.168.25.132    ///变量文件中指定的变量
NAME: node2

[root@ansible ansible]# cat playdemo/test.yml 
---
- hosts: 192.168.25.130
  gather_facts: no
  vars_files:
    - vars/test.yml    //外部变量文件路径名称
  tasks:
    - name: test
      lineinfile:
        path: /etc/hosts
        line: "{{ IP }} {{ NAME }}"
        state: present

[root@node1 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
 
172.168.25.131 node1
192.168.25.132 node2

注意:

  1. 将变量名称放在花括号内即可
  2. 当变量用过开始一个值的第一个元素时,必须使用引号
  3. 外部变量文件必须和play在同一个级别
[root@ansible ansible]# tree
.
├── ansible.cfg
├── hosts
├── inventory
├── playdemo
│   ├── firewalld.yml
│   ├── httpd
│   │   ├── conf.yml
│   │   └── httpd.yml
│   ├── install
│   │   └── install.yml
│   ├── php
│   │   └── php.yml
│   ├── test.yml
│   └── vars
│       └── test.yml
└── roles

1.6变量的分类

直接应用于主机的清单变量分为两类

  • 主机变量: 应用于特定主机
  • 组变量: 应用于一个主机组或一组主机组中的所有主机

定义主机变量和组变量,一种方法是直接在清单文件中定义。这是较旧的做法,不建议采用。

缺点: 使得清单文件更难以处理,在同一文件中混合提供了主机和变量信息,而且采用的也是过时的语法。

1.6.1定义主机变量和组变量(第一种方法)

  1. 定义192.168.25.130的主机变量
[root@ansible ansible]# cat inventory 

[webservers]
192.168.25.130  ansible_user=root ansible_password=1

  1. 定义server主机组的变量

[webservers]
192.168.25.130  ansible_user=root ansible_password=1
192.168.25.140  ansible_user=root ansible_password=1
192.168.25.142  ansible_user=root ansible_password=1

[webservers:vars]
user=root
passwd=1
~                                      
  1. 定义servers组的user组变量,该组由两个主机组成,每个主机组有两个服务器
[webservers1]
192.168.25.130   node1
192.168.25.140   node2

[webservers2]
192.168.25.142   node3

[webservers:children]
webservers1
webservers2

[webservers:vars]
user=root

1.6.2使用目录填充主机和组变量(第二种方法)

定义主机组和主机变量的首选做法:(在与清单文件或目录相同的工作目录中)

  1. 创建group_vars(包含组变量)和host_vars(包含主机变量)两个目录
  2. 创建group_vars/servers的yaml文件,该文件的内容将使用与playbook相同的语法将变量设置为值
  3. 在host_vars目录中创建名称与主机名匹配的文件来存放主机变量

主机变量

[root@ansible ansible]# cat inventory 

[webservers]
192.168.25.130  

[root@ansible ansible]# cat host_vars/192.168.25.130 
ansible_user: root
ansible_password: 1

[root@ansible ansible]# ansible 192.168.25.130 -m ping
192.168.25.130 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}

如果要为每个数据中心定义不同的值,可以为每个数据中心主机组设置组变量

[root@localhost ~]# vim ~/project/groupo_vars/webserver
package: httpd
[root@localhost ~]# vim ~/project/groupo_vars/webserver2
package: apache

1.7从命令行覆盖变量

清单变量可被playbook中设置的变量覆盖,这两种变量又可通过在命令行中传递参数到ansible或ansible-playbook命令来覆盖。在命令行上设置的变量称为额外变量

当需要覆盖一次性运行的playbook的变量的已定义值时,额外变量非常有用

ansible-playbook  -e "ip=1.1.1.1"

1.8使用数组作为变量

除了将同一元素相关的配置数据(软件包列表、服务列表和用户列表等)分配到多个变量外,也可以使用数组,好处是数组是可以浏览的

[root@ansible ansible]# cat host_vars/192.168.25.130 
ansible_user: root
ansible_password: 1

info:
  node4:
    IP: 4.4.4.4
    NAME: 4
  node5:
    IP: 5.5.5.5
    NAME: 5

[root@ansible ansible]# cat playdemo/test.yml 
---
- hosts: 192.168.25.130
  gather_facts: no
  tasks:
    - name: test
      lineinfile:
        path: /etc/hosts
        line: "{{ info.node4.IP }} {{ info.node4.NAME }}"
        state: present


[root@node1 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
 
172.168.25.131 node1
192.168.25.132 node2
4.4.4.4 4

由于变量被定义为Python字典,因此可以使用替代语法

# Returns 'Bob'
users['bjones']['first-name']

# Returns '/users/acook'
users['acook']['home_dir']

如果键名与python方法或属性的名称(如discard、copy和add)相同,点表示法可能会造成问题。使用中括号表示法有助于避免冲突和错误,建议在任何给定Ansible项目的所有文件中一致地采用一种语法,不要混用。

1.9使用已注册变量捕获命令输出

  • 注册变量是主机级变量。在具有循环的任务中注册变量时,注册的变量包含循环中每个项目的值。在循环期间放置在变量中的数据结构将包括一个results属性,该属性是模块中所响应的列表
  • 使用task关键字从ansible任务的输出中创建变量register,输出保存在一个临时变量中,可以在剧本的任何后续任务中使用注册的变量

playbook演示如何调试用途捕获命令输出

[root@ansible ansible]# cat playdemo/test.yml 
---
- hosts: 192.168.25.130
  gather_facts: no
  tasks:
    - name: test
      command: "echo hello word"
      register: install_result

    - debug: var=install_result
        

运行该playbook时,debug模块用于将install_result注册变量的值转储到终端

[root@ansible ansible]# ansible-playbook  playdemo/test.yml 

PLAY [192.168.25.130] ************************************************************************

TASK [test] **********************************************************************************
changed: [192.168.25.130]

TASK [debug] *********************************************************************************
ok: [192.168.25.130] => {
    "install_result": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/libexec/platform-python"
        },
        "changed": true,
        "cmd": [
            "echo",
            "hello",
            "word"
        ],
        "delta": "0:00:00.007640",
        "end": "2021-07-21 11:35:01.206850",
        "failed": false,
        "rc": 0,
        "start": "2021-07-21 11:35:01.199210",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "hello word",
        "stdout_lines": [
            "hello word"
        ]
    }
}

PLAY RECAP ***********************************************************************************
192.168.25.130             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

将注册变量的值输出打印到指定目录

[root@ansible ansible]# cat playdemo/test.yml 
---
- hosts: 192.168.25.130
  gather_facts: no
  tasks:
    - name: test
      command: "echo hello word"
      register: install_result

    - name: create file
      shell: "echo {{ install_result['stdout'] }} > /opt/abc"
        
[root@ansible ansible]# ansible-playbook  playdemo/test.yml 


PLAY [192.168.25.130] ************************************************************************

TASK [test] **********************************************************************************
changed: [192.168.25.130]

TASK [create file] ***************************************************************************
changed: [192.168.25.130]

PLAY RECAP ***********************************************************************************
192.168.25.130             : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@node1 opt]# cat abc 
hello word

使用date打印输出时间

[root@ansible ansible]# cat playdemo/test.yml
---
- hosts: 192.168.25.130
  gather_facts: no
  tasks:
    - name: test
      command: "date"
      register: install_result

    - name: create file
      shell: "echo {{ install_result['stdout'] }} > /opt/abc"
        
[root@ansible ansible]# ansible-playbook  playdemo/test.yml 

PLAY [192.168.25.130] ************************************************************************

TASK [test] **********************************************************************************
changed: [192.168.25.130]

TASK [create file] ***************************************************************************
changed: [192.168.25.130]

PLAY RECAP ***********************************************************************************
192.168.25.130             : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@node1 opt]# cat abc 
2021年 07月 21日 星期三 12:14:57 EDT

2管理机密

2.1Ansible Vault

在使用ansible时,会涉及到一些敏感文件的文件的操作,但实际需求中,我们并不希望ansible的用户,可以对该文件进行查看,故需要对一些文件在ansible的使用过程中加密,以保证系资料的安全性

  • Ansible提供的Ansible Vault可以加密和解密任何由Ansible使用的结构化数据文件
  • 若要使用Ansible Vault,可以通过一个名ansible-vault的命令行工具创建,编辑,加密,解密和查看
  • Ansible Vault可以加密任何由Ansible使用的结构化数据文件。包括清单变量,playbook中含有的变量文件,以及在执行playbook时作为参数传递的变量文件,或者ansible角色中定义的变量

2.1.1使用ansible-vault创建加密文件

  1. 使用ansible-vault filename命令创建加密的文件,该命令在执行时会提示输入新的vault密码,然后利用默认编译器vi打开
[root@ansible ansible]# ansible-vault create runtime.yml
New Vault password: 
Confirm New Vault password: 
[root@ansible ansible]# file runtime.yml 
runtime.yml: ASCII text      //文件已加密
[root@ansible ansible]# cat runtime.yml 
$ANSIBLE_VAULT;1.1;AES256
31346661363264633665353638656536666239333534353366356235393132303065356466343034
6161376165633437633361356137393663613038303030320a613863376133383361646162373865
66623365366536323562376635613538336564353834306339653938616265626637656636313535
3535333730633633300a306130636136326631386630646537323162623837363932303637666334
3665

  1. 使用vault密码文件来存储vault密码,而不是通过标准输入途径vault密码,这样做需要使用文件权限和其他方式来严格保护文件
[root@ansible ansible]# cat runtime       //创建密码文件
123456
[root@ansible ansible]# ansible-vault create --vault-password-file=/etc/ansible/runtime  ll.yml        //创建加密yaml文件
[root@ansible ansible]# cat ll.yml 
$ANSIBLE_VAULT;1.1;AES256
62313564326332383737396665336233633966306231336437376263363464313662356534343237
3236373539396434663064653865393261336434303635370a633832333463373630313561656333
37623533636533623736613335623930383030666236313162313264363236643038633739353334
3162356262343530360a383263333533396265373465363735613635386635636435323536643464
3161

2.1.2查看加密的文件

  1. 使用ansible-vault view filename命令查看ansible vault加密的文件,而不必打开它进行编辑
[root@ansible ansible]# cat ll.yml 
$ANSIBLE_VAULT;1.1;AES256
62313564326332383737396665336233633966306231336437376263363464313662356534343237
3236373539396434663064653865393261336434303635370a633832333463373630313561656333
37623533636533623736613335623930383030666236313162313264363236643038633739353334
3162356262343530360a383263333533396265373465363735613635386635636435323536643464
3161
[root@ansible ansible]# ansible-vault view ll.yml 
Vault password: 
jjkk

  1. 指定存储vault的密码文件来查看ansible vault加密的文件,不必手动输入密码
[root@ansible ansible]# cat ll.yml 
$ANSIBLE_VAULT;1.1;AES256
62313564326332383737396665336233633966306231336437376263363464313662356534343237
3236373539396434663064653865393261336434303635370a633832333463373630313561656333
37623533636533623736613335623930383030666236313162313264363236643038633739353334
3162356262343530360a383263333533396265373465363735613635386635636435323536643464
3161
[root@ansible ansible]# ansible-vault view --vault-password-file=/etc/ansible/runtime ll.yml 
jjkk

2.1.3 编辑现有的加密文件

编辑已加密的文件,使用ansible vault提供的ansible-vault edit filename命令继续编辑已加密文件;此命令将文件解密为一个临时文件,并允许编辑。保存时,它将复制其内容并删除临时文件。

[root@ansible ansible]# ansible-vault view --vault-password-file=/etc/ansible/runtime ll.yml 
jjkk
[root@ansible ansible]# ansible-vault edit --vault-password-file=/etc/ansible/runtime ll.yml 
[root@ansible ansible]# ansible-vault view --vault-password-file=/etc/ansible/runtime ll.yml 
root
port

2.1.4加密和解密现有的未加密文件

  1. 使用ansible-vault encrypt filename加密现有的未加密的文件;此命令可以一次加密多个现有的未加密的文件
[root@ansible ansible]# cat runtime 
123456
[root@ansible ansible]# ansible-vault encrypt runtime 
New Vault password: 
Confirm New Vault password: 
Encryption successful
[root@ansible ansible]# cat runtime 
$ANSIBLE_VAULT;1.1;AES256
30626435646535373631626661613264383133386230313666333134343438333563643162623637
3937363461353562396462343739336135356661333930360a366366623633646266613732626631
30326563333961346637313365663332303036336666313666346261346139303866633437316463
3465336231613731330a363130646464386664633966343933363234376363623830343364383239
6132

  1. 使用–output选项将需要加密的文件加密后另存为具有新名称的文件,一次只能有一个输入文件
[root@ansible ansible]# ansible-vault encrypt runtime --output=test
New Vault password: 
Confirm New Vault password: 
Encryption successful
[root@ansible ansible]# ls
ansible.cfg  group_vars  hosts  host_vars  inventory  ll.yml  playdemo  roles  runtime  test
[root@ansible ansible]# cat test 
$ANSIBLE_VAULT;1.1;AES256
31396566343438336234663961326637663862393839336534636262346164343736643866366330
3330343735316435346633323633623363333263636661630a393837316565653364663739386134
62636463623766626639336662646133653437623738323239666335386634666537356539336233
3661356234633830300a656264306365363737623162613433393937663537373534313931383330
3837

  1. 使用ansible-vault decrypt filename解密现有的已加密的文件,并且永久解密
[root@ansible ansible]# ansible-vault decrypt runtime 
Vault password: 
Decryption successful
[root@ansible ansible]# cat runtime 
123456

  1. 使用–output选项将需要解密的文件解密后另存为具有新名称的文件
[root@ansible ansible]# cat test 
$ANSIBLE_VAULT;1.1;AES256
31396566343438336234663961326637663862393839336534636262346164343736643866366330
3330343735316435346633323633623363333263636661630a393837316565653364663739386134
62636463623766626639336662646133653437623738323239666335386634666537356539336233
3661356234633830300a656264306365363737623162613433393937663537373534313931383330
3837
[root@ansible ansible]# ansible-vault decrypt test --output=jj
Vault password: 
Decryption successful
[root@ansible ansible]# cat jj
123456

2.1.5 更改加密文件的密码

  1. 使用ansible-vault rekey filename命令更改已经加密的文件的密码;此命令一次可以更改多个已经加密文件的密码
[root@ansible ansible]# ansible-vault view runtime 
Vault password:       //输入密码123
123456
[root@ansible ansible]# ansible-vault rekey runtime 
Vault password: 
New Vault password:      //密码123456
Confirm New Vault password: 
Rekey successful
[root@ansible ansible]# ansible-vault view runtime 
Vault password:       //输入密码123456
123456

  1. 使用vault文件作为面密码:使用–new-vault-password-file选项指定更改的密码
[root@ansible ansible]# ansible-vault rekey --new-vault-password-file=/etc/ansible/runtime ll.yml 
Vault password: 
Rekey successful

2.2playbook和ansible vault

要运行可访问通过Ansible Vault加密的文件的playbook,需要向ansible-playbook命令提供加密密码。如果不提供密码,playbook将返回错误

[root@ansible ansible]# ansible-playbook group_vars/test.yml 
ERROR! Attempting to decrypt but no vault secrets found

要为playbook提供vault密码,可使用–vault-id选项。例如,要以交互方式提供vault密码,请使用下例中所示的–vault-id @prompt

[root@ansible ansible]# ansible-playbook --vault-id @prompt group_vars/test.yml 
Vault password (default):       //这里输入密码

PLAY [192.168.25.130] **************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.25.130]

TASK [create user] *****************************************************************
changed: [192.168.25.130]

PLAY RECAP *************************************************************************
192.168.25.130             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


此外,也可使用–vault-password-file选项指定以纯文本存储加密密码的文件。密码应当在该文件中存储为一行字符串。由于该文件包含敏感的纯文本密码,因此务必要通过文件权限和其他安全措施对其加以保护

[root@ansible ansible]# ansible-playbook --vault-password-file=passwd.yml group_vars/test.yml 

PLAY [192.168.25.130] **************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.25.130]

TASK [create user] *****************************************************************
ok: [192.168.25.130]

PLAY RECAP *************************************************************************
192.168.25.130             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


也可以使用ANSIBLE_VAULT_PASSWORD_FILE环境变量,指定密码文件的默认位置

[root@ansible ansible]# export ANSIBLE_VAULT_PASSWORD_FILE=/etc/ansible/passwd.yml 
[root@ansible ansible]# ansible-playbook group_vars/test.yml 

PLAY [192.168.25.130] **************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.25.130]

TASK [create user] *****************************************************************
ok: [192.168.25.130]

PLAY RECAP *************************************************************************
192.168.25.130             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


从Ansible2.4开始,可以通过ansible-playbook使用多个Ansible Vault密码。要使用多个密码,需要将多个–vault-id或–vault-password-file选项传递给ansible-playbook命令

ansible-playbook --vault-id one@prompt --vault-id two@prompt site.yml

注意:@prompt前面的vaultIDone和two可以是任何字符,甚至可以完全省略它们。不过,如果在使用ansible-vault命令加密文件时使用–vault-id id选项,则在运行ansible-playbook时,将最先尝试匹配ID的密码。如果不匹配,将会尝试用户提供的其他密码。没有ID的vaultID@prompt实际上是default@prompt的简写,这意味着提示输入vaultIDdefault的密码

2.2.1 变量文件管理的推荐做法

若要简化管理,务必要设置Ansible项目,使敏感变量和其他变量保存在相互独立的文件中。然后,包含敏感变量的文件可通过ansible-vault命令进行保护。

管理组变量和主机变量的首选方式是在playbook级别上创建目录。group_vars目录通常包含名称与它们所应用的主机组匹配的变量文件。host_vars目录通常包含名称与它们所应用的受管主机名称匹配的变量文件。

不过,除了使用group_vars和host_vars中的文件外,也可对每一主机组或受管主机使用目录。这些目录可包含多个变量文件,它们都由该主机组或受管主机使用。例如,在playbook.yml的以下项目目录中,webservers的主机组的成员将使用group_vars/webservers/vars文件中的变量,而172.16.103.129将使用host_vars/172.16.103.129/vars和host_vars/172.16.103.129/vault中的变量

├── ansible.cfg
├── group_vars
│   └── webservers
│       └── vars
├── host_vars
│   └── 172.16.103.129
│       ├── vars
│       └── vault
├── inventory
└── playbook.yml

在这种情况中,其好处在于用于172.16.103.129的大部分变量可以放在vars文件中,敏感变量则可单独放在vault文件中保密。然后使用ansible-vault加密vault文件,而将vars文件保留为纯文本。

在本例中,host_vars/172.16.103.129目录内使用的文件名没有什么特别之处。该目录可以包含更多文件,一些由Ansible Vault加密,另一些则不加密。

Playbook变量(与清单变量相对)也可通过Ansible Vault保护。敏感的playbook变量可以放在单独的文件中,此文件通过Ansible Vault加密,并能vars_files指令包含在该playbook中。这也是推荐做法,因为playbook变量的优先级高于清单变量。

如果需要在playbook中使用多个vault密码,请确保每个加密文件分配一个vaultID,并在运行playbook时输入具有该vaultID的匹配密码。这可确保在解密vault加密文件时先选择正确的密码,这比强制Ansible尝试用户提供的所有vault密码直至找到正确的密码要快。

3管理事实

3.1ansible事实描述

Ansible事实是Ansible在受管主机上自动检测到的变量。事实(fact)中包含有与主机相关的信息,可以像play中的常规变量、条件、循环或依赖于从受管主机收集的值的任何其他语句那样使用。

事实可能包括

  • 主机名称
  • 内核版本
  • 网络接口
  • IP地址
  • 操作系统版本
  • 各种环境变量
  • CPU数量
  • 提供的或可用的内存
  • 可用磁盘空间

借助事实,可以方便地检索受管主机的状态,并根据该状态确定要执行的操作
例如:

  • 可以根据含有受管主机当前内核版本的事实运行条件任务,以此来重启服务器
  • 可以根据通过事实报告的可用内存来自定义MySQL配置文件
  • 可以根据事实的值设置配置文件中使用的IPv4地址

每个play在执行第一个任务之前会先自动运行setup模块来收集事实

[root@ansible ansible]# ansible-playbook group_vars/test.yml 

PLAY [192.168.25.130] **************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.25.130]       //收集事实

TASK [create user] *****************************************************************
ok: [192.168.25.130]

PLAY RECAP *************************************************************************
192.168.25.130             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

也可以使用setup魔窟手动收集受管主机的全部事实

[root@ansible ansible]# ansible 192.168.25.130 -m setup
192.168.25.130 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.25.130",
            "192.168.122.1"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::871d:6b3a:94aa:aae4",
            "fe80::20a1:fdd5:36c5:6f01"
        ],
        "ansible_apparmor": {
            "status": "disabled"
        },

......
 "ansible_virtualization_role": "guest",
        "ansible_virtualization_type": "VMware",
        "discovered_interpreter_python": "/usr/libexec/platform-python",
        "gather_subset": [
            "all"
        ],
        "module_setup": true
    },
    "changed": false
}
[root@ansible ansible]# 

查看为受管主机收集的事实的一种方式是,也可以运行一个playbook收集事实使用debug模块显示ansible_facts变量值的简短playbook,运行该playbook时,事实将显示在作业输出中

注意: 定义变量时不要加上ansible

[root@ansible group_vars]# cat test.yml
---
- hosts: 192.168.25.130
  tasks:
    - name: facts
      debug: 
        var: ansible_facts['default_ipv4']['address']


[root@ansible ansible]# ansible-playbook group_vars/test.yml 

PLAY [192.168.25.130] **************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.25.130]

TASK [facts] ***********************************************************************
ok: [192.168.25.130] => {
    "ansible_facts['default_ipv4']['address']": "192.168.25.130"
}

PLAY RECAP *************************************************************************
192.168.25.130             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Playbook以JSON格式显示ansible_facts变量的内容,下表显示了可能从受管节点收集的并可在playbook中使用的一些事实

Ansible事实的示例

事实变量
短主机名ansible_facts[‘hostname’]
完全限定域名ansible_facts[‘fqdn’]
IPv4地址ansible_facts[‘default_ipv4’][‘address’]
所有网络接口的名称列表ansible_facts[‘interfaces’]
/dev/vda1磁盘分区的大小ansible_facts[‘devices’][‘vda’][‘partitions’][‘vda1’][‘size’]
DNS服务器列表ansible_facts[‘dns’][‘nameservers’]
当前运行的内核版本ansible_facts[‘kernel’]

在playbook中使用事实时,Ansible将事实的变量名动态替换为对应的值

[root@ansible group_vars]# cat test.yml
---
- hosts: 192.168.25.130
  tasks:
    - name: facts
      debug: 
        msg: > 
          The hosts named {{ ansible_facts['fqdn'] }} of
          ip is {{ ansible_facts['default_ipv4']['address'] }}


[root@ansible ansible]# ansible-playbook group_vars/test.yml 

PLAY [192.168.25.130] **************************************************************

TASK [Gathering Facts] *************************************************************
ok: [192.168.25.130]

TASK [facts] ***********************************************************************
ok: [192.168.25.130] => {
    "msg": "The hosts named lamp of ip is 192.168.25.130\n"
}

PLAY RECAP *************************************************************************
192.168.25.130             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

3.2 Ansible事实作为变量注入

在Ansible2.5之前,事实是作为前缀为字符串ansible_的单个变量注入,而不是作为ansible_facts变量的一部分注入。例如,ansible_facts[‘distribution’]事实会被称为ansible_distribution

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[‘devices’][‘vda’][‘partitions’][‘vda1’][‘size’]ansible_devices[‘vda’][‘partitions’][‘vda1’][‘size’]
ansible_facts[‘dns’][‘nameservers’]ansible_dns[‘nameservers’]
ansible_facts[‘kernel’]ansible_kernel

目前,Ansible同时识别新的事实命名系统(使用ansible_facts)和旧的2.5前“作为单独变量注入的事实”命名系统,将Ansible配置文件的[default]部分中inject_facts_as_vars参数设置为False,可关闭旧命名系统。默认设置目前为True。inject_facts_as_vars的默认值在Ansible的未来版本中可能会更改为False。

3.3 关闭事实收集

有时我们不想为play收集事实,可能的原因

  • 不准备使用任何事实
  • 希望加快play速度
  • 希望减小play在受管主机上造成的负载
  • 受管主机因为某种原因无法运行setup模块
  • 需要安装一些必备软件后再收集事实

种种原因导致我们可能想要永久或暂时关闭事实收集的功能,要为play禁用事实收集功能,可将gather_facts关键字设置为no

[root@ansible group_vars]# cat test.yml
---
- hosts: 192.168.25.130
  gather_facts: no
  tasks:
    - name: create user
      user: 
        name: tom
        state: present


[root@ansible ansible]# ansible-playbook group_vars/test.yml 

PLAY [192.168.25.130] **************************************************************

TASK [create user] *****************************************************************
ok: [192.168.25.130]

PLAY RECAP *************************************************************************
192.168.25.130             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


即使play设置了gather_facts: no,也可以随时通过运行使用setup模块的任务来手动收集事实

[root@ansible group_vars]# cat test.yml
---
- hosts: 192.168.25.130
  gather_facts: no
  tasks:
    - name: facts
      setup: 
    - name:  
      debug: 
        var: ansible_facts


[root@ansible ansible]# ansible-playbook group_vars/test.yml 

PLAY [192.168.25.130] **************************************************************

TASK [facts] ***********************************************************************
ok: [192.168.25.130]

TASK [debug] ***********************************************************************
ok: [192.168.25.130] => {
    "ansible_facts": {
        "all_ipv4_addresses": [
            "192.168.25.130",
            "192.168.122.1"
        ],
        "all_ipv6_addresses": [
            "fe80::871d:6b3a:94aa:aae4",
            "fe80::20a1:fdd5:36c5:6f01"
        ],
        
......

3.4 创建自定义事实

除了使用系统捕获的事实外,我们还可以自定义事实,并将其本地存储在每个受管主机上。这些事实整合到setup模块在受管主机上运行时收集的标准事实列表中。它们让受管主机能够向Ansible提供任意变量,以用于调整play的行为。

自定义事实可以在静态文件中定义,格式可为INI文件或采用JSON。它们也可以是生成JSON输出的可执行脚本,如同动态清单脚本一样。

有了自定义事实,我们可以为受管主机定义特定的值,供play用于填充配置文件或有条件地运行任务。动态自定义事实允许在play运行时以编程方式确定这些事实的值,甚至还可以确定提供哪些事实。

默认情况下,setup模块从各受管主机的/etc/ansible/facts.d目录下的文件和脚本中加载自定义事实。各个文件或脚本的名称必须以.fact结尾才能被使用。动态自定义事实脚本必须输出JSON格式的事实,而且必须是可执行文件。

以下是采用INI格式编写的静态自定义事实文件。INI格式的自定义事实文件包含由一个部分定义的顶层值,后跟用于待定义的事实的键值对

[root@lamp facts.d]# cat test.fact 
[packages]
web_package = httpd
db_package = mariadb-server

[users]
user1 = joe
user2 = jane
[root@lamp facts.d]# 

[root@ansible ansible]# ansible 192.168.25.130 -m setup|less


192.168.25.130 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.25.130",
            "192.168.122.1"
        ],
        
...... 

        "ansible_local": {
            "test": {
                "packages": {
                    "db_package": "mariadb-server",
                    "web_package": "httpd"
                },
                "users": {
                    "user1": "joe",
                    "user2": "jane"
                }
            }
        },
        "ansible_lsb": {},
        "ansible_lvm": {
            "lvs": {
                "root": {
:

同样的事实可能以JSON格式提供。以下JSON事实等同于以上示例中INI格式指定的事实。JSON数据可以存储在静态文本文件中,或者通过可执行脚本输出到标准输出

[root@lamp facts.d]# cat test.fact 
ckages": {
    "web_package": "httpd",
    "db_package": "mariadb-server"
  },
  "users": {
    "user1": "joe",
    "user2": "jane"
  }
}


自定义事实文件不能采用playbook那样的YAML格式,自定义事实由setup模块存储在ansible_facts.ansible_local变量中。事实按照定义它们的文件的名称来整理。

自定义事实的使用方式与playbook中的默认事实相同

[root@ansible ansible]# cat playbook.yaml
---
- hosts: all
  tasks:
    - name: 输出某个用户
      debug:
        msg: 该用户是:{{ ansible_facts['ansible_local']['example']['users']['user_one'] }}

[root@ansible ansible]# ansible-playbook playbook.yaml
 
PLAY [all] ****************************************************************************************************************************************************************
 
TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [client.example.com]
 
TASK [输出某个用户] *************************************************************************************************************************************************************
ok: [client.example.com] => {
    "msg": "该用户是:zhangsan"
}
 
PLAY RECAP ****************************************************************************************************************************************************************
client.example.com         : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

[root@ansible ansible]# ansible 192.168.25.130 -m setup |less
..............
"ansible_local": {
            "example": {
                "servers": {
                    "service_one": "httpd",
                    "service_two": "vsftpd"
                },
                "users": {
                    "user_one": "zhangsan",
                    "user_two": "lisi"
                }
            }
        },

3.5魔法变量

一些变量并非事实或通过setup模块配置,但也由Ansible自动设置。这些魔法变量也可用于获取与特定受管主机相关的信息

常用的魔法变量

魔法变量说明
hostvars包含受管主机的变量,可以用于获取另一台受管主机的变量的值。如果还没有为受管主机收集事实,则它不会包含该主机的事实
group_names列出当前受管主机所属的所有组
groups列出清单中的所有组和主机
inventory_hostname包含清单中配置的当前受管主机的主机名称。因为各种原因有可能与事实报告的主机名称不同
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值