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加载顺序
-
boot loader Boot loader依据预先设定的条件,将kernel与initrd这两个image载入到RAM
-
boot loader > kernel 完成必要的动作后,准备将执行权交给Linux kernel
-
kernel进行一系列初始化动作,initrd所在的记忆体被kernel对应为/dev/initrd装置设备,透过kernel内部的decompressor (gzip解压缩)解开该内容并复制到/dev/ram0装置设备上
-
kernel Linux以R/W (可读写)模式将/dev/ram0挂载为暂时性的rootfs
-
kernel space > user space kernel准备执行/dev/ram0上的/linuxrc程式,并切换执行流程 user space linuxrc与相关的程式处理特定的操作,比方说准备挂载rootfs等。
-
user space kernel space /linuxrc执行即将完毕,执行权转交给kernel。
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,这样会引发几个问题。
有些选项没有加载,使得你编译的内核某些功能用不了,比如NAT模块我之前没选y,就得重新编译
-
有很多是和硬件,服务器配置有关,我们不清楚。
上面的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”一条命令优雅的升级你的内核。