2019-04-04

这篇文档先说明编译安装内核的背景和原因,然后以 4.14 内核为例,介绍详细步骤。

<!-- TOC -->

- [为何要自编译内核?](#为何要自编译内核)

- [选择哪个内核版本?](#选择哪个内核版本)

- [选择 4.14 还是 4.19内核 ?](#选择-414-还是-419内核-)

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

    - [准备编译环境](#准备编译环境)

    - [下载 kernel.org 内核](#下载-kernelorg-内核)

    - [拷贝内核配置文件](#拷贝内核配置文件)

    - [设置自定义内核版本字符串](#设置自定义内核版本字符串)

    - [并发编译内核](#并发编译内核)

    - [安装内核模块](#安装内核模块)

    - [查看安装的设备驱动文件信息](#查看安装的设备驱动文件信息)

    - [安装内核文档](#安装内核文档)

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

    - [安装内核配置文件](#安装内核配置文件)

    - [安装内核符号表文件](#安装内核符号表文件)

    - [创建 initramfs 文件](#创建-initramfs-文件)

    - [更新 Bootloader 配置文件](#更新-bootloader-配置文件)

    - [设置从新内核启动](#设置从新内核启动)

    - [重启机器,确认使用了新版内核](#重启机器确认使用了新版内核)

- [TODO](#todo)

- [参考](#参考)

<!-- /TOC -->

## 为何要自编译内核?

CentOS 7.x 自带的 3.10.x 内核存在诸多 Bugs(见文档尾部的链接列表),导致运行的 Docker 或 Kubernetes 不稳定,进而影响上层业务的可用性。解决的版本是升级到对容器支持更好的高版本内核。

RedHat/CentOS 官方只维护 OS 自带的 3.10.x 内核,对于高版本内核,需要自己获取安装包,常见的两种方式是:

1. 社区编译版本,如 elrepo 发布的 lt 和 ml 内核 RPM 包;

2. 自己配置、编译;

社区编译发布的内核不满足我们的需求,如 elrepo 发布的两个版本:

1. 4.4.x lt:部分设备驱动程序版本较老,场内安装后出现找不到磁盘的情况,导致系统启动失败(更多场内 cases,参考文末的链接列表);

2. 5.x ml:当前主线版本内核,不稳定,而且不是 kernel.org 长期支持版本;

所以,我们只能自己配置、编译内核。

需要注意的是,RedHat 官方只支持 OS 自带和后续发布的 3.10 内核,不支持社区和自编译版本内核。

## 选择哪个内核版本?

我们当前使用的是 4.4 LTS 内核,在场内升级部署后,出现网卡驱动 Bugs、重启时不识别 RAID 卡、启动失败的情况。

所以选择内核版本的原则是:kernel.org 发布的、长期支持的、4.4 以上版本。

目前 kernel.org 发布的内核版本如下:

![](image/2019-04-04-11-50-50.png)

可见,候选的 LTS 内核是:

1. 4.9.167

2. 4.14.110

3. 4.19.33

与 4.4 一样,4.9.167 包含的 megaraid_sas RAID 卡驱动版本是 "06.811.02.00-rc1",不满足需求。

4.14.110 和 4.14.110 对应的驱动版本较新("07.702.06.00-rc1","07.706.03.00-rc1"),可以满足需求。

所以,我们可用的 LTS 内核缩减为两个:

1. 4.14.110

2. 4.19.33

## 选择 4.14 还是 4.19内核 ?

我们做了一些调研,结果如下:

1. 4.19.x 不稳定,特别是 iptables conntrack 相关功能,被吐槽为 [badest release in the last 6 years](https://lists.fedoraproject.org/archives/list/kernel@lists.fedoraproject.org/thread/7GXLO5GLD7H4UUFDORLZE4SHQUBFQQUK/?sort=date):

  - [randomly crashes iptables connlimit module](https://bugzilla.kernel.org/show_bug.cgi?id=202013)

  - [connlimit is broken in whole 4.19.x series and 4.20.0](https://bugzilla.kernel.org/show_bug.cgi?id=202065)

  - [system fails to boot with内核 4.19.8-300.fc29.x86_64](https://bugzilla.redhat.com/show_bug.cgi?id=1658623)

2. 4.14.x 发布时间(2017-12-12)较 4.19.x 发布时间(2018-10-22)早,更稳当;

3. Google Cloud 使用 4.14.x 作为自己公有云 VM 缺省内核;

所以,我们更倾向于满足需求的、更稳定的 4.14.x LTS 版本。

## 编译内核

### 准备编译环境

编译内核需要 gcc、bc、bison 等 GNU 编译工具链,以及一些库头文件。 这里安装相关软件包:

``` bash

[root@m7-uiauto-ssd001 ~]# yum groupinstall 'Development Tools'

[root@m7-uiauto-ssd001 ~]# yum install bc elfutils-libelf-devel openssl-devel ncurses ncurses-devel bison

```

### 下载 kernel.org 内核

从官方下载 4.14 系列最新版内核源码,解压到内核源码目录 /usr/src/kernels:

``` bash

[root@m7-uiauto-ssd001 kernels]# cd /usr/src/kernels

[root@m7-uiauto-ssd001 kernels]# wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.110.tar.xz

[root@m7-uiauto-ssd001 kernels]# tar -xvf linux-4.14.110.tar.xz

```

### 拷贝内核配置文件

内核的配置参数非常多,稍有不慎就可能引起核心功能、驱动的缺失。所以,一般我们使用一个验证过的、版本相近的内核配置文件来配置内核,而不是自己从头一步步配置。

elrepo 发布的内核被广泛使用,可以使用它的内核配置文件作为我们配置的基础。

对于 elrepo 而言,4.14 是历史版本,不是当前的 lt 和 ml 版本,所以需要到 elrep archive repo 下载归档的 RPM,然后使用 cpio 解压 RPM,获得内核配置文件:

``` bash

[root@m7-uiauto-ssd001 kernels]# mkdir elrepo && cd elrepo

[root@m7-uiauto-ssd001 kernels]# wget http://mirror.rc.usf.edu/compute_lock/elrepo/kernel/el7/x86_64/RPMS/kernel-ml-4.14.15-1.el7.elrepo.x86_64.rpm

[root@m7-uiauto-ssd001 elrepo]# rpm2cpio kernel-ml-4.14.15-1.el7.elrepo.x86_64.rpm | cpio -idmv &>/dev/null

[root@m7-uiauto-ssd001 elrepo]# ls -l boot/

total 11100

-rw------- 1 root root 3704096 Dec 22 01:37 System.map-4.14.15-1.el7.elrepo.x86_64

-rw-r--r-- 1 root root  192761 Dec 22 01:37 config-4.14.15-1.el7.elrepo.x86_64

-rw-r--r-- 1 root root  361642 Dec 22 01:41 symvers-4.14.15-1.el7.elrepo.x86_64.gz

-rwxr-xr-x 1 root root 7095680 Dec 22 01:37 vmlinuz-4.14.15-1.el7.elrepo.x86_64

```

使用 eprepo RPM 内核配置文件配置内核:

``` bash

[root@m7-uiauto-ssd001 elrepo]# cd ../kernels/linux-4.14.110

[root@m7-uiauto-ssd001 linux-4.14.110]# make clean && make mrproper # 保证内核树的绝对干净;

[root@m7-uiauto-ssd001 linux-4.14.110]# cp ../elrepo/boot/config-4.14.15-1.el7.elrepo.x86_64 .config

```

### 设置自定义内核版本字符串

社区发布的内核包一般有一定的命名惯例,如 3.10.0-862.el7.x86_64、4.4.166-1.el7.elrepo.x86_64 等,用于区分来源和版本。

所以我们也需要给自编译的内核加上类似的版本字符串。 这里设置为 .0-el7.4pd.x86_64,对应的内核配置项为 General Setup -> Local version - append to内核 release:

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# make menuconfig # 编辑后保存

[root@m7-uiauto-ssd001 linux-4.14.110]# diff ../elrepo/boot/config-4.14.15-1.el7.elrepo.x86_64 .config

3c3

< # Linux/x86_64 4.14.15-1.el7.elrepo.x86_64 kernel Configuration

---

> # Linux/x86 4.14.110 kernel Configuration

21c21

< CONFIG_LOCALVERSION=""

---

> CONFIG_LOCALVERSION=".0-el7.4pd.x86_64"

5231a5232

> # CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set

6178a6180

> # CONFIG_USB_ROLE_SWITCH is not set

```

### 并发编译内核

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# make -j 24

```

### 安装内核模块

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# make modules_install

```

内核模块被安装到系统的 /lib/modules/<kernel-version> 目录下,目录名是内核版本和上面配置的自定义版本字符串的组合:

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# ls -l /lib/modules/ | grep 4pd

drwxr-xr-x  3 root root 4096 Apr  3 17:49 4.14.110.0-el7.4pd.x86_64

drwxr-xr-x  3 root root 4096 Apr  3 22:49 4.14.110.0-el7.4pd.x86_64

[root@m7-uiauto-ssd001 linux-4.14.110]# ls -l /lib/modules/4.14.110.0-el7.4pd.x86_64/

total 4084

lrwxrwxrwx  1 root root      30 Apr  3 22:49 build -> /usr/src/kernels/linux-4.14.110

drwxr-xr-x 13 root root    4096 Apr  3 22:49 kernel

-rw-r--r--  1 root root 1106323 Apr  3 22:49 modules.alias

-rw-r--r--  1 root root 1071287 Apr  3 22:49 modules.alias.bin

-rw-r--r--  1 root root    7058 Apr  3 22:49 modules.builtin

-rw-r--r--  1 root root    9279 Apr  3 22:49 modules.builtin.bin

-rw-r--r--  1 root root  341508 Apr  3 22:49 modules.dep

-rw-r--r--  1 root root  500405 Apr  3 22:49 modules.dep.bin

-rw-r--r--  1 root root    411 Apr  3 22:49 modules.devname

-rw-r--r--  1 root root  136971 Apr  3 22:49 modules.order

-rw-r--r--  1 root root    534 Apr  3 22:49 modules.softdep

-rw-r--r--  1 root root  437869 Apr  3 22:49 modules.symbols

-rw-r--r--  1 root root  537188 Apr  3 22:49 modules.symbols.bin

lrwxrwxrwx  1 root root      30 Apr  3 22:49 source -> /usr/src/kernels/linux-4.14.110

```

+ 内核模块目录中的 build 和 source 目录链接到内核源码目录,后续编译内核模块时需要这两个目录。

### 查看安装的设备驱动文件信息

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# modinfo /lib/modules/4.14.110.0-el7.4pd.x86_64/kernel/drivers/scsi/megaraid/megaraid_sas.ko

filename:      /lib/modules/4.14.110.0-el7.4pd.x86_64/kernel/drivers/scsi/megaraid/megaraid_sas.ko

description:    Avago MegaRAID SAS Driver

author:        megaraidlinux.pdl@avagotech.com

version:        07.706.03.00-rc1

license:        GPL

srcversion:    86E71DF0BD7853161D6991C

alias:          pci:v00001000d0000001Csv*sd*bc*sc*i*

alias:          pci:v00001000d0000001Bsv*sd*bc*sc*i*

alias:          pci:v00001000d00000017sv*sd*bc*sc*i*

alias:          pci:v00001000d00000016sv*sd*bc*sc*i*

alias:          pci:v00001000d00000015sv*sd*bc*sc*i*

alias:          pci:v00001000d00000014sv*sd*bc*sc*i*

alias:          pci:v00001000d00000053sv*sd*bc*sc*i*

alias:          pci:v00001000d00000052sv*sd*bc*sc*i*

alias:          pci:v00001000d000000CFsv*sd*bc*sc*i*

alias:          pci:v00001000d000000CEsv*sd*bc*sc*i*

alias:          pci:v00001000d0000005Fsv*sd*bc*sc*i*

alias:          pci:v00001000d0000005Dsv*sd*bc*sc*i*

alias:          pci:v00001000d0000002Fsv*sd*bc*sc*i*

alias:          pci:v00001000d0000005Bsv*sd*bc*sc*i*

alias:          pci:v00001028d00000015sv*sd*bc*sc*i*

alias:          pci:v00001000d00000413sv*sd*bc*sc*i*

alias:          pci:v00001000d00000071sv*sd*bc*sc*i*

alias:          pci:v00001000d00000073sv*sd*bc*sc*i*

alias:          pci:v00001000d00000079sv*sd*bc*sc*i*

alias:          pci:v00001000d00000078sv*sd*bc*sc*i*

alias:          pci:v00001000d0000007Csv*sd*bc*sc*i*

alias:          pci:v00001000d00000060sv*sd*bc*sc*i*

alias:          pci:v00001000d00000411sv*sd*bc*sc*i*

depends:

retpoline:      Y

intree:        Y

name:          megaraid_sas

vermagic:      4.14.110.0-el7.4pd.x86_64 SMP mod_unload modversions

parm:          lb_pending_cmds:Change raid-1 load balancing outstanding threshold. Valid Values are 1-128. Default: 4 (int)

parm:          max_sectors:Maximum number of sectors per IO command (int)

parm:          msix_disable:Disable MSI-X interrupt handling. Default: 0 (int)

parm:          msix_vectors:MSI-X max vector count. Default: Set by FW (int)

parm:          allow_vf_ioctls:Allow ioctls in SR-IOV VF mode. Default: 0 (int)

parm:          throttlequeuedepth:Adapter queue depth when throttled due to I/O timeout. Default: 16 (int)

parm:          resetwaittime:Wait time in seconds after I/O timeout before resetting adapter. Default: 180 (int)

parm:          smp_affinity_enable:SMP affinity feature enable/disable Default: enable(1) (int)

parm:          rdpq_enable: Allocate reply queue in chunks for large queue depth enable/disable Default: disable(0) (int)

parm:          dual_qdepth_disable:Disable dual queue depth feature. Default: 0 (int)

parm:          scmd_timeout:scsi command timeout (10-90s), default 90s. See megasas_reset_timer. (int)

```

### 安装内核文档

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# install -d /usr/share/doc/linux-4.14.110.0-el7.4pd.x86_64

[root@m7-uiauto-ssd001 linux-4.14.110]# cp -r Documentation/* /usr/share/doc/linux-4.14.110.0-el7.4pd.x86_64

```

### 安装内核

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# cp -iv arch/x86/boot/bzImage /boot/vmlinuz-4.14.110.0-el7.4pd.x86_64

'arch/x86/boot/bzImage' -> '/boot/vmlinuz-4.14.110.0-el7.4pd.x86_64'

```

### 安装内核配置文件

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# cp -iv .config /boot/config-4.14.110.0-el7.4pd.x86_64

'.config' -> '/boot/config-4.14.110.0-el7.4pd.x86_64'

```

### 安装内核符号表文件

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# cp -iv System.map /boot/System.map-4.14.110.0-el7.4pd.x86_64

'System.map' -> '/boot/System.map-4.14.110.0-el7.4pd.x86_64'

```

### 创建 initramfs 文件

创建 Booloader 加载的、启动时必须的 initramfs 文件:

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# time mkinitrd /boot/initramfs-4.14.110.0-el7.4pd.x86_64.img 4.14.110.0-el7.4pd.x86_64

real  0m55.735s

user  0m59.108s

sys 0m55.645s

```

### 更新 Bootloader 配置文件

更新 GRUB Bootloader 配置文件:

``` bash

[root@m7-uiauto-ssd001 linux-4.14.110]# grub2-mkconfig -o /tmp/grub2.cfg

Generating grub configuration file ...

Found linux image: /boot/vmlinuz-4.14.110.0-el7.4pd.x86_64

Found initrd image: /boot/initramfs-4.14.110.0-el7.4pd.x86_64.img

Found linux image: /boot/vmlinuz-4.14.110.0-el7.4pd.x86_64

Found initrd image: /boot/initramfs-4.14.110.0-el7.4pd.x86_64.img

Found linux image: /boot/vmlinuz-4.4.166-1.el7.elrepo.x86_64

Found initrd image: /boot/initramfs-4.4.166-1.el7.elrepo.x86_64.img

Found linux image: /boot/vmlinuz-3.10.0-862.el7.x86_64

Found initrd image: /boot/initramfs-3.10.0-862.el7.x86_64.img

Found linux image: /boot/vmlinuz-0-rescue-d1db6964e41c45e19a373462a1b2e789

Found initrd image: /boot/initramfs-0-rescue-d1db6964e41c45e19a373462a1b2e789.img

done

[root@m7-uiauto-ssd001 linux-4.14.110]# cd /boot/grub2

[root@m7-uiauto-ssd001 grub2]# cp grub.cfg grub.cfg.bak.201904032254

[root@m7-uiauto-ssd001 grub2]# cp /tmp/grub2.cfg grub.cfg

```

### 设置从新内核启动

``` bash

[root@m7-uiauto-ssd001 grub2]# grub2-set-default 0

```

+ 第二个参数值 0 为内核 menuentry 在 grub.cfg 中的序号。

### 重启机器,确认使用了新版内核

``` bash

zhangjun:~ zhangjun$ ssh root@m7-uiauto-ssd001

Last login: Wed Apr  3 22:18:02 2019 from 172.27.153.58

[root@m7-uiauto-ssd001 ~]# uname -a

Linux m7-uiauto-ssd001 4.14.110.0-el7.4pd.x86_64 #1 SMP Wed Apr 3 22:41:54 CST 2019 x86_64 x86_64 x86_64 GNU/Linux

```

## TODO

1. 将编译后的内核打包成 RPM 包,便于后续安装;

2. grub 配置支持 UEFI;

3. 支持 NVIDIA GPU;

## 参考

1. [Kernel/Traditional compilation](https://wiki.archlinux.org/index.php/Kernel/Traditional_compilation)

2. [Redhat/CentOS 3.10 内核 Bugs 导致K8S和Docker异常的情况汇总](https://wiki.4paradigm.com/pages/viewpage.action?pageId=44415151)

3. [华夏升级4.4内核后启动hang](https://wiki.4paradigm.com/pages/viewpage.action?pageId=50566372)

4. [交行数据上传下载慢](https://wiki.4paradigm.com/pages/viewpage.action?pageId=47120044)

5. [Kubernetes And Docker Troubleshooting](https://wiki.4paradigm.com/display/PROD/Kubernetes+And+Docker+Troubleshooting)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容