0x01 前言
最近我又在计划我博客新一代的架构,加入了监控联动的部分。监控主要依赖zabbix,而zabbix agent则是很重要的一个组件。但官方的安装包不能很好适配我的环境,所以我决定自行打包。
自行打包还有一个好处,可以预先配置好agent的配置文件。当rpm被安装时自动填充配置文件内的hostname等信息,而后利用zabbix的自动注册功能在server注册,以此实现自动化监控。
最终通过外部程序调用zabbix api获取数据,最终实现高可用。
想的是比较美好。
0x02 准备
我是用的系统是centos7,只有64位的版本,所以不用纠结32位的;而zabbix源码使用最新的版本,在我写这篇文章的时候,最新版本为4.2.0,下载地址如下:
首先准备一台纯净的虚拟机:
[root@b66760 ~]# lsb_release -a LSB Version: :core-4.1-amd64:core-4.1-noarch Distributor ID: CentOS Description: CentOS Linux release 7.6.1810 (Core) Release: 7.6.1810 Codename: Core
因为打包的过程极有可能需要多次调试,每一次调试都需要编译,为了能最大程度减少编译时间,建议使用SSD替代HDD。
准备好打包环境后即可安装依赖,因为我环境的需要,我需要安装以下软件包:
rpm-build gcc gcc-c++ curl-devel libssh2-devel OpenIPMI-devel
最后两个请根据实际情况选择,一般情况下可以忽略:
完成依赖安装后建立一个临时文件夹,而我的习惯是建立一个codex的文件夹:
[root@b66760 ~]# mkdir /root/codex
默认情况下,rpmbuild的topdir在当前用户的home目录下,但我们可以作出修改:
# 打开或建立文件 vim ~/.rpmmacros # 填入内容并保存 %_topdir /root/codex/
紧接着执行一次rpmbuild命令即可完成相关文件夹的创建:
# 执行命令 [root@b66760 ~]# rpmbuild 1 错误:stat /root/1 失败:没有那个文件或目录 # 检查目录 [root@b66760 ~]# ll codex/ 总用量 0 drwxr-xr-x 2 root root 6 4月 11 23:21 BUILD drwxr-xr-x 2 root root 6 4月 11 23:21 BUILDROOT drwxr-xr-x 2 root root 6 4月 11 23:21 RPMS drwxr-xr-x 2 root root 6 4月 11 23:21 SOURCES drwxr-xr-x 2 root root 6 4月 11 23:21 SPECS drwxr-xr-x 2 root root 6 4月 11 23:21 SRPMS
部分目录的用途如下:
- BUILD:存放打包过程中的源文件
- SOURCE:存放源文件
- SPEC:存放SPEC文件
- SRPM:存放RPM格式的源文件
- RPM:存放二进制文件
最后到SOURCES目录下下载zabbix源码即可:
# 进入文件夹 [root@b66760 ~]# cd /root/codex/SOURCES/ # 下载文件 [root@b66760 SOURCES]# wget 'https://sourceforge.net/projects/zabbix/files/ZABBIX%20Latest%20Stable/4.2.0/zabbix-4.2.0.tar.gz/download' -O zabbix-4.2.0.tar.gz
下载好的源码压缩包不需要解压。
0x03 SPEC文件
SPEC文件是RPM包的描述文件,通过这个文件可以定义如软件名、版本、类别、打包人等信息,最重要的是包含创建、安装和卸载时的操作等。
一个SPEC文件包含几个区段,每个区段对应不同的部署阶段,以下是本文用到的内容:
0x03.1 文件头
文件头主要包含软件包的一些信息,诸如软件名、版本、授权等信息,具体内容如下:
%define client_hostname %(hostname) %define build_timestamp %(date +%s) Name: zabbix-agent Version: 4.2.0 Release: 1%{?dist} Summary: Zabbix Agent Group: Applications/Internet License: GPL Url: https://ngx.hk Source0: zabbix-4.2.0.tar.gz Buildroot: %{_tmppath}/zabbix-%{version}-%{release}-root-%(%{__id_u} -n) Vendor: TerenceChuen BuildArch: x86_64 BuildRequires: gcc, gcc-c++, libssh2-devel, OpenIPMI-devel, curl-devel Requires: gcc, gcc-c++, libssh2, OpenIPMI %description zabbix agent for NGX.HK
第1和第2行中有个%define,它为自定义宏,它可以调用shell脚本等,并可在后面的区段中引用:
# 定义宏,获取hostname %define client_hostname %(hostname) # 引用 %{client_hostname}
BuildRequires与Requires则表示打包时需要的依赖包和安装时需要的依赖包。如果没在系统中检测到相关软件包,则抛出错误。
0x03.2 构建预处理
预处理段以%prep开头,并在下一行编写命令。
预处理段支持shell命令,一般用来进行解包操作,如tar,unzip等。
而一般情况下,我会使用&setup解压SOURCES目录中的tar.gz压缩包。如果压缩包的名称与软件包的名称一致,那么可以直接使用:
%setup -c
如果不一致或希望提高SPEC文件的可用性,可以用-n指定压缩包名称:
%setup -q -n zabbix-%{version}
而%{version}这个宏是在文件头中定义的Version,上面这个%setup命令最终会将SOURCES目录下的zabbix-4.2.0.tar.gz文件解压到BUILD目录中。
0x03.3 构建
构建段以%build开头,这部分内容和平平常编译软件的部分一致,主要通过configure文件与相关参数定制化软件并使用make编译。
如果是其他软件,构建部分的内容可能较为复杂。而zabbix agent的构建内容如下:
%build ./configure \ --prefix=/usr/local/zabbix \ --enable-agent \ --with-net-snmp \ --with-libcurl \ --with-libxml2 \ --with-ssh2 \ --with-openipmi \ --with-openssl \ --with-libcurl make
0x3.4 安装段
安装段以%install开头,主要执行的是make install命令,而安装的路径为文件头中定义的目录:Buildroot。
%install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install
0x03.5 清理临时文件
保持目录整洁是个好习惯。
%clean rm -rf $RPM_BUILD_ROOT
0x03.6 部署前预处理
该部分以%pre开头。
这个部署是指将打包好的RPM包在目标系统中安装的过程,而这个安装可能会有前置准备工作。诸如用户创建、目录创建与权限修改等。
%pre getent group zabbix || groupadd zabbix getent passwd zabbix || useradd -M -s /sbin/nologin -g zabbix zabbix [ -d /usr/local/zabbix ] && rm -rf /usr/local/zabbix [ -d /var/run/zabbix ] || mkdir /var/run/zabbix && chown zabbix:zabbix /var/run/zabbix [ -f /var/log/zabbix_agentd.log ] || touch /var/log/zabbix_agentd.log && chown zabbix:zabbix /var/log/zabbix_agentd.log
因为我打包的zabbix agent RPM安装包主要用于系统安装完成后的自动化部署工作,所以没有旧版本zabbix agent配置文件备份等顾虑,因此我在部署前预处理部分中选择直接删除相关文件夹。
如果你是打包用于升级或大规模分发的RPM包,则建议根据实际情况修改该部分内容。
0x03.7 安装后执行
该部分以%post开头。
该部分主要是RPM包安装后执行,可以进行RPM解包之后的配置文件修改等操作。
%post sed -i "/^# PidFile=/a\PidFile=/var/run/zabbix/zabbix_agentd.pid" /usr/local/zabbix/etc/zabbix_agentd.conf sed -i "/^LogFile=/c\LogFile=/var/log/zabbix_agentd.log" /usr/local/zabbix/etc/zabbix_agentd.conf sed -i "/^Server=/c\Server=zbx.ngx.hk" /usr/local/zabbix/etc/zabbix_agentd.conf sed -i "/^ServerActive=/c\ServerActive=zbx.ngx.hk" /usr/local/zabbix/etc/zabbix_agentd.conf sed -i "/^Hostname=/c\Hostname=%{client_hostname}" /usr/local/zabbix/etc/zabbix_agentd.conf cat > /usr/lib/systemd/system/zabbix-agent.service << "EOF" [Unit] Description=Zabbix Agent After=syslog.target After=network.target [Service] Environment="CONFFILE=/usr/local/zabbix/etc/zabbix_agentd.conf" EnvironmentFile=-/etc/sysconfig/zabbix-agent Type=forking Restart=on-failure PIDFile=/run/zabbix/zabbix_agentd.pid KillMode=control-group ExecStart=/usr/local/zabbix/sbin/zabbix_agentd -c $CONFFILE ExecStop=/bin/kill -SIGTERM $MAINPID RestartSec=10s [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable zabbix-agent.service
而在我的项目中,我还建立了启动文件zabbix-agent.service,并将其设为自动启动。
0x3.8 卸载前执行
卸载前需要停止服务,而我在停止服务之后还禁用了该服务的自动启动以删除相关软链接,而这部分内容以%preun:
%preun systemctl stop zabbix-agent.service systemctl disable zabbix-agent.service
0x03.9 卸载后执行
如果大家卸载过zabbix agent会发现,它会将配置文件重命名并保留在系统中,以便后续查看或修改。而这个工作正是由%preun这个区段内容执行的脚本。
# rpm卸载后执行 %postun userdel zabbix rm -rf /usr/local/zabbix rm -rf /var/run/zabbix rm -f /usr/lib/systemd/system/zabbix-agent.service
但在我的环境中就比较粗暴,我选择直接删除文件与目录。
0x03.10 打包的文件
以%files开头的内容表示需要打包到RPM包中的内容,因为我编译的路径为:/usr/local/zabbix,所以我的配置信息为:
%files %defattr(-,root,root) /usr/local/zabbix
这里有个%defattr,代表默认权限。
-为权限默认值,即:文本文件0644、可执行文件0755,而后面两个值分别为owner和group。
当然,还可以单独配置权限,如:
%attr(0755,root,root) /usr/local/zabbix/bin/zabbix_agentd
0x03.11 完整文件
%define client_hostname %(hostname) %define build_timestamp %(date +%s) Name: zabbix-agent Version: 4.2.0 Release: 1%{?dist} Summary: Zabbix Agent Group: Applications/Internet License: GPL Url: https://ngx.hk Source0: zabbix-4.2.0.tar.gz Buildroot: %{_tmppath}/zabbix-%{version}-%{release}-root-%(%{__id_u} -n) Vendor: TerenceChuen BuildArch: x86_64 BuildRequires: gcc, gcc-c++, libssh2-devel, OpenIPMI-devel, curl-devel Requires: gcc, gcc-c++, libssh2, OpenIPMI %description zabbix agent for NGX.HK # 预处理 %prep # 解压源码压缩包 %setup -q -n zabbix-%{version} # 编译 %build ./configure \ --prefix=/usr/local/zabbix \ --enable-agent \ --with-net-snmp \ --with-libcurl \ --with-libxml2 \ --with-ssh2 \ --with-openipmi \ --with-openssl \ --with-libcurl make # 安装 %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install # 清理临时文件 %clean rm -rf $RPM_BUILD_ROOT # 安装前执行 %pre getent group zabbix || groupadd zabbix getent passwd zabbix || useradd -M -s /sbin/nologin -g zabbix zabbix [ -d /usr/local/zabbix ] && rm -rf /usr/local/zabbix [ -d /var/run/zabbix ] || mkdir /var/run/zabbix && chown zabbix:zabbix /var/run/zabbix [ -f /var/log/zabbix_agentd.log ] || touch /var/log/zabbix_agentd.log && chown zabbix:zabbix /var/log/zabbix_agentd.log # rpm安装后执行 %post sed -i "/^# PidFile=/a\PidFile=/var/run/zabbix/zabbix_agentd.pid" /usr/local/zabbix/etc/zabbix_agentd.conf sed -i "/^LogFile=/c\LogFile=/var/log/zabbix_agentd.log" /usr/local/zabbix/etc/zabbix_agentd.conf sed -i "/^Server=/c\Server=zbx.ngx.hk" /usr/local/zabbix/etc/zabbix_agentd.conf sed -i "/^ServerActive=/c\ServerActive=zbx.ngx.hk" /usr/local/zabbix/etc/zabbix_agentd.conf sed -i "/^Hostname=/c\Hostname=%{client_hostname}" /usr/local/zabbix/etc/zabbix_agentd.conf cat > /usr/lib/systemd/system/zabbix-agent.service << "EOF" [Unit] Description=Zabbix Agent After=syslog.target After=network.target [Service] Environment="CONFFILE=/usr/local/zabbix/etc/zabbix_agentd.conf" EnvironmentFile=-/etc/sysconfig/zabbix-agent Type=forking Restart=on-failure PIDFile=/run/zabbix/zabbix_agentd.pid KillMode=control-group ExecStart=/usr/local/zabbix/sbin/zabbix_agentd -c $CONFFILE ExecStop=/bin/kill -SIGTERM $MAINPID RestartSec=10s [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable zabbix-agent.service # rpm卸载前执行 %preun systemctl stop zabbix-agent.service systemctl disable zabbix-agent.service # 放入rpm中的文件 %files # 文件属性,mode,owner,group,-为默认值(文本文件0644,可执行文件0755) %defattr(-,root,root) /usr/local/zabbix # rpm卸载后执行 %postun userdel zabbix rm -rf /usr/local/zabbix rm -rf /var/run/zabbix rm -f /usr/lib/systemd/system/zabbix-agent.service
0x04 打包
通过help参数查看rpmbuild的相关信息可以发现又多种打包参数:
在这里,我使用-ba参数从specfile构建源代码和二进制软件包:
[root@b66760 SPECS]# rpmbuild -ba zabbix-agent.spec
完成编译和打包后即可在RPMS文件夹中找到打包好的RPM包:
[root@b66760 SPECS]# ll -h /root/codex/RPMS/x86_64/ 总用量 996K -rw-r--r-- 1 root root 234K 4月 18 11:50 zabbix-agent-4.2.0-1.el7.x86_64.rpm -rw-r--r-- 1 root root 757K 4月 18 11:50 zabbix-agent-debuginfo-4.2.0-1.el7.x86_64.rpm
0x05 应用
将在0x04中打包好的RPM包复制到目标机器,即可用rpm或yum命令安装:
[root@b66760 x86_64]# yum install ./zabbix-agent-4.2.0-1.el7.x86_64.rpm
卸载可以通过rpm和yum进行:
[root@b66760 x86_64]# yum remove zabbix-agent.x86_64
0x06 结语
RPM包可以将打包的时间戳添加到文件名中,然后将PRM包放置到内部源,再通过自动部署手段即可实现自动更新、下发配置等操作。