ansible-playbook实战:为多台服务器批量安装zabbix-agent

1. 前言

在2021年的当下,Ansible得益于自身配置简单功能丰富等优点,已经是一个很流行的自动化运维工具了。

而在笔者日常的工作场景中,当首选方案企业版蓝鲸系统作业平台处于维护状态或者是不可用时,会使用ansible作为自动化部署的备用方案。

今天来简单假设一个需求,为多台服务器批量安装zabbix-agent,通过这个过程介绍一下ansible-playbook的使用和编排方法。

我会假设你已经成功安装好了ansible,并且掌握ansible的基本使用方法。如果你没有,这里有个好东西: Installation Guide

2. 实验环境准备

2.1 拓扑图

ansible-diagram

2.2 主机列表

用于测试的ansible inventory文件test_server_list.txt 内容如下:

1
2
3
4
[test_server]
192.168.0.211
192.168.0.212
192.168.0.213

2.3 用ansible ping 验证ssh登录

使用配置好的RSA密钥去测试ansible到各个测试服务器的连接情况:

1
ansible -i test_server_list.txt test_server --key-file=~/.ssh/id_rsa -m ping

理想状态下,会得到返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
192.168.0.211 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.0.212 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
192.168.0.213 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}

3. ansible without playbook

这是一个不优雅的方案。

假设你已经准备好了一个zabbix-agent安装脚本,类似这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/sh

# /data/my_ansible/scripts/centos-install-zabbix-agent.sh

# install zabbix repository
rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm
dnf clean all

# install zabbix-agent
dnf install zabbix-agent

# prepare zabbix agent configuration file
cat << EOF > /etc/zabbix/zabbix_agentd.conf
PidFile=/var/run/zabbix/zabbix_agentd.pid
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=0
DenyKey=system.run[*]
Server=192.168.0.100
Include=/etc/zabbix/zabbix_agentd.d/*.conf
EOF

systemctl start zabbix-agent.service
systemctl enable zabbix-agent.service

那要通过ansible调用也很简单:
大概是这个流程,我只是随手一写,没有实际试过,因为这个不是重点 ;-)

1
ansible -i test_server_list.txt test_server -m script -a '/data/my_ansible/scripts/centos-install-zabbix-agent.sh'

如无意外,这个方案也是能成功的, 在这个部署思路下,我们再看看如何用ansible-playbook实现。

4. ansible with playbook

As you may have noticed,我在前言部分提到了“编排”这个词。

ansible-playbook最大的特点,就是能把各种运维场景中常用的操作,都整合成了众多可以直接调用的标准模块。而在编写playbook之前,我们需要提前拟出一个方案,把我们的需求划分成多个清晰的步骤。

下面我们从易到难,一步一步引入各个功能。

4.1 编写playbook

4.1.1 部署任务分析

回到我们的主题,当我要在服务器上面部署zabbix-agent,简单来说可以分成下面几个步骤:

  1. 安装zabbix的repo
  2. 使用yum安装zabbix-agent
  3. 设置开机启动zabbix-agent
  4. 根据环境修改zabbix-agent的配置文件
  5. 启动zabbix-agent

4.1.2 示例ansible-playbook

根据上文提到的各个步骤,我们便可以编写出一个纯粹的playbook。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- name: install zabbix agent
hosts: test_server
become: True
gather_facts: True
vars:
zabbix_server_ip: 192.168.0.100
zabbix_server_port: 20051
tasks:
- name: Install zabbix-agent repo
yum:
name: https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm
validate_certs: no
state: present
- name: install zabbix-agent
yum: name=zabbix-agent state=latest
- name: enable zabbix-agent service
systemd: name=zabbix-agent enabled=True
- name: copy zabbix-agent configuration file
template: src=zabbix_agentd.conf.j2 dest=/etc/zabbix/zabbix_agentd.conf
notify: restart zabbix-agent
handlers:
- name: restart zabbix-agent
service: name=zabbix-agent state=restarted

在上面的yaml文件中,使用了以下几个ansible模块:

  • yum: 提供yum管理工具的功能,在本例中通过yum模块添加了zabbix的repo,并使用yum完成了zabbix-agent的安装。

  • systemd: 用于管理systemd中的daemon。

  • template: 提供配置文件的模板渲染功能。

4.1.3 准备配置模板

熟悉zabbix监控的人都知道,zabbix-agent有主动和被动两种模式。当我们使用主动模式的时候,zabbix-agent会主动向zabbix-server上报监控数据。为了实现这个功能,需要提前在zabbix-agent的配置文件中加入ServerActiveHostname两个配置项,前者会告诉zabbix-agent把监控数据上报到哪里,后者需要和zabbix-server的配置页面中Configuration -> Hosts所添加的服务器信息中的Host name配置项一致。

也就是说,我们需要对这两个配置项进行可变的配置,尤其是Hostname配置项,往往每台服务器都不一样。在这里,我要对每台服务器的Hostname配置项填入该服务器的内网IP地址。

为了满足这个需求,在上面的playbook中,使用了template功能。配置模板如下:

1
2
3
4
5
6
7
PidFile=/var/run/zabbix/zabbix_agentd.pid
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=0
Server={{ zabbix_server_ip }}
ServerActive={{ zabbix_server_ip }}:{{ zabbix_server_port }}
Hostname={{ ansible_eth0.ipv4.address }}
Include=/etc/zabbix/zabbix_agentd.d/

当playbook运行的时候,template中的变量会被渲染成具体的内容,再复制到目标路径中。在本例中,使用了zabbix_server_ipzabbix_server_port两个自定义变量,至于另一个变量ansible_eth0.ipv4.address最后会赋值为目标服务器上的内网IP。

4.1.4 触发运行handler

我们会看到,在上面的playbook示例的末尾,有一个handlers区段,同时,在task里面包含一个notify关键字。

Ansible的一个重要特征是幂等性(idempotent),意思是我们可以对服务器重复执行同一个任务多次,效果都是相同的。也就是说,当我们即将要进行一次批量部署的时候,或者是因为出错而重新运行部署任务的时候,我们都不用担心会有潜在隐患。

在任务执行过程中,当ansible识别到这个task任务使系统发生了变更,就会通知task中指定的handler,进而触发在handler中配置的操作。

在本例中,ansible只会在检测到zabbix-agent的配置文件被修改后,才会通知handler去重启zabbix-agent,使配置生效。反过来说,在重复执行这个playbook的时候,如果ansible发现服务器的zabbix-agent配置文件没有发生变更,则不会重启zabbix-agent。

4.2 运行前检查

经过上面的一顿操作猛如虎,我们已经万事俱备,就欠一句执行命令了。

总结一下,现在的playbook文件编排如下:

1
2
3
4
5
./playbooks/
├── install-zabbix-agent.yml
├── templates
│   └── zabbix_agentd.conf.j2
└── test_server_list.txt

4.2.1 检查playbook语法

一般来说,在执行之前,都会先进行一次语法检查:

1
ansible-playbook -i playbooks/test_server_list.txt --syntax-check playbooks/install-zabbix-agent.yml

4.2.2 检查主机列表

查看会有哪些服务器会执行这一次的任务:

1
ansible-playbook -i playbooks/test_server_list.txt --list-tasks playbooks/install-zabbix-agent.yml 

4.2.3 试运行playbook(演习模式)

加入--check参数后,ansible会模拟一次playbook的执行并返回各个任务的执行状态,但不会对hosts执行任何实际的修改:

1
ansible-playbook -i playbooks/test_server_list.txt --key-file=~/.ssh/id_rsa --check playbooks/install-zabbix-agent.yml 

4.3 运行playbook

执行命令:

1
ansible-playbook -i playbooks/test_server_list.txt --key-file=~/.ssh/id_rsa playbooks/install-zabbix-agent.yml

输出结果节选如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ansible-playbook -i playbooks/test_server_list.txt --key-file=~/.ssh/id_rsa playbooks/install-zabbix-agent.yml    

PLAY [install zabbix agent] ********************************************************************************************

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

TASK [Install zabbix-agent repo] ***************************************************************************************
changed: [192.168.0.211]

TASK [install zabbix-agent] ********************************************************************************************
changed: [192.168.0.211]

TASK [enable zabbix-agent service] *************************************************************************************
changed: [192.168.0.211]

TASK [copy zabbix-agent configuration file] ****************************************************************************
changed: [192.168.0.211]

RUNNING HANDLER [restart zabbix-agent] *********************************************************************************
changed: [192.168.0.211]

PLAY RECAP *************************************************************************************************************
192.168.0.211 : ok=6 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

可以看到,在ansible的带领下,目标服务器192.168.0.211 按照playbook中定义的顺序,顺利完成了zabbix-agent的安装。

5. 总结

实不相瞒,在笔者最初接触ansible的时候,使用的就是不优雅的方案。因为没有完成思维的转变,只把ansible当作一个批量跑脚本的工具。直到后来接触的服务种类多了,维护的部署脚本以及相应的配置文件变多了之后,才意识到ansible-playbook的香。

而且,使用ansible-playbook还有助于我们养成一个先把任务捋顺了再去编写过程的习惯,比起打开一个shell脚本疯狂输出,成竹在胸地去编写playbook文件是一件优雅得多的事情。更让人欣慰的是,ansible-playbook中的yaml格式比起零零碎碎的shell脚本,更显得赏心悦目(可读性更强)。

然而,ansible-playbook的玩法可不止于此,后面我会介绍更复杂的运维场景,看看如何继续挖掘ansible-playbook的潜力。

6. 扩展阅读

zabbix 5.0 安装指引

ansible user guide

writing-tasks-plays-and-playbooks