资讯详情

Linux启动与systemd服务控制:从GRUB到排障实战

📅 2026/10/13 3:54:52 | 华诺云谱 👁 阅读
Linux启动与systemd服务控制:从GRUB到排障实战
从按下电源键到屏幕上出现登录提示符中间那段时间看起来平平无奇但 Linux 系统其实已经完成了一整套“接力赛”。每个环节都有自己的职责任何一个环节掉链子系统就进不去。这篇文章不打算照抄手册我想以实际运维的视角把 Linux 引导过程和服务控制这整条链路拆开揉碎讲清楚每一步在干什么、为什么这么设计以及你在排障和日常管理时真正用得上的实操经验。不管你是刚接触 Linux 的新手还是已经被 systemd 折磨过几次的运维这篇文章都能给你一些参考。1. 引导过程到底在引导什么1.1 从按下电源键到内核接管的一段旅程很多人把“引导”理解成“开机”这其实不够准确。引导的本质是一系列“接力”动作硬件初始化完成后把控制权从一个程序交给下一个程序最终交给操作系统内核。整个过程可以分成几个关键阶段第一阶段是电源按下后的固件启动。传统 BIOS 或现代 UEFI 会先做上电自检POST检查内存、CPU、磁盘等基础硬件是否正常。自检结束后固件会按照启动顺序查找可引导设备——可能是本地硬盘、U 盘也可能是网络启动。这个阶段的细节平时不需要太关心但有个概念值得记住BIOS 和 UEFI 的区别不只是“能不能用鼠标”UEFI 支持 GPT 分区、安全启动引导加载程序存放的位置也不同。传统 BIOS 会读取硬盘主引导记录MBR里的引导代码而 UEFI 会直接去 EFI 系统分区ESP里找引导文件。第二阶段是引导加载程序登场。无论是 GRUB 2 还是其他引导器它的任务是加载内核映像和初始化内存盘initramfs并把控制权交给内核。GRUB 2 的配置学过 Linux 的人应该不陌生/etc/default/grub里写着默认启动项、等待时间、内核参数这些选项修改后需要执行grub2-mkconfig或update-grub重新生成配置。这个细节后面专门讲。第三阶段是内核初始化。内核被加载到内存后会先做一大堆硬件探测和设备初始化工作挂载根文件系统。这里有个关键点早期内核并不一定具备直接加载根文件系统的能力因为根文件系统可能位于各种类型的设备上——SCSI 磁盘、NVMe 硬盘、LVM 逻辑卷、加密分区等而对应驱动不一定编进了内核本体。这时候就需要 initramfs 来兜底。第四阶段是内核启动第一个用户空间进程。传统 SysVinit 环境下是/sbin/init现代 Linux 发行版基本都换成了 systemd也就是 PID 为 1 的进程。内核把接力棒交给 systemd 后由它负责挂载剩余的目录、启动各种服务、加载系统配置最终进入一个可登录的状态。这一整条链路可以用一个类比来理解固件是“机场广播员”引导加载程序是“摆渡车”内核是“飞机”initramfs 是“备用工具箱”。广播员把人送到摆渡车摆渡车把乘客送到飞机前——如果飞机本身带不了所有行李就先用备用工具箱把必需设备装好等飞机真正起飞了再用完整行李。1.2 initramfs 到底是干什么的initramfs 可能是整个引导过程里最容易被忽略却又最容易出问题的环节。它是一个临时的内存文件系统通常以.img或.cpio.gz形式存放在/boot目录下。内核启动早期会把它解压到内存中并运行里面的/init脚本完成以下任务加载必要的存储驱动比如 USB 磁盘驱动、NVMe 驱动、文件系统驱动激活 LVM 或 MD 软 RAID处理磁盘加密比如 LUKS等待用户输入密码真正挂载根文件系统然后把根目录切换switch_root到真实环境。如果你在系统启动时碰到过“无法挂载根文件系统”或者卡死在“Reached target Waiting for udev events”这类提示十有八九是 initramfs 里缺少对应驱动或者根文件系统参数传错了。重建 initramfs 的命令需要记住在 Red Hat 系发行版CentOS、Rocky、Fedora上是dracut -f /boot/initramfs-$(uname -r).img $(uname -r)在 Debian/Ubuntu 系发行版上是update-initramfs -u -k $(uname -r)重建 initramfs 的场景很多更换了主板导致磁盘控制器变化、从 IDE 改成 AHCI、给内核增加了模块依赖、调整了根文件系统类型等。每次更新内核时包管理器本身也会自动重建 initramfs但你手动改过/etc/default/grub里的 root 参数后建议主动重建一次。2. 引导加载器GRUB 2 的实战理解2.1 配置文件其实是可以改的很多人对 GRUB 2 的认知停留在“开机时按上下键选内核”但它的配置体系比老式 GRUB 复杂一些因为它是“动态生成”的。传统 GRUB 的menu.lst是手写的改完直接生效GRUB 2 把用户可编辑的变量放在/etc/default/grub把脚本片段放在/etc/grub.d/目录真正给引导器读取的配置文件是/boot/grub2/grub.cfgRed Hat 系或/boot/grub/grub.cfgDebian/Ubuntu 系。也就是说你直接编辑grub.cfg也可以但下一次执行配置生成命令时改动会被覆盖。正确的改法是vim /etc/default/grub比如你要修改默认等待时间把GRUB_TIMEOUT5改成GRUB_TIMEOUT3要修改内核启动参数把GRUB_CMDLINE_LINUX那行的引号里追加参数。改完之后执行Red Hat 系grub2-mkconfig -o /boot/grub2/grub.cfgDebian/Ubuntu 系update-grub这两个命令做的事情本质上是一样的——读取/etc/default/grub和/etc/grub.d/里的脚本生成新的grub.cfg。我自己第一次做这件事时犯过一个低级错误在 CentOS 7 上执行了grub2-mkconfig但没带-o参数结果只把配置打印在终端上什么都没写入。后来养成了习惯生成后顺手用grub2-editenv list看一下当前默认启动项确认配置真的生效了。2.2 常见改法和坑先讲一个几乎每个人都会碰到的需求临时修改启动参数排查问题。开机进入 GRUB 界面时选中你要启动的内核按e键进入编辑模式找到以linux开头的那一行在末尾追加参数比如单用户模式实际上在 systemd 时代更常用的做法是在这行末尾加systemd.unitrescue.target或rd.break然后按Ctrlx或F10启动。这种修改是一次性的不会写进配置文件非常适合临时排障。再讲一个“坑”改错 GRUB 配置文件导致系统无法启动。这种情况通常发生在你给/etc/default/grub加了不存在的内核参数或者把根分区设备写错之后。如果 GRUB 界面还能出来修复起来不难进入任意一个可用的内核启动项按e编辑把linux行里的root参数改成正确的设备路径再启动。如果 GRUB 界面都进不去那就需要用安装光盘或 Live CD 进救援模式把原系统的根分区挂载起来然后 chroot 进去重新生成引导配置。我把常见 GRUB 相关场景整理成了一张速查表场景操作修改默认等待时间改/etc/default/grub里GRUB_TIMEOUT重新生成配置给内核添加参数如屏蔽某个驱动改GRUB_CMDLINE_LINUX重新生成配置开机临时进入救援模式按e编辑启动项在linux行追加systemd.unitrescue.target开机临时以 debug shell 模式启动在linux行追加rd.break忘记 root 密码无法进入系统在linux行追加rd.break进入 shell 后重置密码从非默认的内核启动用grub2-set-default指定序号或改/etc/default/grub里GRUB_DEFAULT注意rd.break是 dracut 提供的中断方式进入的是 initramfs 环境根目录还没真正切换需要手动mount -o remount,rw /sysroot再 chroot 进去操作。Debian/Ubuntu 系的 initramfs 机制不太一样多数情况下用breakpremount或直接选救援模式更稳妥。3. systemd 接管之后初始化与服务控制3.1 从 SysVinit 到 systemd 的变化如果你用过早期的 CentOS 6 或 Debian 7应该对 SysVinit 的启动方式和/etc/rc.d/rc3.d底下那些SXXname软链接有印象。SysVinit 的思路是“按顺序执行启动脚本”依赖关系靠脚本编号来约定启动速度快不起来因为串行执行且不稳定。systemd 的核心设计目标是并行启动和依赖管理。它不再用 shell 脚本串起整个启动流程而是把每个可管理的对象抽象成“单元”Unit比如服务是.service、挂载点是.mount、设备是.device、套接字是.socket、目标状态是.target。每个单元都有独立的单元文件里面声明了依赖关系、启动命令、重启策略等。比如说一个服务依赖网络可用可以在它的单元文件里写[Unit] DescriptionExample Service Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple ExecStart/usr/local/bin/example-server [Install] WantedBymulti-user.targetAfter和Wants这两行表达的意思是“尽量在网络可用之后启动我”。systemd 会根据这些声明构建依赖图在不破坏依赖关系的前提下尽可能并行启动互不依赖的服务。这也是为什么 systemd 启动速度比 SysVinit 快很多——它不是在跑一列火车而是在跑一张有约束的网络。你可能注意到单元文件里有多个“target”字样比如multi-user.target。target 可以理解为一组单元的集合类似 SysVinit 里的运行级别。multi-user.target大致对应传统 runlevel 3多用户字符界面graphical.target对应 runlevel 5图形界面。3.2 运行级别与 target 的对应关系很多老运维习惯了init 3、init 5这种切换方式在 systemd 环境下会觉得不太适应。实际上 systemd 为了兼容旧习惯保留了对运行级别的映射关系但更推荐的做法是直接用 target。下面是常见对应关系SysVinit 运行级别systemd target说明0runlevel0.target / poweroff.target关机1runlevel1.target / rescue.target单用户救援模式2runlevel2.target / multi-user.target多用户Red Hat 系传统上表示无网络多用户3runlevel3.target / multi-user.target完整多用户字符界面4runlevel4.target / multi-user.target通常等同于 runlevel35runlevel5.target / graphical.target图形界面6runlevel6.target / reboot.target重启查看当前默认 targetsystemctl get-default修改默认 target比如开机直接进入字符界面systemctl set-default multi-user.target临时切换systemctl isolate multi-user.target注意isolate会停止当前 target 中所有不在新 target 依赖树里的单元跟init 3的行为类似。日常操作中把“运行级别”这个概念重新理解成“启动目标集合”很多困惑就能解开。举个例子你systemctl set-default graphical.target之后重启发现系统仍然停在字符界面原因可能是图形界面服务没装或 display manager 服务挂了而不是 target 没生效。排查时要看systemctl status graphical.target以及对应的 display-manager 服务状态。4. systemctl 服务控制实操4.1 常用命令一览与实例systemctl 的核心用法不难难在“什么场景用什么命令”以及“为什么某个命令不生效”。我把常用操作整理成表格按使用频率排了个序操作命令说明查看服务状态systemctl status 服务名最常用也最值得细看启动服务systemctl start 服务名立即启动不设置开机自启停止服务systemctl stop 服务名立即停止重启服务systemctl restart 服务名先停后起重新加载配置systemctl reload 服务名平滑重载不中断服务设置开机自启systemctl enable 服务名创建符号链接取消开机自启systemctl disable 服务名移除符号链接查看服务是否开机自启systemctl is-enabled 服务名输出 enabled 或 disabled查看当前所有已加载服务systemctl list-units --typeservice全面了解系统服务状态实际排障时systemctl status的输出信息量很大最常见的一种情况是服务启动失败。我用 Nginx 举例systemctl status nginx输出里会显示 Active 行的状态比如failed还会附带最近几条日志。如果这几条日志不够定位问题执行journalctl -u nginx --no-pager -n 50-u指定服务名-n 50表示最近 50 条日志--no-pager表示直接输出不分页。这是排查服务问题的第一板斧。再补充一个容易踩坑的细节systemctl restart和systemctl reload的区别。restart 是进程级别的重启连接会断开适合配置文件的改动比较大、无法在线生效的场景reload 是发给进程一个信号通常是 SIGHUP让进程重新读取配置文件连接通常不会中断适合 Nginx、Apache 这类支持平滑重载的服务。如果配置写错reload 也可能导致服务异常因此操作前先用nginx -t或类似命令做配置语法检查会更稳妥。4.2 服务开机自启的正确姿势新手最容易混淆的是start和enable这两个动作。start只影响“当前这一时刻”enable设置的是“开机之后”。现实中最常见的错误是手动用start把某个服务拉起来了但它没有 enable重启后服务又不见了。反过来只enable但不start会得到一个“开机时启动但现在还没跑”的服务。正确做法是两者都执行systemctl start 服务名 systemctl enable 服务名或者用一条命令systemctl enable --now 服务名--now等于同时执行 start 和 enable省一步操作。还有一类特殊服务需要注意带符号的模板服务。比如systemctl start foobar.service这种单元文件是foo.service后面的部分是实例名。比如网络管理里的dhcpdeth0.service就是给eth0接口单独启用的 DHCP 服务。管理这类服务时systemctl enable dhcpdeth0.service同样可以但要注意实例名必须匹配实际的接口或配置名否则启用了也起不来。万一遇到服务反复重启、根本稳不住的情况大概率是Restart策略导致的。比如单元文件里写了Restartalways进程一退出 systemd 就把它拉起来形成一个“崩溃重启”的死循环。查看日志时你会发现大量“Restarting”记录。这时候不要慌先看Restart的具体值如果是always配合快速崩溃的进程可以临时停止服务或者修改单元文件加上StartLimitIntervalSec0和StartLimitBurst0来取消重启次数限制但根治问题还是要看日志里具体的退出原因。提示修改单元文件后必须执行systemctl daemon-reload重新加载否则 systemd 还会用旧配置。这个命令不优雅但非常重要。我见过不止一次有人改完/etc/systemd/system/下的单元文件后直接 restart 服务结果 systemd 一脸茫然地用旧配置启动。5. 服务故障排查实录5.1 常见问题速查表排障过程是一个“缩小范围”的过程先看当前状态再看错误日志最后检查配置和依赖。这里把最常见的几类问题整理成速查表症状常见原因排查命令/方法服务启动失败状态为 failed配置语法错误、端口被占用、依赖服务未启动journalctl -u 服务名 -n 50看日志服务启动成功但立刻退出启动命令写错、工作目录不存在、权限不足用ExecStart的命令手动执行看报错服务显示 inactive (dead)服务进程主动退出或从未接受 start检查日志末尾确认主进程 exit code开机自启不生效未 enable或依赖的 target 不对systemctl is-enabled 服务名检查 WantedBy修改配置不生效忘记 reload / restart或改错了配置文件路径systemctl reload后systemctl status确认端口无法访问防火墙拦截 / 服务只监听在回环地址ss -lntp查看监听地址检查防火墙规则服务卡在 activating启动命令阻塞Type 设置错误检查Type是否与启动方式匹配关于Type这一项我单独解释一下因为这是个高频坑。单元文件里的Type默认值是simple表示ExecStart启动的那个进程本身就是服务主进程。但如果你的启动命令是一个 shell 脚本它可能 fork 了一个子进程作为真正服务进程父进程很快退出这种情况下simple类型的判断就会出问题。更常见的是Typeforking要求ExecStart启动的进程会 fork 出子进程后父进程退出配合PIDFile指定子进程的 PID 文件。这几个字段配置错了systemd 对“服务是否还在运行”的判断就不可靠就会出现“服务明明在跑systemctl status 却显示 dead”的怪象。5.2 独家排查技巧技巧一不只盯着服务日志也要看内核日志。很多服务起不来根本原因是底层硬件或内核模块的问题比如网卡驱动加载失败导致网络服务无法启动。这时候journalctl -k或dmesg -T能帮你发现内核层面的报错。我曾经排查过一个某服务反复重启的问题服务日志里啥都没有后来看了一眼内核日志发现是内存相关模块加载失败导致的进程崩溃。这种跨层问题只盯一层很难定位。技巧二学会用手工方式验证启动命令。假如某服务起不来别急着改配置先把单元文件里的ExecStart那行命令复制到终端手动执行。这一步能一次性排除很多因素命令写错、可执行文件不存在、权限不足、依赖的目录没有就位、环境变量缺失等。比如ExecStart/usr/bin/python3 /opt/myapp/server.py你在终端直接跑/usr/bin/python3 /opt/myapp/server.py如果它报“ModuleNotFoundError”那就直接看 Python 环境问题跟 systemd 没关系。技巧三关注journalctl的时间关联。系统启动时各服务几乎是并行起来的如果你发现 A 服务和 B 服务之间总是存在启动顺序冲突光看它们各自的日志不一定看得出来。这时候执行journalctl --since 2024-01-15 09:00:00 --until 2024-01-15 09:05:00把时间窗口拉开按时间顺序看整个系统的日志流能看到 A 服务在什么时候启动、B 服务什么时候报错、中间有没有其他服务抢占资源。有一次我在一台某云主机上排查某服务启动慢的问题就是通过时间窗口日志发现是systemd-tmpfiles-setup.service耗时特别长导致后续依赖它的服务整体延迟了。技巧四利用systemd-analyze分析启动耗时和依赖链。systemd-analyze是常被忽略但非常强力的工具systemd-analyze time systemd-analyze blame systemd-analyze critical-chaintime显示总时间和各阶段耗时blame按耗时从高到低列出每个服务单元的启动时间占用critical-chain显示系统的关键依赖链条告诉你哪条链路上哪个环节最耗时间。优化开机速度时这三条命令是必看的。6. 调试与定制引导过程的经验6.1 修复引导的实战套路引导出问题的情况千奇百怪但修复套路是相对固定的。我把最常见的“系统重启后停在 GRUB 提示符”场景走一遍这种情况通常是 GRUB 找不到配置文件或内核映像。在 GRUB 命令行界面你需要手动告诉 GRUB 内核和 initramfs 在哪里。先执行ls列出 GRUB 能识别到的硬盘和分区比如(hd0,gpt1)、(hd0,gpt2)等。不确定根分区在哪可以用ls (hd0,gpt1)/ ls (hd0,gpt2)/逐个查看分区内容找到包含/boot/vmlinuz-*文件的分区。假设你在(hd0,gpt2)的/boot目录下看到了内核文件接下来的核心步骤依次是set root(hd0,gpt2) linux /boot/vmlinuz-$(uname 的内核版本) root/dev/sdaX initrd /boot/initramfs-$(内核版本).img boot这里的root/dev/sdaX要替换成你实际根分区的设备路径。如果你不确定可以用search命令自动查找search --no-floppy --setroot --label系统根分区的卷标这种手动引导方式只是临时起一个系统。进入系统后第一件事是重新生成 GRUB 配置grub2-mkconfig -o /boot/grub2/grub.cfg如果不确定该往哪个磁盘安装引导程序可以执行grub2-install /dev/sda这里要注意/dev/sda是磁盘设备本身不是分区不是/dev/sda1。MBR 引导程序需要安装到磁盘开头区域而不是分区里。6.2 定制引导与增强可维护性的建议定制引导不只是为了进系统更多是为了让系统在“起不来”的时候能自救。建议一给 GRUB 设置一个较低的超时时间但不设为零。GRUB_TIMEOUT0虽然看起来启动更快但排障时想进救援模式都没机会。设成 3 秒平时多等三秒关键时刻省下大量抢救时间。建议二不要删除旧内核。很多运维为了省磁盘空间把旧内核包卸载了但新内核如果有 bug 或驱动不兼容你会被卡在 GRUB 界面干瞪眼。保留至少一个上一个版本的内核就是给系统留了条后路。建议三利用 BLSBoot Loader Specification风格配置。现代 Fedora、RHEL 9 和部分其他发行版把 GRUB 菜单项拆成了独立的/boot/loader/entries/*.conf文件每次安装内核时自动生成。这种设计的好处是删内核时不会再出现“grub 配置文件残留错误条目”的经典问题。如果你还在用老式grub.cfg单文件方式升级内核后记得顺手看一眼配置生成日志。建议四把systemd-analyze纳入系统初始化后的检查清单。我每次给客户交付一台新服务器都会先跑一遍systemd-analyze time systemd-analyze critical-chain如果看到某条链路异常臃肿比如某个服务等待时间过长趁系统还没正式上线就把它揪出来处理比上线后再背锅要舒服得多。最后再分享一个小技巧排查引导问题时GRUB 菜单里通常有多个内核条目老的救援模式rescue内核也值得保留。有些环境的救援内核带了更完整的基础驱动和额外工具进入救援模式后可以直接挂载根分区、修改配置、重新生成 initramfs比用 Live CD 方便。每次内核升级时顺手看一眼分区空间避免/boot爆满导致新内核装不上这算是我踩过若干次坑后总结出来的实际经验了。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑