安装 Zabbix Agent
对于 CentOS 7
sudo rpm -Uvh https://repo.zabbix.com/zabbix/6.4/rhel/7/x86_64/zabbix-release-6.4-1.el7.noarch.rpm
对于 CentOS 8
sudo rpm -Uvh https://repo.zabbix.com/zabbix/6.4/rhel/8/x86_64/zabbix-release-6.4-1.el8.noarch.rpm
对于 CentOS 9
sudo rpm -Uvh https://repo.zabbix.com/zabbix/6.4/rhel/9/x86_64/zabbix-release-6.4-1.el9.noarch.rpm
更新缓存
sudo yum clean all
安装
sudo yum install zabbix-agent -y
配置 Zabbix Agent
-
编辑配置文件
sudo vi /etc/zabbix/zabbix_agentd.conf
-
修改以下关键参数
Server=<Zabbix_Server_IP> ServerActive=<Zabbix_Server_IP> Hostname=<Client_Hostname>
- Server:填写 Zabbix Server 的 IP 地址。指定允许连接到代理的 Zabbix 服务器或代理端 IP 地址。它是一个安全控制参数,确保只有列出的 IP 地址可以与代理通信
- ServerActive:填写 Zabbix Server 的 IP 地址。指定 Zabbix 代理将主动连接到的 Zabbix 服务器的 IP 地址或主机名,用于主动检查模式。代理会向列出的服务器发送监控数据。
- Hostname:填写此客户端在 Zabbix Server 上的唯一名称(应与 Zabbix Server 上配置的主机名一致)。
配置多个主动模式
Server=172.19.20.107,172.19.20.106 #多个IP地址用逗号(,)分割
ServerActive=172.19.20.147:10051 #添加多个的主动模式
ServerActive=172.19.20.146:10051
其它配置参数
如要要使用system.run,需要添加支持的key,否则会报错:Unsupported item key.
AllowKey=system.run[*]
自定义UserParameter
UserParameter=custom.basic,/root/zabbix-agent/zabbix_basic.sh
UserParameter=custom.disk_free,df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted usedd"} {print $1,$3,$4,$5,$6,$3}'
3. 配置防火墙
sudo firewall-cmd --permanent --add-port=10050/tcp
sudo firewall-cmd --permanent --add-port=10051/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
启动 Zabbix Agent
-
设置开机自启动
sudo systemctl enable zabbix-agent
-
启动 Zabbix Agent
sudo systemctl start zabbix-agent
-
检查状态
sudo systemctl status zabbix-agent
验证 Zabbix Agent
-
确保 Zabbix Agent 正常运行
sudo systemctl status zabbix-agent
-
测试 Zabbix Agent 与 Zabbix Server 通信
zabbix_get -s <Client_IP> -k agent.ping
- 返回
1
表示正常通信。
查看Zabbix Agent日志
tail -f /var/log/zabbix/zabbix_agentd.log
我在 WSL 启动 zabbix agent 报错:
sudo systemctl start zabbix-agent Failed to get D-Bus connection: Operation not permitted
可以直接启动 zabbix_agentd:
sudo /usr/sbin/zabbix_agentd -c /etc/zabbix/zabbix_agentd.conf
ps aux | grep zabbix_agentd
SpringBoot自定义Server和Zabbix-agent通信
比较简单,生产环境未测试,仅供开发测试。
ZabbixSocketServerRunner.java
package com.xxx.xxx.runner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class ZabbixSocketServerRunner implements CommandLineRunner {
@Autowired
private ZabbixSocketServer zabbixSocketServer;
@Override
public void run(String... args) throws Exception {
System.out.println("✅ Zabbix Server Socket are ready.");
zabbixSocketServer.startServer(10051);
}
}
ZabbixSocketServer.java
package com.xxx.xxx.runner;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
@Service
@Slf4j
class ZabbixSocketServer {
@Async
public void startServer(int port) throws Exception {
try (ServerSocket serverSocket = new ServerSocket(port)) {
log.info("✅ Listening on 0.0.0.0:{}", port);
while (true) {
Socket clientSocket = serverSocket.accept();
log.info("\uD83D\uDD17 Connection from {}", clientSocket.getInetAddress());
new Thread(() -> handleClient(clientSocket)).start();
}
}
}
private void handleClient(Socket clientSocket) {
try (InputStream input = clientSocket.getInputStream(); OutputStream output = clientSocket.getOutputStream()) {
byte[] header = new byte[13];
int bytesRead = input.read(header);
if (bytesRead < 13 || !new String(header, 0, 4).equals("ZBXD")) {
log.error("无效的header");
return;
}
// 提取协议版本
byte protocolVersion = header[4];
if (protocolVersion != 1) {
log.error("不支持的协议版本: {}", protocolVersion);
return;
}
// 提取数据长度(在 Zabbix 协议中始终为 little-endian)
long dataLength = 0;
for (int i = 0; i < 8; i++) {
dataLength |= ((long) (header[5 + i] & 0xFF)) << (i * 8);
}
if (dataLength > 10 * 1024 * 1024) {
log.error("数据长度过大,限制10MB");
return;
}
byte[] dataBytes = new byte[(int) dataLength];
int totalRead = 0;
while (totalRead < dataLength) {
int read = input.read(dataBytes, totalRead, (int) (dataLength - totalRead));
if (read == -1) break;
totalRead += read;
}
String receivedJson = new String(dataBytes, StandardCharsets.UTF_8);
log.info("接收到的JSON:\n{}", receivedJson);
String responseJson = generateResponse(receivedJson);
log.info("生成的返回JSON:\n{}", responseJson);
byte[] responsePayload = responseJson.getBytes(StandardCharsets.UTF_8);
// 创建header - 'ZBXD\1' 后跟 little-endian 格式的 payload 长度
byte[] responseHeader = new byte[13];
responseHeader[0] = 'Z';
responseHeader[1] = 'B';
responseHeader[2] = 'X';
responseHeader[3] = 'D';
responseHeader[4] = 1; // Protocol version
// 以 little-endian 格式写入长度
long responseLength = responsePayload.length;
for (int i = 0; i < 8; i++) {
responseHeader[5 + i] = (byte) ((responseLength >> (i * 8)) & 0xFF);
}
output.write(responseHeader);
output.write(responsePayload);
output.flush();
} catch (Exception e) {
log.info("处理 TCP 客户端时出错: {}", e.getMessage());
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
log.info("关闭client socket出错: {}", e.getMessage());
}
}
}
private String generateResponse(String receivedJson) {
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(receivedJson);
if (rootNode.has("request")) {
String request = rootNode.get("request").asText();
if ("active checks".equals(request)) {
// 从请求中获取主机
String host = rootNode.has("host") ? rootNode.get("host").asText() : "unknown";
log.info("active checks的主机: {}", host);
// 日志
ObjectNode dataItem = mapper.createObjectNode();
dataItem.put("itemid", 12345);
dataItem.put("name", "log item");
dataItem.put("type", "ZABBIX_ACTIVE"); // 监控项类型,ZABBIX_ACTIVE Zabbix主动模式
dataItem.put("key", "log[/var/log/zabbix/zabbix_agentd.log,error]");
dataItem.put("delay", 120);
dataItem.put("lastlogsize", 0); // 上次已读取的日志文件字节偏移量,下次从这里继续读取,返回的数据中会有{"request":"agent data","session":"979b49792d714c5cfcc49831d05802fd","data":[{"host":"Zabbix server","key":"log[/var/log/zabbix/zabbix_agentd.log,error]","value":"test8 error","lastlogsize":1210802,"id":16134,"clock":1747817135,"ns":113673130}],"clock":1747817135,"ns":113941398}
dataItem.put("value_type", "LOG");
dataItem.put("mtime", 0); // 日志文件的修改时间(时间戳)
dataItem.put("logtimefmt", "pppppp:yyyyMMdd:hhmmss");
// 执行命令结果,脚本用双引号包裹,脚本内容中的双引号要\转义
ObjectNode systemRun = mapper.createObjectNode();
systemRun.put("itemid", 12346);
systemRun.put("name", "system run item");
systemRun.put("type", "ZABBIX_ACTIVE");
systemRun.put("key", "system.run[\"fre -h | awk 'BEGIN{print \\\"total used free\\\"} NR==3{print $2,$3,$4}'\"]");
systemRun.put("lastlogsize", 0);
systemRun.put("mtime", 0);
systemRun.put("delay", 120);
ObjectNode systemRun2 = mapper.createObjectNode();
systemRun2.put("itemid", 12347);
systemRun2.put("name", "system run item2");
systemRun2.put("type", "ZABBIX_ACTIVE");
systemRun2.put("key", "system.run[\"ps -aux | sort -k3nr | awk 'BEGIN{ print \\\"id pid cpu_usage mem_usage command\\\" } {print NR,$2, $3, $4, $11}'| head -n 11\"]");
systemRun2.put("lastlogsize", 0);
systemRun2.put("mtime", 0);
systemRun2.put("delay", 120);
ObjectNode systemRun3 = mapper.createObjectNode();
systemRun3.put("itemid", 12348);
systemRun3.put("name", "system run item3");
systemRun3.put("type", "ZABBIX_ACTIVE");
systemRun3.put("key", "system.run[\"LANG=C lscpu | awk -F: '$1==\\\"Model name\\\" {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}';vmstat 1 2 | awk 'NR==4{print $15}'\"]");
systemRun3.put("lastlogsize", 0);
systemRun3.put("mtime", 0);
systemRun3.put("delay", 120);
ObjectNode custom = mapper.createObjectNode();
custom.put("itemid", 12349);
custom.put("name", "custom.disk_free");
custom.put("type", "ZABBIX_ACTIVE");
custom.put("key", "custom.disk_free");
custom.put("lastlogsize", 0);
custom.put("mtime", 0);
custom.put("delay", 120);
ArrayNode dataArray = mapper.createArrayNode();
dataArray.add(dataItem);
dataArray.add(systemRun);
dataArray.add(custom);
dataArray.add(systemRun2);
dataArray.add(systemRun3);
ObjectNode response = mapper.createObjectNode();
response.put("response", "success");
response.set("data", dataArray);
return mapper.writeValueAsString(response);
} else if ("agent data".equals(request)) {
// 处理agent data请求
if (rootNode.has("data") && rootNode.get("data").isArray()) {
JsonNode dataArray = rootNode.get("data");
log.info("收到的 agent data 数量: {}", dataArray.size());
for (JsonNode item : dataArray) {
if (item.has("key") && item.has("value")) {
log.info("返回结果: \n{} → \n{}", item.get("key").asText(), item.get("value").asText());
}
}
}
// agent data成功响应
ObjectNode response = mapper.createObjectNode();
response.put("response", "success");
return mapper.writeValueAsString(response);
}
}
// 无法识别请求类型时的默认响应
ObjectNode response = mapper.createObjectNode();
response.put("response", "failed");
response.put("info", "Unsupported request type: " + receivedJson);
return mapper.writeValueAsString(response);
} catch (Exception e) {
log.info("生成响应时出错: {}", e.getMessage());
e.printStackTrace();
try {
ObjectNode response = new ObjectMapper().createObjectNode();
response.put("response", "failed");
response.put("info", "Internal error: " + e.getMessage());
return new ObjectMapper().writeValueAsString(response);
} catch (Exception ex) {
return "{\"response\":\"failed\",\"info\":\"Internal error\"}";
}
}
}
}
zabbix_agentd.conf 配置修改
Server=172.19.20.107
ServerActive=172.19.20.147:10051
AllowKey=system.run[*]
UserParameter=custom.disk_free,df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted usedd"} {print $1,$3,$4,$5,$6,$3}'
参考文档
Header: https://www.zabbix.com/documentation/current/zh/manual/appendix/protocols/header_datalen
主被动Agent: https://www.zabbix.com/documentation/current/zh/manual/appendix/items/activepassive
Agent支持内容:https://www.zabbix.com/documentation/7.2/zh/manual/config/items/itemtypes/zabbix_agent#log
Comments (暂无评论)