Ansible变量-概述
一、变量概述
变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态值,比如 nginx-1.6.3 这个软件包的版本,在其它地方或许会反复使用,那么如果讲此值设置为变量,然后再在其他的playbook中调用,会方便许多。如此一来还方便维护,减少维护的成本。
二、定义变量的方式
- 通过命令行:进行变量定义。
- 在 play 文件中:进行变量定义。
- 通过 Inventory 主机信息文件:进行变量定义。
三、变量的优先级
当变量冲突时,读取优先级顺序为:命令行 > playbook 文件 > Inventory 文件。
例如:
- 命令行中:age = 11
- play 文件中:age = 12
- Inventory 中:age=13
最终的 age 结果为 11。
一、在 Play 里定义变量
案例 1:定义单个变量
在 Ansible 中,可以在 Play 里定义单个变量。以下是示例代码:
[root@ansible ansible]# cat var.yml
- hosts: backup
vars:
pk: wget
tasks:
- name: Install package
yum:
name: "{{ pk }}"
state: present
在上述代码中,定义了一个名为 pk
的变量,其值为 wget
。在 tasks
部分,通过 yum
模块安装名为 {{ pk }}
的软件包,这里的 {{ pk }}
就是引用了前面定义的变量。
案例 2:定义多个变量(使用列表方式)
可以使用列表的方式定义多个变量,示例如下:
[root@ansible ansible]# cat var.yml
- hosts: backup
vars:
pk:
- wget
- tree
- lrzsz
tasks:
- name: Install package
yum:
name: "{{ pk }}"
state: present
这里定义的 pk
变量是一个列表,包含了 wget
、tree
和 lrzsz
三个值。在 yum
模块中,name: "{{ pk }}"
会尝试安装列表中的所有软件包。
案例 3:定义路径的变量
变量单独调用
变量单独调用时必须加双引号,如下示例:
[root@ansible ansible]# cat var.yml
- hosts: backup
vars:
- pk1: 10.0.0.41
- pk2: backup
tasks:
- name: create file
file:
path: "{{ pk1 }}"
state: touch
变量带路径的情况
如果变量带路径,不需要使用双引号。错误示例:
如果是变量开头,就要加双引号
[root@ansible ansible]# cat var.yml
- hosts: backup
vars:
- pk1: 10.0.0.41
- pk2: backup
tasks:
- name: create file
file:
path: /root/"{{ pk1 }}"
state: touch
正确写法:
[root@ansible ansible]# cat var.yml
- hosts: backup
vars:
- pk1: 10.0.0.41
- pk2: backup
tasks:
- name: create file
file:
path: /root/{{ pk1 }}
state: touch
案例 4:创建名称为 backup_10.0.0.41 的目录
通过组合不同变量来创建具有特定名称的目录,示例如下:
[root@ansible ansible]# cat var.yml
- hosts: backup
vars:
- pk1: 10.0.0.41
- pk2: backup
tasks:
- name: create file
file:
path: /root/{{ pk2 }}_{{ pk1 }}
state: directory
上述代码通过组合 pk2
和 pk1
变量的值,在 /root
目录下创建了名为 backup_10.0.0.41
的目录。
二、在 vars_file 文件中定义变量
systemctl mask tmp.mount
:此命令用于永久卸载tmp
挂载。
1. 创建存放变量的文件
使用以下命令创建并查看v.yml
文件,在其中定义变量:
[root@ansible ansible]# cat v.yml
pk1: lrzsz
pk2: tree
此文件定义了两个变量pk1
和pk2
,分别赋值为lrzsz
和tree
。
2. 在 play 中调用变量
创建var.yml
文件来调用v.yml
中定义的变量:
vars_files: v.yml
[root@ansible ansible]# cat var.yml
- hosts: backup
vars_files: v.yml
tasks:
- name: create file
file:
path: /root/{{ pk2 }}_{{ pk1 }}
state: directory
上述 playbook 中:
hosts: backup
指定目标主机组为backup
。vars_files: v.yml
加载v.yml
文件中的变量。tasks
部分定义了一个任务,name
为create file
,使用file
模块根据变量pk1
和pk2
创建一个目录/root/{{ pk2 }}_{{ pk1 }}
。
3. 案例:使用列表调用多个变量
变量文件依旧使用v.yml
:
[root@ansible ansible]# cat v.yml
pk1: lrzsz
pk2: tree
h1: abaaba
h2: sbsbssbb
h3: heiehiehei
h4:
- wget
- tree
- nginx
- mariadb
var.yml
文件内容如下:
[root@ansible ansible]# cat var.yml
- hosts: backup
vars_files: v.yml
tasks:
- name: yum lrzsz wget
yum:
name:
- "{{ pk1 }}"
- "{{ pk2 }}"
state: present
此 playbook 通过yum
模块,根据变量pk1
和pk2
安装对应的软件包。
三、使用 ansible 的内置变量
Ansible 的内置变量可以通过setup
模块来查看。以下是一个使用内置变量的var.yml
示例:
#例如
ansible backup -m setup -a 'filter=ansible_hostname'
from cryptography.exceptions import InvalidSignature
backup | SUCCESS => {
"ansible_facts": {
"ansible_hostname": "backup01"
},
"changed": false
}
###常用fact变量
ansible_hostanme ##主机名
ansible_memtotal_mb ##内存大小(总计) 单位mb
ansible_processor_vcpus ##cpu核心总数数量
ansible_default_ipv4.address ##默认的网卡ip eth0
ansible_distribution ##默认发行版本名字 Centos Ubuntu Debian.
ansible_distribution_version ##系统的版本
ansible_date_time.date ##年-月-日
ansible_all_ipv4_addresses: ##仅显示ipv4的信息。
ansible_devices: ##仅显示磁盘设备信息。
ansible_distribution: ##显示是什么系统,例:centos,suse等。
ansible_distribution_major_version ## 显示是系统主版本。
ansible_distribution_version: ##仅显示系统版本。
ansible_machine: ##显示系统类型,例:32位,还是64位。
ansible_eth0: ##仅显示eth0的信息。
ansible_hostname: ##仅显示主机名。
ansible_kernel: ##仅显示内核版本。
ansible_lvm: ##显示lvm相关信息。
ansible_memtotal_mb: ##显示系统总内存。
ansible_memfree_mb: ##显示可用系统内存。
ansible_memory_mb: ##详细显示内存情况。
ansible_swaptotal_mb: ##显示总的swap内存。
ansible_swapfree_mb: ##显示swap内存的可用内存。
ansible_mounts: ##显示系统磁盘挂载情况。
ansible_processor: ##显示cpu个数(具体显示每个cpu的型号)。
ansible_processor_vcpus ##显示cpu个数(只显示总的个数)。
[root@ansible ansible]# cat var.yml
- hosts: backup
tasks:
- name: Create file
file:
path: /root/{{ ansible_hostname }}_{{ ansible_default_ipv4.address }}
state: directory
在这个 playbook 中,使用ansible_hostname
(主机名)和ansible_default_ipv4.address
(默认 IPv4 地址)这两个内置变量来创建一个目录。
四、在主机清单中定义变量
这种方式不推荐使用。在/etc/ansible/hosts
文件中定义变量:
相当于子组,lnmp里的主机可以调用这些变量
[root@ansible ansible]# cat /etc/ansible/hosts
nfs ansible_ssh_host=10.0.0.31
[lnmp]
backup ansible_ssh_host=10.0.0.41
web01 ansible_ssh_host=10.0.0.7
web02 ansible_ssh_host=10.0.0.8
db01 ansible_ssh_host=10.0.0.51
[lnmp:vars]
pk1=wget
pk2=lrzsz
在var.yml
文件中调用这些变量:
[root@ansible ansible]# cat var.yml
- hosts: backup
tasks:
- name: Create file
file:
path: /root/{{ pk1 }}_{{ pk2 }}
state: directory
通过在主机清单的[组名:vars]
部分定义变量,可在对应的组主机的 playbook 中使用这些变量。
五、官方推荐方式变量
1. 定义主机的变量
在当前目录创建host_vars
目录,按照主机清单来定义变量文件。例如,主机清单中有backup ansible_ssh_host=10.0.0.41
,则在host_vars
下创建一个backup
文件,在其中定义变量:
- 组里能调用变量,是group_vars目录下面创建
- 单个主机调用变量,是host_vars目录下面创建
- 就记住group_vars就行,改目录和vars.yml在一级
- group_vars/all/all.yml所有都能用
[root@Ansible ~/ansible]# ll
drwxr-xr-x 2 root root 6 Jan 1 21:45 group_vars
drwxr-xr-x 2 root root 6 Jan 1 21:45 host_vars
[root@Ansible ~/ansible]# cat group_vars/lnmp/lnmp.yml
dir: sd123
[root@ansible oldboy]# cat host_vars/backup
pk1: lrzsz
pk2: wget
在vars.yml
文件中使用这些变量:
[root@ansible oldboy]# cat vars.yml
- hosts: backup
tasks:
- name: Install lrzsz wget
yum:
name:
- "{{ pk1 }}"
- "{{ pk2 }}"
state: present
[root@Ansible ~/ansible]# cat var.yml
- hosts: web01
tasks:
- name: create dir
file:
path: /root/{{ dir }}
state: touch
2. 定义组的变量
在group_vars
目录下按照组名定义变量文件。例如,主机清单如下:
[root@ansible oldboy]# cat /etc/ansible/hosts
nfs ansible_ssh_host=10.0.0.31
[lnmp]
backup ansible_ssh_host=10.0.0.41
web01 ansible_ssh_host=10.0.0.7
web02 ansible_ssh_host=10.0.0.8
db01 ansible_ssh_host=10.0.0.51
在group_vars/lnmp
文件中定义变量:
[root@ansible oldboy]# cat group_vars/lnmp
name: oldboy
age: 10
在vars.yml
文件中使用这些变量:
[root@ansible oldboy]# cat vars.yml
- hosts: web01
tasks:
- name: touch file
file:
path: /root/{{ name }}_{{ age }}
state: touch
3. 对所有的组定义变量
在group_vars/all
文件中定义变量:
[root@ansible oldboy]# cat group_vars/all
name: old
age: 11
这个文件中定义的变量可以在所有组的主机中使用。
Ansible 变量注册
一、Ansible 执行命令与结果返回问题
- Ansible 执行命令有时不直接出结果。它的模块运行后会有返回值,像脚本执行后给的反馈,能让我们知道操作是否成功。但默认这些返回值不显示,把它们存到变量里,通过调用变量名获取,这就是变量注册 。
二、变量注册返回命令详细信息
示例 1:列出 /root
目录详细信息
- 创建 playbook 文件
re.yml
[root@ansible oldboy]# cat re.yml
- hosts: web01
tasks:
- name: list /root
command: ls -l
- 使用变量注册获取
ls -l
详细信息
创建 playbook 文件li.yml
[root@ansible oldboy]# cat li.yml
- hosts: web01
tasks:
- name: list root
command: ls -l
register: ng_re
- name: print ng_re env
debug:
msg: "{{ ng_re }}"
上述代码中,通过 register: ng_re
将 ls -l
命令的执行结果注册到变量 ng_re
中,然后使用 debug
模块输出该变量信息。
三、变量注册返回 nginx 检查结果
示例 2:检查 Nginx 配置并返回结果
- 创建 playbook 文件
re.yml
[root@ansible oldboy]# cat re.yml
- hosts: web01
tasks:
- name: Check Nginx Config
command: nginx -t
- 使用变量注册获取 nginx 检查结果
同样使用re.yml
文件
[root@ansible oldboy]# cat re.yml
- hosts: web01
tasks:
- name: Check Nginx Config
command: nginx -t
register: ng_re
- name: print ng_re env
debug:
msg: "{{ ng_re }}"
这里将 nginx -t
命令的执行结果注册到变量 ng_re
中,并通过 debug
模块输出。
四、获取子集的值
示例 3:获取 nginx 检查结果的特定子集
不带子集正常输出结果:
[root@Ansible ~/ansible]# ansible-playbook var.yml
TASK [nginx -t] ********************************************************************************************************************************************************************
changed: [web01]
TASK [preint ls_l env] *************************************************************************************************************************************************************
ok: [web01] => {
"msg": {
"changed": true,
"cmd": [
"nginx",
"-t"
],
"delta": "0:00:00.006205",
"end": "2025-01-02 09:19:42.364234",
"failed": false,
"msg": "",
"rc": 0,
"start": "2025-01-02 09:19:42.358029",
"stderr": "nginx: the configuration file /etc/nginx/nginx.conf syntax is ok\nnginx: configuration file /etc/nginx/nginx.conf test is successful",
"stderr_lines": [
"nginx: the configuration file /etc/nginx/nginx.conf syntax is ok",
"nginx: configuration file /etc/nginx/nginx.conf test is successful"
],
"stdout": "",
"stdout_lines": []
}
}
PLAY RECAP *************************************************************************************************************************************************************************
web01 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@Ansible ~/ansible]#
带上子集 .stderr_lines 的结果:
[root@ansible oldboy]# cat re.yml
- hosts: web01
tasks:
- name: Check Nginx Config
command: nginx -t
register: ng_re
- name: print ng_re env
debug:
msg: "{{ ng_re.stderr_lines }}"
此例中,通过 ng_re.stderr_lines
获取 ng_re
变量中的 stderr_lines
子集信息并输出。
TASK [preint ls_l env] *************************************************************************************************************************************************************
ok: [web01] => {
"msg": [
"nginx: the configuration file /etc/nginx/nginx.conf syntax is ok",
"nginx: configuration file /etc/nginx/nginx.conf test is successful"
]
}
五、查看内置变量
示例 4:查看 Ansible 内置变量
[root@ansible oldboy]# cat re.yml
- hosts: web01
tasks:
- name: Check Nginx Config
command: nginx -t
register: ng_re
- name: print ansible_kernel env
debug:
msg: "{{ ansible_kernel }}"
上述代码展示了如何查看 Ansible 内置变量 ansible_kernel
,输出系统内核信息。
六、官方推荐写法
示例 5:获取变量特定属性的官方推荐写法
[root@ansible oldboy]# cat re.yml
- hosts: web01
tasks:
- name: Check Nginx Config
command: nginx -t
register: ng_re
- name: print ng_re env
debug:
msg: "{{ ng_re['rc'] }}" 等同于 "{{ ng_re.rc }}"
这里展示了获取变量 ng_re
的 rc
属性的两种写法,官方推荐的使用方括号 []
的写法与使用点号 .
的写法是等效的。
Ansible 中 when 判断
when判断案例
案例 1:在特定主机(web01)上安装 wget
- 需求:对
lnmp
组操作,仅在web01
服务器上安装wget
命令。 - playbook 内容:
[root@ansible oldboy]# cat w.yml
- hosts: lnmp
tasks:
- name: Install wget
yum:
name: wget
state: absent
when: ansible_hostname == "web01"
使用 == 精确匹配
案例 2:在特定 IP 地址的主机上安装 wget
- 需求:只在 IP 地址是
10.0.0.8
的服务器上安装wget
命令。 - playbook 内容:
[root@ansible oldboy]# cat w.yml
- hosts: lnmp
tasks:
- name: Install wget
yum:
name: wget
state: present
when: ansible_default_ipv4.address == "10.0.0.8"
案例 3:在满足 IP 和主机名条件的主机上安装 wget
- 需求:在 IP 地址是
10.0.0.7
且主机名是web01
的服务器上安装wget
。 - playbook 内容:
[root@ansible oldboy]# cat w.yml
- hosts: lnmp
tasks:
- name: Install wget
yum:
name: wget
state: present
when:
- ansible_default_ipv4.address == "10.0.0.7"
- ansible_hostname == "web01"
案例 4:在满足 IP 或主机名条件的主机上安装 wget
- 需求:在 IP 地址是
10.0.0.7
或者主机名称是web02
的服务器上安装wget
。 - playbook 内容:
[root@ansible oldboy]# cat w.yml
- hosts: lnmp
tasks:
- name: Install wget
yum:
name: wget
state: present
when: ( ansible_default_ipv4.address == "10.0.0.7" ) or ( ansible_hostname == "web02" )
其他判断字符 search 的使用
- 需求:对
lnmp
组内主机,当主机名包含web
时安装wget
。 when: ansible_hostname is search “web”搜索 - playbook 内容:
[root@ansible oldboy]# cat w.yml
- hosts: lnmp
tasks:
- name: Install wget
yum:
name: wget
state: present
when: ansible_hostname is search "web"
综合案例:安装、配置、检测并根据结果重启 Nginx
需求
- 安装
nginx
。 - 配置
nginx
。 - 检测
nginx
配置文件,通过变量注册接收结果。 - 重启
nginx
,通过when
判断,若nginx
配置文件正确则重启,错误不重启。
playbook 内容
[root@ansible ansible]# cat nginx.yml
- hosts: web02
tasks:
- name: Nginx Repo
yum_repository:
name: nginx
description: Nginx YUM repo
baseurl: http://nginx.org/packages/centos/7/$basearch/
gpgcheck: no
enabled: yes
- name: create group www
group:
name: www
gid: 666
- name: Create www user
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: Install Nginx Server
yum:
name: nginx
state: present
- name: Configure Nginx Server
copy:
src: nginx.conf
dest: /etc/nginx/
- name: check nginx conf
shell: nginx -t
ignore_errors: yes
register: ng_re
- name: Start Nginx Server
systemd:
name: nginx
state: restarted
enabled: yes
when: ng_re.stderr_lines is search "ok"
notify监控handlers触发
一、目的
实现对 Nginx 服务器配置文件变化的监控,当配置文件发生变化时,触发相应的 handlers 来重启 Nginx 服务器。
二、配置
总体配置:
[root@ansible ansible]# cat nginx.yml
- hosts: web02
tasks:
- name: Nginx Repo
yum_repository:
name: nginx
description: Nginx YUM repo
baseurl: http://nginx.org/packages/centos/7/$basearch/
gpgcheck: no
enabled: yes
- name: Install Nginx Server
yum:
name: nginx
state: present
- name: Configure Nginx Server
copy:
src: nginx.conf
dest: /etc/nginx/
notify: Restart Nginx Server # 监控nginx配置文件是否发生变化 如果一致不触发handlers,如果发生变化则触发handlers进行重启动作
- name: check nginx conf
shell: nginx -t
ignore_errors: yes
register: ng_re
- name: create group www
group:
name: www
gid: 666
- name: Create www user
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: Start Nginx Server
systemd:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart Nginx Server # 必须和notify后的名称一致
systemd:
name: nginx
state: restarted
when: ng_re.stderr_lines is search "ok"
notify说明
- name: Configure Nginx Server
copy:
src: nginx.conf
dest: /etc/nginx/
notify: Restart Nginx Server
handlers:
- name: Restart Nginx Server
systemd:
name: nginx
state: restarted
when: ng_re.stderr_lines is search "ok"
- 通知机制:
notify: Restart Nginx Server
表示当此任务执行且nginx.conf
文件内容发生变化(即源文件与目标文件不同时),会触发名为Restart Nginx Server
的 handlers。
handlers说明
- name: Configure Nginx Server
copy:
src: nginx.conf
dest: /etc/nginx/
notify: Restart Nginx Server
handlers:
- name: Restart Nginx Server
systemd:
name: nginx
state: restarted
when: ng_re.stderr_lines is search "ok"
- handlers 名称:
Restart Nginx Server
,此名称必须与notify
中指定的名称完全一致,以便在接收到通知时能够正确触发。 - 条件判断:
when: ng_re.stderr_lines is search "ok"
是一个条件语句。它表示只有当变量ng_re
的stderr_lines
中包含 “ok” 时,才会执行重启 Nginx 服务的操作。ng_re
是之前通过nginx -t
命令检查 Nginx 配置文件语法时注册的变量,通过这种方式确保只有在配置文件语法检查通过的情况下才重启 Nginx 服务,避免因配置错误导致服务无法正常启动。
总结
上述配置通过 notify
和 handlers
的配合,实现了对 Nginx 配置文件变化的监控以及在必要时重启 Nginx 服务的功能,并且通过条件判断保证了重启操作是在配置文件语法正确的前提下进行,有助于提高 Nginx 服务器运行的稳定性和可靠性。
综合案例nfs重构
- 重构nfs,并且web服务器自动挂载
1.定义主机清单
[root@ansible ~]# cat /etc/ansible/hosts
[lnmp]
web01 ansible_ssh_host=10.0.0.7
web02 ansible_ssh_host=10.0.0.8
nfs ansible_ssh_host=10.0.0.31
2.配置playbook
[root@ansible oldboy]# cat nfs.yml
- hosts: lnmp
vars:
dir: /data/wp
tasks:
- name: Install nfs-utils
yum:
name: nfs-utils
state: present
- name: Configure nfs Server
copy:
src: exports
dest: /etc/
notify: Restart nfs Server
when: ansible_hostname == "nfs"
- name: create Group www
group:
name: www
gid: 666
- name: Create www User
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: Create "{{ dir }}"
file:
path: "{{ dir }}"
state: directory
owner: www
group: www
- name: Start nfs Server
systemd:
name: nfs
state: started
enabled: yes
when: ansible_hostname == "nfs"
- name: web mount
mount:
src: 172.16.1.31:{{ dir }}
path: /mnt
fstype: nfs
state: mounted
when: ansible_hostname is search "web"
handlers:
- name: Restart nfs Server
systemd:
name: nfs
state: restarted