【Linux从入门到精通】第41篇:Linux内核编译初体验——裁剪属于你自己的内核

目录

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

二、内核源码获取与准备

[2.1 内核版本命名规则](#2.1 内核版本命名规则)

[2.2 下载内核源码](#2.2 下载内核源码)

[2.3 安装编译依赖](#2.3 安装编译依赖)

[三、配置内核:make menuconfig](#三、配置内核:make menuconfig)

[3.1 三种配置界面](#3.1 三种配置界面)

[3.2 以当前配置为起点](#3.2 以当前配置为起点)

[3.3 进入配置菜单](#3.3 进入配置菜单)

[3.4 精简内核的核心思路](#3.4 精简内核的核心思路)

[3.5 配置速查](#3.5 配置速查)

四、编译与安装

[4.1 编译内核](#4.1 编译内核)

[4.2 安装模块](#4.2 安装模块)

[4.3 安装内核](#4.3 安装内核)

五、Grub引导配置

[5.1 确认新内核已添加到启动菜单](#5.1 确认新内核已添加到启动菜单)

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

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

六、安全须知与回滚

[6.1 不要删除正在运行的内核](#6.1 不要删除正在运行的内核)

[6.2 启动失败的处理](#6.2 启动失败的处理)

[6.3 内存和磁盘要求](#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等编译工具链

  • flexbison:词法分析和语法分析工具

  • libssl-dev:内核模块签名

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

  • libncurses-devmake menuconfig的图形菜单界面

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

  • bc:数学计算工具

3.1 三种配置界面

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

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分区的真正作用。理解这些,你才能真正看懂freevmstat的输出,在内存问题排查时做到心中有数。


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

相关推荐
海兰7 小时前
将 Cursor 连接到生产日志:通过 Elastic MCP 服务器
运维·服务器·elasticsearch
Elastic 中国社区官方博客7 小时前
2026 年金融服务可观测性现状:从实施到业务影响
大数据·运维·人工智能·elasticsearch·搜索引擎·金融·自动化
木木_王7 小时前
嵌入式Linux学习 | 数据结构 (Day03)顺序表与单链表 超详细解析(含 C 语言实现 + 作业 + 避坑指南)
linux·c语言·数据结构·学习
vortex57 小时前
HackMyVm靶机Artig复盘
linux·渗透测试·靶机·hmv
谷哥的小弟7 小时前
(最新版)腾讯云服务器项目部署教程(4)— 部署项目
linux·运维·服务器·云计算·腾讯云·云服务器·项目部署
楼田莉子7 小时前
仿muduo库的高并发服务器——buffer缓冲区模块、socket模块
运维·服务器
starvapour8 小时前
INTEL-C621A芯片组服务器主板如何修改pcie等级
运维
计算机安禾8 小时前
【Linux从入门到精通】第48篇:Linux集群与负载均衡——LVS与Keepalived高可用
linux·负载均衡·lvs
酸钠鈀8 小时前
AI M61SDK Ubuntu 环境搭建
linux·运维·ubuntu