如何优雅的升级内核?

 ADDOPS团队许斯亮 360云计算 


女主宣言

该文章出自于ADDOPS团队,该文章带入式的给大家介绍了一遍升级内核的流程,因为升级内核在运维工作中是经常的事情,但是同样的工作,同样的流程,如何让流程更加优雅和高效,是ADDOPS团队一直探索的点。也希望该文章能给大家一些启发,让大家在日常的运维工作中更加的高效和优雅。

PS:丰富的一线技术、多元化的表现形式,尽在“HULK一线技术杂谈”,点关注哦!



前言

大家都知道linux最核心的组件就是kernel:“内核”,有的时候修改内核代码来满足一些功能,有时候需要使用比较新的版本的一些特性,这时候就需要升级内核。


本文和大家聊聊如何优雅的升级内核。


kernel简介


什么是kernel,linux由用户空间和内核空间组成,内核空间负责和硬件驱动打交道,基本上你的每项操作都通过内核反应到硬件当中,很多核心的操作也需要内核支持才行,比如iptables,cgroup,一些系统debug等。


kernel组成


kernel基本有以下文件组成:


/boot/vmlinuz-3.8.0 内核核心启动程序 启动第一时间加载它 vmlinuz是可引导的、压缩的内核。


/boot/initramfs-3.8.0.img 内核核心预加载模块 将磁盘中核心模块抽离出来,因为在内核启动时候为了避免不必要问题,将一些用到的驱动等压缩到img中,虚拟出一个rootfs,待所有都准备好再加载真实文件分区,避免启动时的分区挂载问题。


/boot/System.map-xxx 核心功能对应表


/lib/module/kernel.版本号 内核加载的模块,内核模块有些是静态编译有些动态加载,动态加载的模块就放在这,以.ko方式存在。


/lib/firmware 驱动固件,网卡驱动等程序。


/etc/grub.conf 启动文件,管理要启动哪个内核,启动方式等。


kernel加载顺序


  1. boot loader Boot loader依据预先设定的条件,将kernel与initrd这两个image载入到RAM


  2. boot loader > kernel 完成必要的动作后,准备将执行权交给Linux kernel


  3. kernel进行一系列初始化动作,initrd所在的记忆体被kernel对应为/dev/initrd装置设备,透过kernel内部的decompressor (gzip解压缩)解开该内容并复制到/dev/ram0装置设备上


  4. kernel Linux以R/W (可读写)模式将/dev/ram0挂载为暂时性的rootfs


  5. kernel space > user space kernel准备执行/dev/ram0上的/linuxrc程式,并切换执行流程 user space linuxrc与相关的程式处理特定的操作,比方说准备挂载rootfs等。


  6. user space kernel space /linuxrc执行即将完毕,执行权转交给kernel。


  7. kernel Linux挂载真正的rootfs并执行/sbin/init程式 user space依据Linux distribution规范的流程,执行各式系统与应用程序。


编译内核


了解以上,我们就可以自己编译内核了,目前内核编译已经非常简单,只需要几步就可完成。


下载

去 https://www.kernel.org/ 上下载你要编译的版本,以下操作基于3.12.17。


make mrproper

删除之前编译的配置等,相当于make clean all


make menuconfig

加载配置管理界面,你可能需要先安装ncurses-devel。


如何优雅的升级内核?


这里面会有好多好多选项,比如是否编译蓝牙驱动,是否编译NAT模块等等,选项基本为m,y,n,这样会引发几个问题。


  1. 有些选项没有加载,使得你编译的内核某些功能用不了,比如NAT模块我之前没选y,就得重新编译

  2. 有很多是和硬件,服务器配置有关,我们不清楚。


上面的make menuconfig命令,实际上就是在内核编译文件夹下生成了.config文件,只不过使用可视化方式让选择更方便一些,最终内核是基于.config文件的配置来进行编译的。


时至今日,内核模块已非常的丰富(繁多),如果全部都编译加载的话,内核将变的非常臃肿,你在编译的时候最好按需加载,每个模块是否加载都有.config文件来决定。 比如以下配置表明是否开启cgroup


CONFIG_CGROUP_SCHED=y

CONFIG_CGROUPS=y

CONFIG_CGROUP_NS=y

CONFIG_CGROUP_FREEZER=y

CONFIG_CGROUP_DEVICE=y

CONFIG_CGROUP_CPUACCT=y

CONFIG_CGROUP_MEM_RES_CTLR=y

CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y

CONFIG_BLK_CGROUP=y

CONFIG_CGROUP_PERF=y

CONFIG_SCHED_AUTOGROUP=y

CONFIG_CFQ_GROUP_IOSCHED=y

CONFIG_NET_CLS_CGROUP=y

CONFIG_NETPRIO_CGROUP=y


在你编译内核过程中,必然面临一个问题,就是这么多内核选项,我要开启哪些?我要精简哪些?


这块有个技巧就是你找到现在服务器用得内核配置,把它拷贝一份作为一个默认的config文件,当然你得注意内核版本,版本相差太大很多参数是不一样的。


所以调优内核编译参数是个技术活


make dep

保存好配置以后,meke dep内核程序还会自己check依赖关系,哪些配置可用等,它会修改你的.config文件,把它变成这台机器上可用的。


make clean

清除上一次编译的残留文件


make -j8 bzImage

编译内核并压缩成一个img镜像,make -j8 -jn为多进程一般为cpu核心数2倍,如果24核就可以-j48 这样会速度会加快很多。


make -j8 modules

编译各个依赖模块


make -j8 modules_install

安装各个模块,其实就是把模块拷贝到/lib/modules/kernel.版本号/里


make -j8 install

安装内核,将镜像,预加载文件,拷贝到/boot中,修改/etc/grub.conf文件


默认内核程序会将新安装得内核顺序调成0,而启动调成1,把它手动调成0,重启才用新内核。


至此内核编译就结束了,然后到了最关键一步,重启,如果重启成功,基本上不会有太大问题,如果启动失败,那就要看具体报错来调整了。


内核移植


编译内核耗时很长,如果你编译好新的内核,想要在很多服务器上批量升级该怎么办?难道每台服务器都要重新编译一遍么?


当然不用,这里就涉及到内核移植。


移植文件

内核依赖以下几个文件


  • /bootvmlinuz-3.12.16 内核镜像

  • /boot/System.map-3.12.16 系统表

  • /lib/moudles 内核模块库

  • /lib/firware 内核相关驱动程序


将这些文件打个包传到新的机器上,然后执行拷贝。

cp vmlinuz-3.12.16 /boot/

cp System.map-3.12.16 /boot/

mkdir -p /lib/modules/3.12.16

/bin/cp -r moudles/* /lib/modules/3.12.16/

mv /lib/firmware /lib/firmware_old

cp -r firware /lib/


生成镜像

/sbin/new-kernel-pkg -v --mkinitrd --depmod --install --make-default --dracut --host-only 3.12.35-101.el6.x86_64


然后手动修改grub引导顺序即可。


这样就可以将编译好的内核在其它服务器上使用了,但是你是不是觉得还是有些繁琐,那么还有更优雅的升级内核方式么?当然有,使用rpm。


rpm包升级


在centos系统中,所有的软件更新都以rpm方式完成的,包括kernel,你可以看到系统上存在如下rpm包

kernel-devel-3.10.0-327.36.3.el7.x86_64

kernel-headers-3.10.0-229.el7.x86_64

kernel-3.10.0-327.36.3.el7.x86_64

kernel-devel-3.10.0-229.el7.x86_64

kernel-3.10.0-229.el7.x86_64

你也可以将编译好的内核build成rpm包,这样需要升级内核的服务器只要执行一条命令就行了

yum upgrade kernel

那么如何将自己编译的内核build成rpm包呢?


最简单的方式是参考官方的spec文件,然后做一点修改。


下载srpm

首先下载srpm包,并解压,比如kernel-3.10包地址:

http://vault.centos.org/7.3.1611/os/Source/SPackages/kernel-3.10.0-514.el7.src.rpm


解压srpm

rpm -i kernel-3.10.0-514.el7.src.rpm

在以下目录下会看到spec文件

/root/rpmbuild/SPECS/kernel.spec


修改替换

在/root/rpmbuild/SOURCES/文件夹下你会看到很多kernel相关的包文件: 比如"linux-2.6.32-504.30.3.el6.tar.bz2"就是kernel的源码文件。


在spec中做一系列替换操作比如"Source 0"替换为你需要的源码包文件,替换相关config等,就可以重新build一个属于你的kernel rpm包了。


值得一提的是,yum按照小版本号由大到小来判断具体升级哪个包,这样你可以把版本号调的高一些比如"100",这样即使官方的kernel也进行了更新,但是版本号没有你的高,每次升级还是默认升级你定制的kernel rpm。


这样你就可以只用“yum upgrade”一条命令优雅的升级你的内核。


上一篇:uniapp 打包生成EXE文件


下一篇:Cgroups Namespace Rootfs Volume Docker容器