2.4:Playbook 中变量的多种使用方式
关于如何在Playbook中使用变量的官方文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html
在Playbook中调用变量的方式有:
- 调用变量的值:
{{ VARIABLE_NAME }}
- 有时需要加双引号,避免被解析为内联字典:
"{{ VARIABLE_NAME }}"
- 当调用变量的字符串中有
:
时,避免被解析为key: value
,也要为整个字符串加上引号:"STRING: {{ VARIABLE_NAME }}"
- 当调用变量作为
key: value
中的value
时,也需要加上引号:key: "{{ VARIABLE_NAME }}"
- 调用变量名,则直接使用变量名,什么也不加:
VARIABLE_NAME
比如在Playbook中的某些模块中使用var参数来指定变量名:debug: var=VARIABLE_NAME
Playbook中调用的变量有以下来源:
-
setup模块获取的fact信息,其中就包含了大量的变量,可以直接调用。
-
为Playbook传递的自定义变量,这其中包括了:
- 通过命令行
ansible-playbook -e VARIABLE_NAME=VALUE PLAYBOOK.yml
定义的变量; - Playbook中通过
var_files
定义的变量文件中的变量; - Playbook中通过
vars
定义的变量; - Ansible项目中在
host_vars/HOSTNAME
文件中定义的主机变量(文件名是HOSTNAME
,与主机清单中定义的主机名一致); - 主机清单文件中定义的主机变量;
- Ansible项目中在
group_vars/GROUPNAME
文件中定义的主机组变量(文件名是GROUPNAME
,与主机清单中定义的主机组名一致); - Ansible项目中在
group_vars/all
文件中定义的公共变量(该文件中定义的变量对主机清单中的所有主机生效); - 主机清单文件中定义的主机组变量。
优先级从高到低。
- 通过命令行
-
为Playbook的Role传递的自定义变量:
roles/ROLE_NAME/vars/main.yml
文件中定义的变量;roles/ROLE_NAME/defaults/main.yml
文件中定义的变量。
优先级从高到低。
2.4.1:使用 facts 信息中的变量
Playbook在执行时默认就会收集目标主机的facts信息并存为变量,可以指定变量来直接调用。当在Playbook中使用facts变量时,就不能将gather_facts
设为no。
2.4.1.1:ansible_nodename
该变量保存的是目标主机的主机名。
示例:
- hosts: websrvs
tasks:
- name: ansible_nodename
debug:
msg: "目标主机名: {{ ansible_nodename }}"
执行结果:
2.4.1.2:ansible_IFNAME.ipv4.address
该变量保存的是目标主机特定网络接口的ipv4地址。
IFNAME
为目标主机的网络接口名称,如eth0
。
也可以由ansible_facts.IFNAME.ipv4.address
取得。
示例:
- hosts: websrvs
tasks:
- name: ansible_eth0.ipv4.address
debug:
msg: "eth0的ipv4地址: {{ ansible_eth0.ipv4.address }}"
执行结果:
2.4.1.3:ansible_facts.IFNAME.ipv4.address
该变量保存的同样是目标主机特定网络接口的ipv4地址。
示例:
- hosts: websrvs
tasks:
- name: ansible_facts.eth0.ipv4.address
debug:
msg: "eth0的ipv4地址: {{ ansible_facts.eth0.ipv4.address }}"
执行结果:
2.4.1.4:ansible_default_ipv4.address
该变量保存的是目标主机默认的ipv4地址。
示例:
- hosts: websrvs
tasks:
- name: ansible_default_ipv4.address
debug:
msg: "默认的ipv4地址: {{ ansible_default_ipv4.address }}"
执行结果:
2.4.1.5:使用 split 对变量值进行切分
通过指定分隔符和切分后的对象序号(序号从0开始),来取得变量值中需要的部分。
示例1:
- hosts: websrvs
tasks:
- name: split
debug:
msg: "eth0的ipv4地址中的最后一个数字: {{ ansible_facts.eth0.ipv4.address.split('.')[-1] }}"
执行结果1:
2.4.2:使用自定义变量
2.4.2.1:在 ansible-playbook 命令行中定义变量
使用ansible-playbook命令执行Playbook时,可以通过-e VARIABLE_NAME=VALUE
来定义变量,或通过-e '@VARIABLE_FILE'
来指定变量文件。
2.4.2.1.1:定义变量
Playbook 示例:
[root@ansible ~]# vim remove.yml
---
- hosts: websrvs
tasks:
- name: remove {{ rmfile_name }}
file: path={{ rmfile_name }} state=absent
...
在命令行中定义变量并执行Playbook:
[root@ansible ~]# ansible-playbook -e rmfile_name=/etc/fstab -C remove.yml
2.4.2.1.2:指定变量文件
可以将多个变量定义在一个变量文件中:
[root@ansible ~]# vim vars.yml
src_file: files/ports.conf
dest_file: /etc/apache2/ports.conf
Playbook 示例:
[root@ansible ~]# vim copy.yml
---
- hosts: websrvs
tasks:
- name: copy {{ src_file }} to {{ dest_file }} on {{ ansible_nodename }}
copy:
src: "{{ src_file }}"
dest: "{{ dest_file }}"
...
在命令行中指定变量文件并执行Playbook:
[root@ansible ~]# ansible-playbook -e '@vars.yml' -C copy.yml
2.4.2.2:在 Playbook 中使用 vars_files 指定变量文件
上边定义的vars.yml
变量文件可以在Playbook中使用vars_files
这个Keyword来指定。
Playbook 示例:
[root@ansible ~]# vim copy.yml
---
- hosts: websrvs
vars_files:
- vars.yml
tasks:
- name: copy {{ src_file }} to {{ dest_file }} on {{ ansible_nodename }}
copy:
src: "{{ src_file }}"
dest: "{{ dest_file }}"
...
执行结果:
2.4.2.3:在 Playbook 中使用 vars 定义变量
上述变量文件中的变量可以在Playbook中使用vars
来直接定义:
[root@ansible ~]# vim copy.yml
---
- hosts: websrvs
vars:
src_file: files/ports.conf
dest_file: /etc/apache2/ports.conf
tasks:
- name: copy {{ src_file }} to {{ dest_file }} on {{ ansible_nodename }}
copy:
src: "{{ src_file }}"
dest: "{{ dest_file }}"
...
执行结果:
2.4.2.4:在 Ansible 项目中通过 host_vars/HOSTNAME 文件定义主机变量
在 Ansible 项目中通过 host_vars/HOSTNAME
文件定义主机变量,可以实现为不同主机定义不同的变量,或为不同主机的同一变量传递不同的变量值。
创建一个简单的 Ansible 项目,分别为一台Ubuntu主机安装apahce2,为一台CentOS主机安装httpd,通过为不同主机的pkg_name变量传递不同值来实现。
2.4.2.4.1:编写 Playbook
[root@ansible ~]# mkdir ansible
[root@ansible ~]# vim ansible/install_web.yml
---
- hosts: 192.168.1.111
tasks:
- name: "Ubuntu 安装 {{ pkg_name }}"
apt:
name: "{{ pkg_name }}"
state: present
when: ansible_os_family == "Debian"
- hosts: 192.168.1.203
tasks:
- name: "CentOS 安装 {{ pkg_name }}"
yum:
name: "{{ pkg_name }}"
state: present
when: ansible_os_family == "RedHat"
...
2.4.2.4.2:定义主机清单文件
[root@ansible ~]# vim ansible/hosts
[websrvs]
192.168.1.111
192.168.1.203
2.4.2.4.3:准备主配置文件
[root@ansible ~]# cp /etc/ansible/ansible.cfg ansible/
[root@ansible ~]# vim ansible/ansible.cfg
inventory = ./hosts
2.4.2.4.4:定义主机变量文件
[root@ansible ~]# mkdir ansible/host_vars
[root@ansible ~]# vim ansible/host_vars/192.168.1.111
pkg_name: apache2
[root@ansible ~]# vim ansible/host_vars/192.168.1.203
pkg_name: httpd
2.4.2.4.5:查看 Ansible 项目结构
[root@ansible ~]# tree ansible/
ansible/
├── ansible.cfg
├── hosts
├── host_vars
│ ├── 192.168.1.111
│ └── 192.168.1.203
└── install_web.yml
2.4.2.4.6:为目标主机推送 ssh_key
[root@ansible ~]# vim key_push.sh
#!/bin/bash
# Description: 向被管理主机批量推送管理端ssh公钥
# Variables set
export SSHPASS=123456
Hosts="
192.168.1.111
192.168.1.203"
for i in ${Hosts}; do
sshpass -e ssh-copy-id -o StrictHostKeyChecking=no ${i}
done
[root@ansible ~]# bash key_push.sh
2.4.2.4.7:执行 Playbook
到Ansible项目目录中执行Playbook:
[root@ansible ~]# cd ansible
[root@ansible ansible]# ansible-playbook install_web.yml
执行结果:
验证:
root@node111:~# dpkg-query -l apache2
[root@node203 ~]# rpm -q httpd
httpd-2.4.6-97.el7.centos.x86_64
2.4.2.5:在主机清单文件中定义主机变量
可以在主机清单文件的主机后面为单个主机定义变量:
[GROUP_NAME]
HOST1 VARIABLE1=VALUE1 VARIABLE2=VALUE2
HOST2 VARIABLE1=VALUE1 VARIABLE2=VALUE2
2.4.2.5.1:主机清单示例
[root@ansible ~]# vim ansible/hosts
[websrvs]
192.168.1.111 pkg_name=apache2
192.168.1.203 pkg_name=httpd
2.4.2.5.2:Playbook 示例
Playbook和上一个示例相同:
[root@ansible ~]# vim ansible/install_web.yml
---
- hosts: 192.168.1.111
tasks:
- name: "Ubuntu 安装 {{ pkg_name }}"
apt:
name: "{{ pkg_name }}"
state: present
when: ansible_os_family == "Debian"
- hosts: 192.168.1.203
tasks:
- name: "CentOS 安装 {{ pkg_name }}"
yum:
name: "{{ pkg_name }}"
state: present
when: ansible_os_family == "RedHat"
...
2.4.2.5.3:执行 Playbook
执行Playbook前,先进行一些恢复操作。
- 卸载两台目标主机上的apache2和httpd:
root@node111:~# apt remove apache2 [root@node203 ~]# yum remove httpd
- 删除
host_vars
主机变量目录(因为host_vars
中定义的主机变量比主机清单中定义的主机变量优先级高,会优先调用):[root@ansible ~]# rm -rf ansible/host_vars/
执行Playbook:
[root@ansible ~]# cd ansible
[root@ansible ansible]# ansible-playbook install_web.yml
执行结果:
2.4.2.6:在 Ansible 项目中通过 group_vars/GROUPNAME 文件定义主机组变量
在 Ansible 项目中通过 group_vars/GROUPNAME
文件定义主机组变量,可以实现为不同主机组定义不同的变量,或为不同主机组的同一变量传递不同的变量值。
同样创建一个简单的 Ansible 项目,分别为ubuntu主机组安装apahce2,为centos主机组主机安装httpd,通过为不同主机组的pkg_name变量传递不同的变量值来实现。
2.4.2.6.1:编写 Playbook
[root@ansible ~]# vim ansible/install_web.yml
---
- hosts: ubuntu
tasks:
- name: "Ubuntu 安装 {{ pkg_name }}"
apt:
name: "{{ pkg_name }}"
state: present
when: ansible_os_family == "Debian"
- hosts: centos
tasks:
- name: "CentOS 安装 {{ pkg_name }}"
yum:
name: "{{ pkg_name }}"
state: present
when: ansible_os_family == "RedHat"
...
2.4.2.6.2::定义主机清单文件
[root@ansible ~]# vim ansible/hosts
[ubuntu]
192.168.1.111
[centos]
192.168.1.203
2.4.2.6.3:准备主配置文件
[root@ansible ~]# cp /etc/ansible/ansible.cfg ansible/
[root@ansible ~]# vim ansible/ansible.cfg
inventory = ./hosts
2.4.2.6.4:定义主机组变量文件
[root@ansible ~]# mkdir ansible/group_vars
[root@ansible ~]# vim ansible/group_vars/ubuntu
pkg_name: apache2
[root@ansible ~]# vim ansible/group_vars/centos
pkg_name: httpd
2.4.2.6.5:查看 Ansible 项目结构
[root@ansible ~]# tree ansible/
ansible/
├── ansible.cfg
├── group_vars
│ ├── centos
│ └── ubuntu
├── hosts
└── install_web.yml
2.4.2.6.6:为目标主机推送 ssh_key
[root@ansible ~]# vim key_push.sh
#!/bin/bash
# Description: 向被管理主机批量推送管理端ssh公钥
# Variables set
export SSHPASS=123456
Hosts="
192.168.1.111
192.168.1.203"
for i in ${Hosts}; do
sshpass -e ssh-copy-id -o StrictHostKeyChecking=no ${i}
done
[root@ansible ~]# bash key_push.sh
2.4.2.6.7:执行 Playbook
执行前先卸载两个主机上之前安装了的apace2和httpd:
root@node111:~# apt remove apache2 -y [root@node203 ~]# yum remove httpd -y
到Ansible项目目录中执行Playbook:
[root@ansible ~]# cd ansible
[root@ansible ansible]# ansible-playbook install_web.yml
执行结果:
验证:
root@node111:~# dpkg-query -l apache2
[root@node203 ~]# rpm -q httpd
httpd-2.4.6-97.el7.centos.x86_64
2.4.2.7:在 Ansible 项目中通过 group_vars/all 文件定义公共变量
在一个Ansible项目中,还可以在group_vars/all
文件中为主机清单的所有主机定义公共变量,改文件中的变量对整个主机清单生效。
在上述Ansible项目中再编写一个Playbook,用于删除各主机上的apache2或httpd(使用公共变量pkg_state
,为所有主机传递absent
变量值)。
2.4.2.7.1:编写 Playbook
[root@ansible ~]# vim ansible/remove_web.yml
---
- hosts: ubuntu
tasks:
- name: "Ubuntu 卸载 {{ pkg_name }}"
apt:
name: "{{ pkg_name }}"
state: "{{ pkg_state }}"
when: ansible_os_family == "Debian"
- hosts: centos
tasks:
- name: "CentOS 卸载 {{ pkg_name }}"
yum:
name: "{{ pkg_name }}"
state: "{{ pkg_state }}"
when: ansible_os_family == "RedHat"
...
2.4.2.7.2:定义公共变量文件
[root@ansible ~]# vim ansible/group_vars/all
pkg_state: absent
2.4.2.7.3:查看 Ansible 项目结构
[root@ansible ~]# tree ansible/
ansible/
├── ansible.cfg
├── group_vars
│ ├── all
│ ├── centos
│ └── ubuntu
├── hosts
├── install_web.yml
└── remove_web.yml
2.4.2.7.4:执行 Playbook
[root@ansible ~]# cd ansible
[root@ansible ansible]# ansible-playbook remove_web.yml
执行结果:
验证:
root@node111:~# dpkg-query -l apache2
[root@node203 ~]# rpm -q httpd
package httpd is not installed