前几天在给一台浪潮信息KeyarchOS(KOS)服务器做日志审计的时候,发现系统里日志文件越堆越多,却没有一个能每天早上自动汇总关键事件的工具。翻遍系统默认仓库,logwatch没有被收录;直接去网上找一个现成RPM,装完又是一堆Perl依赖问题,要么版本不对、要么路径跑偏。折腾下来,最靠谱的办法就是从官方src.rpm开始,在KOS上完整走一遍rpmbuild编译、配置、部署的流程。这篇文章就是把整个过程复盘一遍,适配对象是浪潮信息KeyarchOS,软件版本logwatch-7.3.6-55。适合两类人:一是KOS上做基础运维、希望把日志分析自动化补全的同学;二是想把主流开源组件迁移到KOS上做成正式RPM包的编译党。我会把中间踩过的坑、改过的spec、验证过的命令全部列出来。
1. 为什么要在KeyarchOS上给logwatch做适配
1.1 先搞清楚KOS是什么
浪潮信息KeyarchOS(KOS)本质上是面向数据中心场景的企业级Linux发行版,底层沿用标准Linux内核,包管理、服务管理、网络配置这些习惯和主流企业级Linux生态保持一致。它针对浪潮自家服务器硬件做了很多专项优化,比如固件带外管理、驱动适配、安全加固等。对运维来说,刚上手KOS时基本不会有陌生感,dnf install、systemctl这些命令照用不误。
但问题也出在这里。主流企业级Linux生态的软件仓库虽然庞大,却不可能把每个实用小工具都收录进去。logwatch这类“日志分析辅助工具”在默认源里的地位相当边缘,要么没有,要么版本落后。我在KOS上dnf search logwatch的结果是空的,第一反应是从CentOS生态找一个二进制包直接装,结果装上之后logwatch --version报缺少Perl模块。这就是典型的“二进制包能装上,但跑不起来”。
所以“适配”这两个字,不是简单把软件拷过来,而是要让它在KOS的目录结构、Perl路径、依赖声明都正确的前提下,作为系统原生软件包运行起来,并且能被dnf统一管理。
1.2 logwatch能解决什么实际问题
logwatch是一个用Perl写的日志分析聚合工具。它的工作模式很简单:定期扫描指定日志,把sshd登录失败、sudo提权记录、磁盘空间不足、服务重启、防火墙拦截这些事件分类汇总,生成一份可读的摘要报告,再通过邮件发送给管理员。
服务器日志管理有个真实痛点:日志量太大,人工翻不动。/var/log/secure一天能刷几百行,大部分是无效信息,但里面偶尔藏着暴力破解的关键迹象。logwatch的价值就是它内置了30多类服务的解析脚本,自动做排序、去重、归纳,最后只把核心信息呈现出来。相比自己写shell脚本轮询,logwatch的规则沉淀和输出格式都是现成的,省掉很多重复造轮子的时间。
选择7.3.6-55而不是更新版本,是经过考虑的。7.3.6这个上游版本在主流企业级生态里已经非常稳定,各功能模块基本冻结,不会频繁变动。55这个release号代表发行版维护补丁已经叠加了很多轮,比较成熟。另外,logwatch的核心依赖是Perl环境和少量Perl模块,版本越新越可能要求更新的Perl构建特性,反而增加适配复杂度。稳字当头,选这个版本最合适。
1.3 不直接装二进制的三个理由
我一开始图省事,尝试过直接装CentOS/RHEL系的logwatch RPM,也试过从GitHub拉源码make install,两条路都走不通,或者说不值得走。
第一条路是二进制兼容风险。不同发行版对Perl模块的路径定义有差异,/usr/lib/perl5和/usr/share/perl5的划分规则不一定一样,依赖的perl模块版本也可能和KOS自带的Perl版本有冲突。装的时候可能一切顺利,跑的时候才暴露问题,排查成本反而更高。
第二条路是源码直接make install。这是最不可取的做法,因为装完的文件散落在/usr/local/bin、/usr/local/share等路径,完全脱离dnf的管理体系。以后想升级、卸载、批量分发,都变成麻烦事。对正规审计环境来说,网络上下载的脚本文件如果不在RPM台账里,连安全合规都不好交代。
最终结论只有一个:拿到src.rpm,在当前系统上重新构建出适配KOS环境的RPM包。构建产物再导入本地仓库,以后任何一台KOS机器都能dnf install,这是最干净的方案。
2. 适配方案选型:直接装、源码装还是RPM构建
2.1 三种做法对比
我把三条路线放在一起做过对比,整理成一张表,方便你根据自己环境判断。
| 做法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 在线仓库直接安装 | 速度快、一条命令搞定 | KOS默认源基本没收录logwatch | 一般发行版有现成包时 |
| 下载其他发行版二进制RPM | 省去编译环节 | 依赖不匹配、路径差异、版本兼容待验证 | 临时验证功能时 |
| 源码编译并make install | 完全可控、可自定义 | 不受dnf管理、升级卸载困难、批量分发难 | 开发调试、个人临时使用 |
| 源码src.rpm重建RPM | 生成正式RPM、纳入仓库管理、可复现 | 需要理解spec构建流程 | 正式生产适配 |
2.2 为什么最终选择src.rpm重建
我选src.rpm重建,核心逻辑是“复用上游构建配方”。src.rpm里面包含的不只是源码压缩包,还有spec文件、补丁、构建说明。spec文件就是构建说明书,定义了软件装哪些文件、依赖什么包、安装到哪里、有什么前置脚本。基于同一个spec重新构建,能最大程度保留上游的补丁和经验,避免自己从零写安装脚本时漏掉细节。
可能有人会问,为什么不直接用源码包自己写一个spec?说实话,对logwatch这种文件散落多个目录的Perl应用,自己写spec很容易在%files段落漏掉配置文件、脚本目录、文档目录,构建完要么缺文件,要么rpm -V校验不过。基于官方src.rpm改,效率和安全都更有保障。
2.3 规划交付产物
整个适配的目标产物很清晰:一个noarch架构的RPM包,加上配套的本地仓库索引。logwatch是纯Perl脚本应用,不涉及CPU平台相关二进制编译,所以构建出来的包是noarch,x86_64和aarch64架构都能装。这意味着只要在一台构建机上跑通构建,其他架构的KOS服务器可以直接复用产物,不需要每台机器各编译一遍。
交付物清单包括:
logwatch-7.3.6-55.*.noarch.rpm(二进制包)logwatch-7.3.6-55.*.src.rpm(源包,留档备查)- 修改后的spec文件
- 本地仓库repodata索引(用于批量分发)
3. 编译前准备:环境搭建与依赖分析
3.1 准备一台干净构建机
编译的第一原则,不要在正在运行业务的生产机上直接构建。构建过程中可能会安装额外的开发工具、生成临时文件,甚至触发安全扫描告警。最好准备一台和线上环境同版本KOS的独立虚拟机或小机器,专门做构建。
进入构建机后,先确认系统信息。
cat /etc/os-release uname -m perl -v第一项确认KOS版本和构建机一致,保证产物的兼容性。第二项确认架构,虽然目标是noarch包,但构建机的Perl环境会影响构建过程中的路径生成逻辑。第三项确认Perl版本,logwatch依赖的Perl模块需要和当前Perl版本兼容。
3.2 安装rpm构建工具链
KOS默认安装可能没有完整的rpm构建工具链,需要手动装上。
sudo dnf groupinstall -y "Development Tools" sudo dnf install -y rpm-build rpmdevtools createrepo rpmdev-setuptreerpmdev-setuptree会在当前用户家目录创建标准构建目录结构:~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}。每个目录都有明确职责:SOURCES放源码压缩包和补丁,SPECS放spec文件,BUILD是构建过程的工作目录,RPMS输出二进制包,SRPMS输出源包。
有人可能觉得logwatch是纯脚本应用,不需要装“Development Tools”这种重型工具组。但从我的实操经验看,装全编译工具链更稳。原因有两层:第一,spec文件里可能有附带perl模块的编译操作,需要gcc;第二,后续想在这个构建机上适配其他软件时,工具链现成,不用重复安装。反正构建机不对外提供服务,多装一点无妨。
3.3 梳理Perl模块依赖
logwatch本体是Perl脚本,所以对Perl环境和特定模块有依赖。主模块包括日期解析相关的Date::Manip、Date::Format,还有邮件发送相关的Mail模块。在KOS里需要找到对应的包名。
dnf search perl-Date-Manip dnf search perl-Date-FormatKOS基于企业版Linux生态,包命名规则和上游基本一致。perl-Date-Manip对应Date::Manip模块,perl-Date-Format对应Date::Format。如果dnf源里这些包没有收录,就需要启用仓库补充源,或者用dnf provides 'perl(Date::Manip)'反查哪个包提供了这个模块。
这里多说一句,Perl模块包装名和模块名经常不完全一样。搜不到包的时候,用dnf provides比用dnf search更高效。比如dnf provides '*/Date/Manip.pm',直接按文件路径反查,命中率更高。
4. 完整编译流程:从src.rpm到可安装RPM
4.1 下载并解包src.rpm
构建的起点是拿到官方维护的src.rpm包。可以从上游rpm镜像的source目录下载,也可以从项目托管平台的release页面找。下载完成后先做校验,养成好习惯:
wget https://example.com/logwatch-7.3.6-55.src.rpm sha256sum logwatch-7.3.6-55.src.rpm校验值和官方公布的一致再继续。实际踩过坑,下载不完整时rpm命令会直接报错rpm: not an rpm package,白白浪费时间排查网络问题。
导入src.rpm的动作很简单:
cp logwatch-7.3.6-55.src.rpm ~/rpmbuild/SRPMS/ rpm -ivh ~/rpmbuild/SRPMS/logwatch-7.3.6-55.src.rpm执行后,~/rpmbuild/SOURCES/会出现源码包和补丁文件,~/rpmbuild/SPECS/出现logwatch.spec。有时候系统会提示package logwatch-7.3.6-55 is already installed,这是因为构建机上可能残留旧版本,用rpm -Uvh --force强制覆盖即可。
如果好奇src.rpm里面都有什么,可以用rpm2cpio logwatch-7.3.6-55.src.rpm | cpio -t列文件清单,再解包查看。
4.2 读懂并修改spec文件
打开spec文件,重点看几个关键段落。
Name: logwatch Version: 7.3.6 Release: 55%{?dist} BuildArch: noarch BuildRequires: perl(ExtUtils::MakeMaker) perl(Date::Manip) Requires: perl(Date::Manip) perl(Date::Format)第一处要改的是Release。原值55%{?dist}在企业版Linux上会带发行版标识,KOS上构建时会自动加上KOS相关的dist字段。为了区分自建产物,我在Release后面追加了.kos1,变成55%{?dist}.kos1,这样一眼能看出是什么环境下编译的,后续维护也方便。
第二处关注BuildArch。logwatch是纯脚本应用,保持noarch不动。这样产出的RPM包不绑定CPU架构,KOS的x86_64和aarch64机器都能装。
第三处是依赖声明。spec里的Requires会自动检查Perl模块是否存在,并且支持版本号约束。之前网上那个二进制包缺模块的问题,本质就是Requires没有覆盖完整。我们自己的构建可以保留上游的依赖声明,以当前KOS环境为准补全。
4.3 拉取编译依赖
spec文件准备好后,用dnf自动解析BuildRequires:
cd ~/rpmbuild/SPECS sudo dnf builddep -y logwatch.specdnf builddep会把spec里声明的BuildRequires逐个通过仓库解析并安装,省去手动找依赖的功夫。实测下来,KOS在线源里大部分包都能找到,但如果某个perl模块在默认源里没有,builddep会报Unable to find a match,这时候就得手动补装:
sudo dnf install -y perl-Date-Manip perl-Date-Format perl-MailTools手动补装的原则是缺什么装什么,不要一口气把能猜的包全装一遍。构建报错信息会明确告诉你是哪一行Perl代码加载哪个模块失败,按需补装最精准。
4.4 执行rpmbuild并处置构建异常
一切准备就绪,开始正式构建:
rpmbuild -ba SPECS/logwatch.spec-ba的意思是Build All,同时构建二进制包和源包。构建过程会依次执行spec里的%prep解包打补丁、%build编译配置、%install安装到临时目录、生成RPM元信息、打包归档。如果一切顺利,~/rpmbuild/RPMS/noarch/下会出现logwatch-7.3.6-55*.noarch.rpm,~/rpmbuild/SRPMS/下会出现新的src.rpm。
构建期最容易遇到的报错有几种:
error: Bad exit status from /var/tmp/rpm-tmp.xxxxx (%build)。这种报错信息本身不说明原因,后边跟着的才是重点。需要去/var/tmp/rpm-tmp.xxxxx文件里看实际执行了什么命令、哪一步返回了非零状态。Installed (but unpackaged) file(s) found。构建过程把文件装到了buildroot,但spec的%files段没有声明这些文件。解决办法是去%files段把缺失的文件路径补上。File must begin with "/"。%files里写了相对路径或者空行导致格式不对,检查文件列表每一项都必须是绝对路径。
遇到报错不要急着全量重新构建,用rpmbuild -bi只执行到安装阶段,或者rpmbuild -bc只执行到编译阶段,能大幅缩短调试循环。我在调试过程中用这个技巧,把一个构建问题从5分钟一次缩短到1分钟一次,效率提升很明显。
5. 安装配置与KOS生态接入
5.1 安装RPM并做功能验证
构建产物出来后,先在构建机本机安装验证:
sudo dnf install ~/rpmbuild/RPMS/noarch/logwatch-7.3.6-55*.noarch.rpm which logwatch logwatch --version确认命令能识别后,再跑一次手动生成日志报告:
logwatch --print --service sshd --range today这条命令会扫描今天的sshd日志,把结果直接打印到终端。如果输出为空,优先检查系统是否有/var/log/secure或/var/log/auth.log文件。KOS默认使用systemd的journald做日志采集,有些日志文件可能没有传统text文件。后续再细说这个问题。
5.2 core配置项逐一解读
logwatch安装后,全局配置文件位于/etc/logwatch/conf/logwatch.conf。如果没有这个文件,可以从/usr/share/logwatch/default.conf/logwatch.conf复制一份再改。默认配置可以直接跑,但生产环境建议至少调整下面几项。
MailTo = ops@example.com Range = yesterday Detail = Med Service = All Output = mail Format = text LogDir = /var/logMailTo指定报表收件人。Range定义日志范围,生产环境用yesterday最合适,每天报告前一天的完整日志。Detail控制报告详细程度,Low只给摘要,Med给主要细节,High给全部细节,建议从Med开始调。Service设为All表示扫描所有logwatch能识别的服务,也可以按需指定为Service = sshd, sudo, kernel-message。Output设为mail配合定时任务,就能每天自动发送报告。
有一点值得注意,Format = text或html。如果邮件客户端对HTML支持好,用html格式排版更清晰;如果只是纯文本监控,text更省空间。我实测KOS邮件环境下text格式最通用,不容易被邮件网关拦截。
5.3 接入cron与邮件投递
logwatch装完后系统一般会自动生成/etc/cron.daily/0logwatch定时脚本,这个脚本会读取配置并执行每日报告。需要确保crond服务在运行:
systemctl enable --now crond cat /etc/cron.daily/0logwatch定时任务本身不复杂,真正的坑在邮件投递上。KOS默认可能没有装MTA(邮件传输代理),logwatch发邮件会静默失败。测试邮件可以手动执行:
logwatch --mailto ops@example.com --service all --range yesterday --output mail --format text如果没收到邮件,先检查/var/log/maillog。用postfix做本地投递的话,先安装postfix:
sudo dnf install -y postfix sudo systemctl enable --now postfixpostfix默认只做本地投递,把邮件投递到本机用户的mailbox。如果想发到外部邮箱,需要额外配置smtp relay,这部分和logwatch本身无关,但在生产环境里绕不开。我一般会在postfix里配一个对外的relay地址,把日志邮件统一投到运维告警邮箱。
5.4 把RPM纳入本地仓库
单机安装RPM只是完成了第一步,真正有价值的做法是把构建产物放入本地仓库。这样更多KOS服务器无需拷贝包,一条dnf命令就能安装。
sudo mkdir -p /srv/repo/kos/base/x86_64 cp ~/rpmbuild/RPMS/noarch/logwatch-7.3.6-55*.noarch.rpm /srv/repo/kos/base/x86_64/ sudo createrepo /srv/repo/kos/base/x86_64/然后在客户端机器上写repo文件:
cat > /etc/yum.repos.d/kos-local.repo <<'EOF' [kos-local] name=KOS Local Repo baseurl=http://your-repo-server/srv/repo/kos/base/x86_64/ gpgcheck=0 enabled=1 EOF如果仓库只在单机使用,baseurl可以写成file:///srv/repo/kos/base/x86_64/。多机共享时用nginx或httpd把仓库目录暴露出去就行。本地仓库配合createrepo,是批量分发自建RPM最标准的方式。
需要留个心:如果仓库面向正式的严肃环境,建议用rpm --addsign给RPM做GPG签名,并把客户端repo的gpgcheck设为1。本地内网环境为了简单可以gpgcheck=0,但这个开关一旦放宽,RPM内容就完全靠仓库本身的安全来保证,风险自负。
6. 实战排错:6类高频问题一次说清
6.1 高频报错速查表
| 现象 | 可能原因 | 处理建议 |
|---|---|---|
| dnf builddep找不到依赖 | 默认源缺少perl包装包 | 用dnf provides反查或用补充源安装 |
| rpmbuild报Bad exit status | %build阶段某个命令返回非零 | 查看/var/tmp/rpm-tmp.*脚本定位具体命令 |
| Can't locate Date/Manip.pm in @INC | 缺少perl-Date-Manip模块 | dnf install perl-Date-Manip |
| /usr/bin/env: 'perl': No such file | 系统没有装Perl | dnf install perl |
| logwatch --print无输出 | 指定服务的日志文件不存在 | 检查/var/log下对应服务日志 |
| 邮件报表收不到 | MTA未配置或MailTo写错 | 查看/var/log/maillog,配置postfix |
6.2 一个典型编译失败案例复盘
我在KOS上第一次跑rpmbuild -ba的时候,报错出现在%build阶段。错误信息很长,核心是Can't locate Date/Manip.pm in @INC。这个错误说明系统Perl环境里没有Date::Manip模块,而spec的BuildRequires声明的依赖没有被正确解析。
排查流程是这样的:先看dnf builddep是否完整执行,发现执行到一半有包找不到被跳过;再dnf provides '*/Date/Manip.pm'确认包名,补齐后重新builddep,问题解决。这个案例很有代表性,很多“编译失败”本质上是依赖没有装全,而不是代码本身有问题。构建报错信息里如果出现Can't locate,十有八九是缺Perl模块,按需安装最有效。
6.3 运行期日志源与邮件投递问题
logwatch正常安装后,另一个容易踩的坑是日志文件不存在。KOS使用journald采集系统日志,默认不一定会生成传统文本日志文件。logwatch默认从/var/log目录读取文本日志,如果对应服务的日志没有落盘,报告就是空的。
解决办法是在logwatch自定义脚本层面做适配。比如为某个服务写一个自定义脚本,用journalctl从journald拉取日志再格式化成logwatch能识别的文本流。具体可以在/etc/logwatch/scripts/services/下新建脚本文件,并在/etc/logwatch/conf/services/下加入对应配置项。这个能力是logwatch比较灵活的体现,遇到日志源差异时不需要改核心代码,只需要适配数据来源。
邮件投递的排查也同样明确。先确认logwatch --print有内容输出,再查邮件。如果mail命令可用,直接mail查看本地mailbox;如果记录在/var/log/maillog里显示status=sent但收件人没收到,那是外部smtp relay或邮件网关的问题,跟logwatch本身无关。
6.4 自定义服务脚本的扩展思路
生产环境里总会遇到logwatch内置脚本覆盖不到的应用日志。我曾经给一个内部应用写过一个自定义日志脚本:在/etc/logwatch/scripts/services/myapp目录下写解析脚本,在/etc/logwatch/conf/services/myapp.conf里声明日志路径和输出级别。加入之后,logwatch的Service = All会自动识别这个新服务,报告里就会出现对应分类。
这个机制的价值在于,logwatch不是一个封闭工具,它对“新日志类型”的扩展成本很低。把自定义脚本和配置做成RPM的一部分,还能随logwatch一起批量部署到所有KOS节点。适配到这一步,基本算是把logwatch从“可以用”变成了“好用”。
整个适配过程做下来,我最大的体会是:KOS环境下的软件适配并没有多神秘,关键是把构建配方(spec)和系统依赖这两件事处理好。不要图省事用make install,也别看到一个二进制包就想直接装,花点时间把src.rpm重新构建成原生RPM,后续的安装、分发、升级才能进入正轨。另外一个额外收获是我把本地仓库也顺手搭起来了,以后在KOS上适配的任何一个自建RPM都会丢进去,组里的其他机器再也不用靠拷包过日子。这套流程虽然是以logwatch为例,但对其他脚本类工具的KOS适配同样适用,你可以当作一套模板保存下来。