ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux软件包管理与systemd服务管理实战总结(14天学习笔记)

Linux软件包管理与systemd服务管理实战总结(14天学习笔记) 学了半个多月Linux到今天第十四天终于敢说自己对“装软件”和“管服务”这两件事有点底气了。前面十几天基本都在跟命令、文件、权限、进程这些基础概念打交道说白了都是单点操作今天开始碰系统里最日常、也最容易出问题的两块内容软件包管理和服务管理。这篇文章就当给自己做一份学习版总结也希望能给正在走同一条路的人一点参考。我当前的学习环境是一台2核4G的虚拟机装的是主流的RHEL系发行版全程用终端操作没有装图形界面。选择RHEL系纯粹是因为单位生产环境基本都是这个体系早一天熟悉早一天上手。今天主要实践了yum源配置、rpm与yum命令互操作、编译安装的取舍以及systemd服务单元的全流程管理。这几个技能点不仅是日常运维的刚需也是后面学自动化、学容器编排的地基。1. 软件包管理为什么第十四天一定要啃这块硬骨头1.1 RPM、YUM、DNF到底是什么关系很多初学者看到rpm、yum、dnf几个命令就直接懵了我一开始也是。今天实际反复用过之后总算把三者关系理顺了。把系统比作一个房子软件包就是你要搬进来的家具。rpm命令是“人工搬家具”你拿到一个.rpm文件手动把它安装到系统里。它能干活但有个致命弱点不会主动帮你解决家具之间的配套问题。你装A家具A需要B家具当底座rpm只会告诉你“缺B”然后就不管了。这就是所谓的依赖关系处理。yum则是“智能搬运工”它知道每个家具需要什么配件并且会先帮你把配件准备好再安装主件。yum背后有一个软件仓库仓库里预先整理好了成千上万个软件包以及它们之间的依赖关系数据。所以你执行一条yum install它能把所有需要的包一次性装好。dnf是新一代的yum可以理解为同一个东西的增强版主要在依赖解析算法和性能上做了优化。我们系统里现在直接敲yum命令底层实际上就是dnf在工作。新手没必要纠结用哪个记住一句话优先使用yum只有拿到单独的.rpm安装包时才用rpm。1.2 从Windows习惯过渡到Linux装软件思维Windows下装软件是下载一个install.exe双击一路下一步就完事了。Linux完全不是这个逻辑刚切换过来的人会觉得很不适应。Linux下装软件的途径可以概括为三种。第一种是yum安装适合绝大多数常用软件一条命令搞定依赖自动处理这是首选。第二种是rpm直接安装适合离线的.rpm包但依赖需要自己操心。第三种是源码编译安装适合需要定制功能或官方未提供现成包的特殊软件流程是./configure、make、make install三步走自由度最高也最容易踩坑。今天我把三种途径都各试了一遍。实际操作下来yum安装最无脑rpm安装最考验对依赖的理解源码编译则像一次小型开发过程耗时和变数都大。对第十四天的学习阶段来说yum必须熟练rpm要会用源码编译至少知道流程和原理这就够了。别想着一天吃成胖子后面很多天还会反复跟这些命令打交道。2. 配置软件源一切安装工作的地基2.1 搭建本地YUM源实操软件源就是一串告诉yum“去哪里下载软件包”的地址配置。今天的第一个实操就是搭建本地yum源因为我们的虚拟机处于内网环境外网访问不通畅而本地镜像光盘里正好有整套软件包这是最快、也最稳定的一种源。准备工作很简单把安装镜像ISO挂载到系统上。我的做法是在虚拟机设置里把ISO文件关联到CD/DVD光驱然后在终端里执行mount操作。挂载完成后iso里的内容会出现在一个目录下通常是/run/media/root/目录名或者/mnt下的自定义目录。我在/media下创建了一个iso目录作为挂载点。挂载后的目录里有个repodata目录这是整个仓库的关键所在里面存放着所有软件包的元数据和依赖关系索引。yum能不能正常工作就看这个目录存不存在。如果挂载的目录里没有repodata说明这个ISO不适合直接当yum源或者镜像版本太特殊。然后我在/etc/yum.repos.d/目录下新建了一个本地源配置文件名字叫local.repo内容大概是下面这样[local] nameLocal Repository baseurlfile:///media/cdrom enabled1 gpgcheck0这里有几个字段要说明一下。方括号里的local是仓库标识必须全局唯一。name字段是仓库描述性名称随便写。baseurl就是仓库地址file://表示本地文件路径。enabled1表示启用这个仓库gpgcheck0表示不对软件包做GPG签名校验内网环境为了省事可以这样配置但公网环境建议保持gpgcheck1并配置好公钥。配置完成后建议先缓存清理一下yum clean all yum makecache测试源是否可用最直接的方法是随便装个小软件比如执行yum install -y tree如果顺利安装成功说明本地源完全可用。我第一次配置时忘了关闭系统自带的网络源配置两个源同时启用结果yum在解析时出现了耗时较长的问题后来把默认源配置文件全部移走后一切正常。建议新手在实践本地源时先临时改动或者移走那些自带的源配置文件只保留自己这一个新的避免干扰。2.2 网络源与官方源的选择取舍离线练习结束之后我又恢复了网络环境对比了一下本地源和网络源的实际差异。网络源的好处是软件包版本更新、选择面广而且能自动获取最新的安全补丁。缺点是依赖公网的稳定性如果公司网络有防火墙限制yum很容易卡在连接超时上。用网络源时我记得执行过一次yum install nginx结果提示要下载依赖包数量和总大小会先列出来然后问我是否确认。这个过程看似简单背后其实请求了远程仓库的元数据来做依赖解析。如果你所在环境网络波动大yum makecache阶段就可能会卡很久这时候可以把仓库配置里的超时时间加大一点或者干脆像前面那样切到本地源。选择建议其实不难内网环境优先本地源或者公司内部搭建的镜像源公网环境优先官方源但要注意设置gpgcheck1。对于学习阶段两种源都应该亲手配一遍只有体会过本地源那种“秒装”的感觉再对比网络源的速度才会真正理解软件源配置在生产环境里的重要性。3. 高频命令实操拿着终端就像拿着工具箱3.1 rpm命令的增删查与细节坑rpm命令虽然日常用得比yum少但一旦要用就是必须精准的场景比如离线排查问题、验证某个包是否已安装、提取某个包里的配置文件等等。我今天重点练习了rpm的查询功能这是日常工作里最常用的。rpm -q是查询指定包是否安装格式是rpm -q 包名比如rpm -q vim-enhanced如果已安装会返回完整的包名和版本信息未安装则会提示not installed。rpm -qa是列出所有已安装的包数量多到惊人建议加上管道配合grep过滤用比如rpm -qa | grep nginx。rpm -ql是列出某个已安装包的所有文件列表这个在看软件到底安装了哪些内容时特别有用。rpm -qf是反向查询比如你看到一个配置文件但不知道属于哪个包直接rpm -qf /etc/nginx/nginx.conf就能查出来。安装单独的.rpm文件用rpm -ivh 包名.rpm升级是rpm -Uvh卸载是rpm -e 包名。这里有个细节坑rpm卸载只接受包名不接受文件名例如rpm -e nginx-1.20.1.rpm这种写法是错的正确写法是rpm -e nginx。我开始时就因为记错这个走了弯路花了几分钟才反应过来。另一个要记住的是rpm安装时的-vh参数v表示显示详细过程h表示显示进度条不加也能装但输出只有一行出了问题不好判断卡在哪。rpm还有校验功能rpm -V如果包的文件被改动过会输出提示做安全排查时很实用。今天我没有深入这块但知道有这个东西后期再做安全加固时是必考项。3.2 yum命令组合安装、分组、历史回滚yum命令表面看就一个install实际上它有一整套组合玩法。今天我把常用的都过了一遍其中几个值得重点说。首先是安装与卸载。yum install -y 包名和yum remove -y 包名是最基础的。这里的-y表示自动应答yes否则每个装包确认都会问你一遍尤其是依赖多的时候特别烦人。卸载时要注意yum remove会把依赖这个包的其他包也一并删掉所以生产环境卸载前要看清提示列出的受影响包列表。yum search 关键词用于在仓库中查找模糊匹配的软件包不知道确切包名时的第一选择。yum provides 文件名则是按文件反查包名比如你执行某个命令提示找不到文件可以用yum provides */该文件名来定位属于哪个包。这一招我实操时用过一次解决了一个“明明装了某个软件但提示缺库文件”的疑惑实际上缺的是另一个依赖包。分组安装是yum的一个特色功能。yum grouplist能列出所有软件组比如“Development Tools”“Security Tools”等。yum groupinstall “组名”可以一次性安装一整组软件。我测试时安装了一组开发工具一下就装好了几十个包省去了逐个安装的麻烦。注意组名通常带空格必须用引号包裹。yum history和yum history undo是回滚功能。今天模拟了一个场景先安装了一个包接着又把它卸载了再用yum history查看事务记录最终用yum history undo 事务编号把卸载动作撤销。这个功能在处理“我到底刚才做了什么”的后悔场景时特别好用。yum历史就像操作日志跟shell history不同它记录的是完整的包管理事务包括安装了哪些依赖改动过哪些文件适合出问题后做溯源。4. systemd服务管理学了才能理解“启动”这件事4.1 服务单元文件的结构与语法刚开始学Linux时看到的“服务”是个特别抽象的词。其实把服务理解为“一个常驻后台运行的程序”就行了比如nginx是网页服务sshd是远程登录服务。systemd负责管理这些服务它接管了启动、停止、重启、开机自启等一系列工作。systemd管理每个服务靠的是服务单元文件这些文件以.service结尾通常存放在/usr/lib/systemd/system/目录下这是系统自带服务单元的地方。用户自定义的服务可以放到/etc/systemd/system/目录这个目录优先级更高而且不应该随便改动系统自带的文件自定义的内容放到这里就对了。今天我自己编写了一个极简服务单元内容大概如下[Unit] DescriptionMy Test Service Afternetwork.target [Service] Typesimple ExecStart/usr/bin/sleep 500 [Install] WantedBymulti-user.target[Unit]区块里的Description是服务描述After表示这个服务要在网络服务之后启动这是一种依赖声明但不等于强依赖只是顺序保证。[Service]区块里的Typesimple是默认类型表示ExecStart启动的程序就是主程序直接前台运行。如果程序会自行守护并后台化则可能要设置Typeforking。ExecStart指定启动命令这里我用sleep命令模拟一个常驻进程。[Install]区块里的WantedBymulti-user.target表示这个服务在系统进入多用户模式时被启用本质就是控制开机自启的挂载点。编写完服务单元后执行systemctl daemon-reload重新加载配置然后systemctl start 服务名就能启动。如果改过ExecStart等重要字段但不执行daemon-reload启动时用的还是内存里的旧配置这个坑我在实操时踩过改了文件后发现服务没按预期执行排查了半天才发现是配置没重载。4.2 systemctl常用操作与开机自启逻辑systemctl是systemd的控制命令每天都会用。基础操作无非是start、stop、restart、status、enable、disable这几项配合起来已经能覆盖绝大多数需求。status输出里包含的信息很丰富我一般重点看几个字段loaded表示服务单元是否已加载active表示运行状态active (running)代表正常运行inactive (dead)代表已停止还有进程PID、内存占用、最近日志。启动失败时status给出的信息往往是第一手线索。今天有一次我故意把ExecStart命令路径写错结果status明确提示“Failed to start”后面跟着一行错误原因定位问题基本不用看别的日志。开机自启的逻辑要理解清楚。enable命令做的事情是把服务单元文件软链接到multi-user.target.wants目录下disabled则相反。systemctl is-enabled 服务名可以查询当前是否开机自启返回enabled或disabled。有个常见误解是把start和enable混为一谈start只是“现在运行”系统重启后不保证再运行enable是“每次开机都运行”。两者可以独立设置也常常配合使用。还有一个组合操作systemctl enable --now 服务名它的含义是同时完成“开机自启”和“立即启动”一条命令干两件事非常高效。日常配置服务时我推荐直接使用这个组合形式省得先enable再start来回敲。服务重启后想确认是否真的起来了别只看systemctl status的结果我习惯再用ps或ss命令交叉验证端口和进程是否真实存在。今天我用nginx测试过systemctl restart nginx返回正常但用ss -lntp查看端口时发现进程起在了一个不同端口上仔细一看是配置文件里把监听端口改掉了服务的启动状态是真实的只是它启动后读了新的配置。这类“服务正常但不符合预期”的场景只能靠交叉验证来发现。5. 实操中踩过的坑第14天最值钱的几段经历5.1 依赖地狱的几个典型解法依赖问题就是软件A依赖BB又依赖C环环相扣一旦仓库里找不到某个中间依赖安装就会失败。今天实操中遇到的最典型问题是yum install时报“Requires: libxxx.so.1()(64bit) 1.2.3”错误提示找不到某个共享库。遇到这类问题先不要慌也不要试图去网上乱下.so文件然后硬塞进系统这样做非常危险可能把系统搞崩溃。正确做法分几步走。第一步用yum provides “*/libxxx.so.1”这个语法查一下这个库由哪个包提供如果仓库里有直接安装那个包。第二步如果本地或当前仓库搜不到可能是仓库源不全或版本不对尝试启用更多扩展仓库。第三步如果确属仓库里没有的定制库再考虑源码编译方式安装到/usr/local目录并且注意用ldconfig刷新动态链接库缓存。另一个容易踩的坑是i686和x86_64架构混淆比如64位系统装了32位包提示缺的库全是32位的安装依赖时又拉来一堆32位包系统会越装越乱。解决办法是装包前强制指定架构或者尽量保持所有软件包都是同一个架构系列。今天我一台小虚机上测试了交叉架构安装虽然最终能装上但总感觉会有隐患实际生产环境没人这么干。依赖问题的本质是仓库元数据不完整或源配置错误遇到后先在源层面找原因比就地解决报错更治本。5.2 服务启动失败时的三分法排查思路服务起不来是每个Linux学习者迟早都要面对的事今天至少碰到了三次好在通过整理出一套排查思路后面没再懵过。第一步看状态systemctl status 服务名关注错误行和Active状态。这一步能过滤掉大约一半的问题比如路径写错、权限不足这些错误信息都会直接显示出来。第二步看日志journalctl -u 服务名 -n 50查看该服务最近50行日志。日志里通常有更具体的报错原因比如端口被占用、配置文件语法错误。如果日志量太大可以加上--since 5 min ago限定时长。今天nginx启动失败就是通过日志发现listen端口被另一个服务占用了停掉那个服务后问题解决。这里补充一个小技巧端口占用排查可以用ss -lntp查看监听状态配合lsof -i:端口号定位占用进程两个命令组合一次就能查明白。第三步看权限和文件如果日志没有明确线索检查服务单元文件里ExecStart指向的命令是否存在、是否有执行权限、运行服务的用户对相关目录是否有读写权限。今天有一个服务起不来原因就是二进制文件存在的目录权限是700而服务运行用户没有访问权限日志只报了一个很泛的“Failed”加上对目录的ls检查才发现是权限问题。这套排查路径基本覆盖了大多数服务启动故障建议新手记录下来遇到问题时按顺序执行效率会明显提升。5.3 离线环境里的备选方案从本地RPM包到源码编译学习过程中可以花一点时间专门验证一下没有网络时的安装方案。我今天的最后一个实操是把一个常用软件包从一台联网机器上把.rpm文件全部下载下来拷贝到离线虚拟机上手动安装。下载一个包的依赖集合有两套思路。简洁的办法是用yumdownloader这个工具它可以只下载指定的rpm包而不安装。而要用yum下载一个包及其全部依赖更便捷的方式是使用yum install --downloadonly --downloaddir/tmp/pkg 包名不过这个玩法在不同版本的yum上参数略有差异我这次是在RHEL系上操作的用起来没问题。离线机器上执行rpm -ivh *.rpm时如果目录里的依赖包齐全一般能装上。但顺序有讲究需要先装被依赖的包后装依赖它的主包。这个顺序手动判断起来很吃力所以更推荐在目录里执行一条yum localinstall *.rpm让yum从本地目录自动解析依赖并安装省心很多。这个命令现在也可以直接用yum install ./包名.rpm的格式效果类似。源码编译这次我试了一个体积较小的工具包整个流程其实更适合后面单独花一天专门学习。今天只求一个整体感知./configure阶段负责环境检测和生成Makefilemake阶段调用编译器生成可执行文件make install把文件复制到系统目录。如果没有安装gcc等开发工具编译会直接报错所以源码编译前通常需要先把Development Tools这个软件组装上。6. 今天的收尾心得与下一步计划一天高强度操作下来最大的感受是Linux的知识点像一张网命令只是一个个节点真正有用的是节点之间的连线。软件包管理和服务管理这两块正好把前面学的文件系统、权限、进程给串起来了比如理解服务单元文件就需要文件权限知识排查服务日志就要用上文本处理命令而软件安装时包里文件的归属又逼着你去复习rpm -ql之类的查询。对正在学Linux的人我的建议很具体先把本地源和网络源各配一遍然后专门拿一台虚拟机反复安装卸载同一个软件再看它的依赖关系之后自己写一个简单的服务单元文件启动一个测试进程再故意改坏配置去排查。这套操作下来你会比死记一堆命令公式的学生强得多因为每个命令都对应着你亲手解决过的问题。第十四天就这么过完了。想清楚下一天可以往Shell脚本方向走把今天手动执行的一堆命令写成自动化脚本让系统替自己干活。学Linux最难的是坚持但每闯过一个坑后面会越来越有意思。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进