目录

一、引言:为什么要自己编译内核?

二、内核源码获取与准备

2.1 内核版本命名规则

2.2 下载内核源码

2.3 安装编译依赖

三、配置内核:make menuconfig

3.1 三种配置界面

3.2 以当前配置为起点

3.3 进入配置菜单

3.4 精简内核的核心思路

3.5 配置速查

四、编译与安装

4.1 编译内核

4.2 安装模块

4.3 安装内核

五、Grub引导配置

5.1 确认新内核已添加到启动菜单

5.2 暴露启动菜单(Ubuntu默认隐藏)

5.3 双内核启动策略(保底方案)

六、安全须知与回滚

6.1 不要删除正在运行的内核

6.2 启动失败的处理

6.3 内存和磁盘要求

七、本篇小结

动手练习

八、下篇预告


​​​​​​​一、引言:为什么要自己编译内核?

对于95%的Linux用户来说,发行版提供的内核已经足够好。但在某些场景下,自己编译内核是有实际价值的:

  • 精简与性能:通用内核为了支持从嵌入式设备到超级计算机的所有硬件,包含了数千个驱动模块。裁剪掉你不需要的部分,内核体积更小、启动更快、内存占用更低

  • 学习与研究:编译内核是理解Linux底层机制的入口——你会接触到进程调度器、内存管理、文件系统驱动、网络协议栈等底层子系统

  • 特定需求:启用发行版默认关闭的内核特性(如实时内核抢占、特定的安全模块),或者你的硬件需要最新的驱动支持

⚠️ 重要提醒:本文的练习必须在虚拟机中进行。在物理机或生产服务器上编译内核,一旦配置出错,可能导致系统无法启动。先创建虚拟机快照,再动手操作。

二、内核源码获取与准备

2.1 内核版本命名规则

Linux内核的版本号经历了两次命名规则变化:

bash

uname -r   # 查看当前内核版本

2.6时代(2003-2011):2.6.x.y——2.6.32.45中,32是主线版本,45是bug修复号。

3.x/4.x/5.x时代(2011-2024):当2.6的bug修复号积累到一定程度(2.6.39),Linus决定简化版本号,跳到3.0。之后大版本号每隔2-3年升级一次。

6.x时代(2024至今):版本号彻底变成“无特殊含义”的数字,纯粹是序号。6.x只是5.x之后的自然延续。

内核官网 kernel.org 提供以下几种版本类型:

版本类型标识说明
主线版(mainline)最新版本号Linus Torvalds亲自维护的开发主线
稳定版(stable)版本号主线稳定后转入的维护分支
长期支持版(longterm)标注LTS支持长达6年,生产环境使用(也是我们的选择)

建议:选择最新的longterm(LTS)版本。LTS版持续接收安全更新和关键bug修复,比最新的主线版本更稳定。

2.2 下载内核源码

bash

# 通过wget下载最新LTS源码(以6.12.13为例,请到kernel.org确认最新LTS版本)
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.13.tar.xz

# 解压
tar -xf linux-6.12.13.tar.xz
cd linux-6.12.13/

源码体积约1.5GB(解压后),确保至少有10GB可用空间(编译还会产生大量临时文件)。

2.3 安装编译依赖

bash

sudo apt update
sudo apt install -y \
    build-essential \
    flex bison \
    libssl-dev \
    libelf-dev \
    libncurses-dev \
    dwarves \
    bc

各依赖的作用:

  • build-essential:gcc、make等编译工具链

  • flex、bison:词法分析和语法分析工具

  • libssl-dev:内核模块签名

  • libelf-dev:ELF格式支持(内核模块和vmlinux)

  • libncurses-dev:make menuconfig的图形菜单界面

  • dwarves:生成BTF(BPF Type Format)调试信息,现代内核必需的依赖

  • bc:数学计算工具

三、配置内核:make menuconfig

3.1 三种配置界面

命令界面类型适用场景
make menuconfig终端菜单(ncurses)推荐,终端下直观易用
make config逐行问答极端情况,体验较差
make xconfigQt图形界面桌面环境下使用

3.2 以当前配置为起点

bash

# 复制当前系统的内核配置作为起点(免去从零开始的繁琐)
cp /boot/config-$(uname -r) .config

# 更新配置以适配新内核版本(自动处理新增/废弃的选项)
make olddefconfig

make olddefconfig的作用:以.config为基础,对于新内核中增加的配置项自动选择默认值,对于已废弃的选项自动忽略。这样可以省去手动回答大量新增选项的麻烦。

3.3 进入配置菜单

bash

make menuconfig

界面操作:

  • 方向键:移动光标

  • 空格:切换选项状态(*=编译进内核,M=编译为可加载模块,空=不编译)

  • ?:查看选项帮助

  • /:搜索配置项

  • Tab/Enter:切换和进入菜单

  • Esc:返回上层或退出

3.4 精简内核的核心思路

通用内核约80%的驱动和模块是多余的。按以下思路精简:

确认你自己的硬件:

bash

# CPU型号
cat /proc/cpuinfo | grep "model name" | head -1

# 网卡型号
lspci | grep -i ethernet
# 或
lspci | grep -i net

# 磁盘控制器
lspci | grep -i sata
lspci | grep -i nvme

# USB控制器
lspci | grep -i usb

# 文件系统使用情况
df -Th

在menuconfig中按硬件筛选:

  • Processor type and features → 选择你的CPU系列(如Intel/AMD),关闭不相关的微码更新,关闭无关的CPU特性

  • Device Drivers → 这是最大的精简空间。lspci列出的硬件才编译,其他的都可以关掉

  • File systems → 只选你实际使用的(通常是ext4和xfs),关掉reiserfs、jfs、几十种文件系统

  • Networking support → 网卡驱动只保留你的型号,其余全关

  • Kernel hacking → 生产环境全部关闭(调试选项会拖慢性能)

3.5 配置速查

如果不想深入每个菜单,在做完上述针对性精简后,还有一个原则:确保硬盘控制器驱动编译进内核(*而非M),否则内核启动时无法加载根文件系统而直接panic。可以先用虚拟机快照备份,然后大胆尝试——实践中踩过的坑往往印象最深。

四、编译与安装

4.1 编译内核

bash

# -j$(nproc) 使用所有CPU核心并行编译
make -j$(nproc)

这个过程通常需要30分钟到2小时,取决于你的CPU性能和精简程度。

4.2 安装模块

bash

sudo make modules_install

这一步将编译好的内核模块安装到/lib/modules/内核版本/目录下。

4.3 安装内核

bash

sudo make install

这一步执行三件事:

  1. 将内核镜像(bzImage)复制到/boot/

  2. 生成initramfs(初始RAM文件系统)

  3. 自动更新Grub引导菜单(添加新内核条目)

五、Grub引导配置

5.1 确认新内核已添加到启动菜单

bash

# 查看Grub配置文件中的内核条目
grep -E "^menuentry|submenu" /boot/grub/grub.cfg | grep -v recovery

你应该能看到新旧两个内核的条目。默认启动的是排在最前面的(通常是新安装的内核)。

5.2 暴露启动菜单(Ubuntu默认隐藏)

很多发行版默认隐藏Grub菜单,直接启动。修改配置让菜单显示出来,以便手动选择内核:

bash

sudo vim /etc/default/grub

修改以下几行:

ini

GRUB_TIMEOUT_STYLE=menu    # 显示菜单(不是hidden)
GRUB_TIMEOUT=5             # 菜单等待5秒
# GRUB_HIDDEN_TIMEOUT=0   # 注释掉这一行

更新Grub使配置生效:

bash

sudo update-grub           # Ubuntu/Debian
sudo grub2-mkconfig -o /boot/grub/grub.cfg   # CentOS/RHEL

5.3 双内核启动策略(保底方案)

Grub自动帮我们保留了旧内核——新内核启动失败时,重启后在Grub菜单中选择旧内核即可正常进入系统。这就是内核编译的“安全气囊”。

六、安全须知与回滚

6.1 不要删除正在运行的内核

bash

# 千万不要在运行着新内核时删除旧内核!
# 如果新内核出现问题,旧内核是你的救生圈。确认新内核稳定运行一周后再考虑清理

6.2 启动失败的处理

如果重启后新内核启动失败:

  1. 看到Grub菜单时,选择“Advanced options for Ubuntu”

  2. 选择旧的、能正常工作的内核版本启动

  3. 进入系统后,可以将有问题的内核卸载:

bash

dpkg --list | grep linux-image   # 找到有问题的内核包
sudo apt remove --purge linux-image-问题版本

6.3 内存和磁盘要求

  • 内存:编译消耗约2-3GB,剩余内存在4GB以上

  • 磁盘:预留10GB用于编译和安装

  • 时间:首次编译大约2小时(虚拟机上更慢),使用-j$(nproc)充分利用多核

七、本篇小结

内核编译流程:

text

下载源码 → 安装依赖 → 复制当前配置 → make olddefconfig → make menuconfig
→ make -j$(nproc) → sudo make modules_install → sudo make install
→ 修改Grub显示菜单 → 重启验证

三条安全法则:

  1. 虚拟机+快照:这是最安全的实验环境,搞崩了秒回滚

  2. 保留旧内核:Grub自动保留,新内核启动失败时它就是救生圈

  3. 理解再动手:不要为了“精简数字”盲目关闭不了解的选项

动手练习

bash

# 1. 查看当前内核版本和配置文件
uname -r
ls -lh /boot/config-$(uname -r)

# 2. 查看当前内核的模块数量(感受通用内核的"臃肿")
ls /lib/modules/$(uname -r)/kernel/ | wc -l

# 3. 在虚拟机中走一遍完整流程(核心练习)
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.13.tar.xz
tar -xf linux-6.12.13.tar.xz
cd linux-6.12.13
cp /boot/config-$(uname -r) .config
make olddefconfig
make menuconfig   # 探索一下菜单结构,不一定要改什么
# Ctrl+C 退出即可(如果不想真的编译)

八、下篇预告

内核编译让你看到了操作系统的“零件清单”。但你知道Linux是如何管理内存的吗?free -h看到的buff/cache到底是什么?为什么系统有时候会杀掉你的程序(OOM Killer)?

下一篇我们将深入Linux内存管理的核心机制——物理内存与虚拟内存的区别、Buffer与Cache的不同角色、Swap分区的真正作用。理解这些,你才能真正看懂free、vmstat的输出,在内存问题排查时做到心中有数。


延伸思考:你刚刚编译的内核配置中,有数千个选项被设置为m(编译为模块)。模块的优点是按需加载、节省初始内存,但被编译为模块加载需要额外时间。哪些驱动必须编译进内核(*)?答案是:启动过程中访问根文件系统所必需的驱动——磁盘控制器驱动和根文件系统驱动。如果它们被编译为模块,内核就需要“从磁盘加载磁盘驱动模块”,这形成了一个死循环。这也是initramfs存在的原因之一(第14篇已介绍过)。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐