Linux Kernel
内核设计流派:
单内核设计,但是充分借鉴了微内核体系设计的优点,为内核引入了模块化机制,内核高度模块化; 内核被模块化之后,一些最为基本最为重要的内容,被编译到内核核心; 而其他更多的功能则以模块的方式来提供; 而且支持动态装载和卸载各内核模块;
内核的组成部分:
kernel: 内核核心文件,一般为bzImage,经过压缩处理的镜像文件; 通常内核核心文件保存在/boot目录下,名称为vmlinuz-VERSION-release
kernel object(ko): 内核对象,内核额外功能模块,一般该类文件放置于/lib/modules/UERSIN-release
注意: 内核模块与内核核心,版本号必须严格匹配;
内核模块其实就是内核源代码的一部分,只是在编译内核的过程中,由于其功能可能并非内核核心所必须,所以以模块的方式被编译;
在编译内核时,内核的功能通常有如下几种选择方式:
[ ] kernel Function: No,不选择编译此功能;
[M] Kernel Function: Modules,将此功能编译为内核模块使用; 此功能不占据内核空间,只占用磁盘空间;
[*] Kernel Function: Yes,将此功能直接编译进内核核心;
ramdisk: 内核补充文件,辅助文件,对于内核核心来说,此文件非必须,是否使用此文件取决于内核能否直接驱动rootfs所在的存储设备;
设备的驱动程序,SCSI设备的驱动;
逻辑设备驱动程序: LVM的驱动程序,软RAID驱动程序等;
文件系统:
解压initramfs: cpio -i -F initramfs-2.6.32-573.el6.x86_64.img
简化的rootfs
注意: 一般来讲,kernel核心文件必须具有完全相同的版本号;
内核管理的相关命令:
uname命令: 打印系统信息
uname [OPTION] ...
常用选项:
-a: 显示所有信息
lsmod命令: 显示有Linux内核核心已经装载的内核模块;
lsmod显示的内容,分为三个字段: 模块名称模块大小被引用次数及被谁所引用
modinfo命令:实例显示了一个Linux内核模块的信息
modinfo [-k kernel] [modulename|filename...]
常用选项:
-F field: 仅显示指定字段的信息; 通常只能指定一个字段;
-a: 只显示模块的作者信息
-d: 只显示模块的描述
-l: 只显示许可证信息
-p: 只显示模块参数信息
depmod命令: 内核模块依赖文件及系统信息映射文件的生成工具
实现内核模块的动态装载和卸载的命令:
insmod命令: 装载指定的内核模块文件,但无法自动解决模块间的依赖关系;
使用格式: insmod [filename] [module options...]
示例: ]# insmod `modinfo -n btrfs`
rmmod命令: 从Linux内核中移除模块
格式: # rmmod module_name
modprobe命令:从内核中移除模块或者向内核中插入模块;
modprobe [-C config-file] [modulename] [module parameters...]
默认的配置文件: /etc/modprobe.conf,/etc/modprobe.d/*
modprobe module_name: 装载模块,自动识别和解决依赖关系;
modprobe -r module_name: 卸载模块
ramdisk管理:
ramdisk文件是在操作系统安装完成之后,有特定的应用程序根据当前硬件设备信息,文件系统信息等量身定制而成;
ramdisk文件的制作工具:
CentOS 5:
mkinitrd: 创建预加载模块初始化内存图像;
使用格式: mkinitrd initrd-KERNEL-VERSION.img kernel-version
CentOS6/7:
dracut: 预加载模块中创建初始化内存磁盘图像;
使用格式: dracut initramfs-KERNEL-VERSION.img kernel-version
mkinitrd(脚本,依旧是调用drcaut命令)
/proc: 内核状态及统计信息的主要的输出接口; 同时还提供了一个能够输入配置信息,完成内核参数实时配置的接口----/proc/sys;
/proc/*(除了sys目录): 信息输出,只读;
/proc/sys: 可读写,可以接受用户指定的"新值",来实现对内核相应功能或特性的实时配置;
格式: echo "VALUE" > /proc/sys/PATH/TO/PARAMETER
查看内核参数以及配置/proc/sys中的诸多功能,还可以使用:
sysctl命令: 在运行时配置内核参数
查看内核参数:
sysctl -a: 查看所有可以被修改的内核参数;
sysctl variable: 查看指定内核参数的设定值;
配置某个内核参数(功能或特性)的值:
sysctl -w variable=value
注意: 在此方法中,"="两端不能写空格字符;
sysctl -p: 根据配置文件设置内存参数值; 重新读取并加载配置文件中所有的设置参数并且使其生效;
常用的几个内核参数:
net.ipv4.ip_forward: Linux的核心转发功能,路由功能; 取值0,1;
net.ipv4.icmp_echo_ignore_all: 忽略所有来源于外部主机的ping操作请求,取值0,1;
vm.drop_caches: 清理buffer和cache,释放物理内存,取值: 0,1,2;
kernel.hostname: 当前生效的主机名;
DDOS: Dynamic Deny of Service,动态拒绝服务攻击;
/sys: sysfs
专门为用户提供的伪文件系统,输出内核识别出来的各硬件设备的相关属性信息,也包括内核对硬件特性的可设定的信息; 对于某些参数进行特定格式的修改,以调整或设定硬件的工作特性;
udev: 通过读取/sys目录下的硬件设备的信息,按需为各硬件设备创建设备文件;
udev是运行在用户空间的进程;
专用工具: udevadmin,hotplug...
当内核已经被加载至内存中,加入操作系统被安装到sda磁盘上,则内核需要先标识出sda磁盘并且将其标记为设备(创建设备文件),而后才能挂载此设备;
为了能够让这样的设备以后也能正常使用,内核通过内置的devtmpfs为每个内核所要使用的设备文件;(当真正的文件系统起来后, 其内的文件会被转移到真正的文件系统中) 而这样的文件可以在被当做文件系统挂载之后,从内核直接转移到真正的rootfs中的dev目录内的; 对于操作系统启动之后被新插入的设备,就必须要依靠udev来识别并创建设备文件了;
udev之所以能够为设备创建设备文件,主要依赖于其事先定义好的规则; 而这样的规则一般保存在udev的规则配置文件中: /etc/udev/rules.d/usr/lib/udev/rule.d
定制内核----编译内核源代码:
http://kernel.org 内核维护的官方站点,可以获取内核源代码包;
编译源代码的前提条件:
1.开发环境:
开发工具: gcc,make,automake,qt,GTK,ncurses
程序包组:
"Development Tools","Server Platform Development"
“开发工具”,“服务器平台开发"
ncurses-devel
头文件: /usr/include/*.h
2.获取目标主机上各硬件设备的相关信息;
cpu:
# cat /proc/cpuinfo
# lscpu
# x86info -a
PCI设备:
# lspci [-v|-vv]
USB设备:
# lsusb [-v|-vv]
块设备:
# lsblk
了解更多的硬件设备的信息:
# hal-device (CentOS 6可用, 包名:hal-0.5.14-14.el6.x86_64)
目标主机需要使用哪种文件系统;
目标主机是否需要启用安全防护机制;
……
编译安装应用程序的一般步骤:
1) # ./.configure ARG1 [ARG2...]
2) # make
3) # make install
编译安装内核的一般步骤:
1.需要准备或生成一个.config的文件, 该文件记录了内核的编译细节,如:
哪些功能直接编译进内核;
哪些功能编译成内核模块;
哪些功能在此次编译中不启用;
make menuconfig|xconfig|gconfig|config
2.开始编译内核
make [-j #]
多线程编译,可以将编译进程在多个cpu核心上并行进行,加快编译速度;
3.安装模块:
make modules_install
make install
安装的是bzImage文件(即vmlinuz),安装到/boot/vmlinuz-VERSION-release; 生成与内核版本完全匹配的initramfs文件;编译grub的配置文件,生成启动菜单项;
screen命令:自由切换本地与终端之间的命令行。
开启screen: # screen
拆除screen: Ctrl+a,d
列表显示scree: #screen -ls
恢复连接至指定的screen: # screen -r SCREEN_ID
关闭screen: # exit
内核的配置选项:
64-bit kernel
是否支持64位内核
General setup --->
通用配置项
() Local version - append to kernel release
自定义本地版本号,附加到内核版本号后面的信息,由编译者定义;
((none)) Default hostname
定义当没有设置主机名时的默认主机名;
Enable loadable module support
是否支持内核模块的动态卸载;
Enable the block layer
Processor type and features:
处理器类型和特征
Processor family (Generic-x86-64) --> (Core 2/newer Xeon)
选择处理器类型
Power management and ACPI options:
电源管理及高级电源管理接口选项
Executable file formats / Emulations
指定可执行文件的格式,默认为ELF,以#!开头的文件也具备可执行特性;
Networking support:
内核中的网络协议栈
Networking options
[ ] IPv6 support 关闭
Device drivers:
设备驱动程序
File system:
DOS/FAT/NT file systems
[M] NTFS support
Kernel hacking:
内核调试的相关内容
Security options:
NSA SELinux support
安全选项
Crytographic API:
加密解密的应用编程接口;
Virtualization:
虚拟化相关
配置内核方式:
1.make config: 基于单行命令行以遍历内核所有功能的方式进行内核配置,因此每个内核选项的配置都是交互式的。
2.make menuconfig: 基于curses的文本模式的配置窗口;
3.make gconfig: 基于GTK开发环境的窗口配置界面;一般情况下, 只要安装了“ 桌面平台开发”程序包组就可以了;
4.make xconfig: 基于QT开发环境的窗口配置界面;一般情况下, 只要安装了“桌面开发平台”程序包组就可以了;
5.make defconfig: 基于内核为目标平台提供默认配置模板进行配置;
6.make allnoconfig: 所有功能全部不编译(全部选no)配置方式;
7.make allyesconfig: 所有功能全部编译进核心(全部选yes)的配置方式;
内核的编译方式:
1.全编译: make [-j #]
2.部分编译:
a.只编译某个子目录中的相关源代码;
# cd /usr/src/linux
# make [-j #] DIR_NAME/只编译某个目录中的源代码
b.只编译特定的模块
# cd /usr/src/linux
# make [DIR/]file.ko
示例:
# cd /usr/src/linux
# make drivers/net/ethernet/intel/e1000/e1000.ko
3.交叉编译:编译的目标平台与当前编译的平台不相同;
make ARCH=arch_name
示例:make ARCH=arm
内核重新编译:
1.将所有/usr/src/linux-VERSION目录的内容直接删除,重新从源代码包释放; 随后可以重复之前的步骤重新编译即可;
2.先清理之前的编译结果:
make clean:
清理大多数的编译生成的文件, 但是会保留.config文件;
make mrproper:
清理所有编译生成的文件,包括.config以及其他的备份文件;
make distclean:
相当于make mrproper,但是还会额外清理各种patches以及编译器自身的备份文件;
编译安装内核实例
~]# tar xf linux-3.10.99.tar.xz -C /usr/src
~]# cd /usr/src
src]# ln -sv linux-3.10.99 linux
src]# cd /usr/src/linux
linux]# cp /boot/config-$(uname -r) ./.config
linux]# make menuconfig
linux]# make -j 4
linux]# make modules_install
linux]# make install
linux]# reboot
重启之后在grub菜单中选择新编译的内核来启动, 如果可以看到登录提示符, 则说明内核编译升级成功!
Linux系统安装: CentOS系
POST --> BootSequece(BIOS) --> BootLoader(GRUB --> 1_5 stage --> 2nd stage) --> Kernel (devtmpfs) -->[ ramdisk (dev,proc,sys) --> ] rootfs(ro) --> /sbin/init (SysV Init,upstart Init,systemd)
对于所安装的CentOS操作系统来说, 其一级子目录中,有一些绝对不能单独分区, 有一些可以单独分区;
绝对不能分区: bin,sbin,lib,lib64
建议单独分区: boot,home,var,usr
安装Linux系统:/bootswap/ /home/var/usr
磁盘分区规划(必要分区): 启动分区 根分区 交换分区
规划文件系统:
/sbin/init,/sbin/systemd
所有的应用程序存放的路径
应用程序所依赖的库文件存放的路径
应用程序所使用的配置文件存放的路径
CentOS系/RHEL系操作系统的安装程序: anaconda
在安装操作系统的过程中, 系统的启动流程:
POST --> BootLoader --> kernel --> initrd --> rootfs --> anaconda
anaconda给我们提供了两种操作界面:
TUI:基于curses的文件配置窗口;
GUI:图形界面
CLI:命令行界面
以光盘为例, CentOS系统的安装启动流程:
1.POST
2.读取MBR:/isolinux/boot.cat,就是光盘的bootloader;
3.stage2: /isolinux/isolinux.bin
配置文件: /isolinux/isolinux.cfg
label linux
menu label ^Install or upgrade an existing system
menu default
kernel vmlinuz
append initrd=initrd.img
向内核传递附加参数; 常用的参数有:
initrd=initrd.img
text:从文本界面启动
method:手动选择安装方式
ip=ADDRESS:IP地址
netmask=MASK:子网掩码
gateway=GW: 网关
dns=DNS――SERVER: DNS服务器
rescue:启动紧急救援模式
dd:device drivers,装载额外的设备的启动程序;
ks:使用kickstart启动无人值守安装, 指明kickstart配置文件的所在位置:
光盘上:ks=cdrom:/PATH/TO/KICKSTART_FILE
本地硬盘: ks=hd:/DEVICE/PATH/TO/KICKSTART_FILE
某个远程web站点:ks=http://HOST[:PORT]/PATH/TO/KICKSTART_FILE
某个远程FTP站点: ks=ftp://[username@]HOST[:PORT]/PATH/TO/KICKSTART_FILE
某个远程安全WEB站点: ks=https://HOST[:PORT]/PATH/TO/KICKSTART_FILE
4.装载rootfs, 并启动anaconda
注意:如果内存不够512M, 则anaconda是以文本界面启动的;如果内存大于512M, anaconda默认以图形界面启动;
“ESC”键 --> boot: linux text
注意:上述的所有内容一般位于引导设备, 而后续的anaconda及其它安装时所用的程序包或程序包组等可来源于yum仓库, yum仓库的位置:本地光盘本地硬盘FTP服务器HTTP服务器NFS服务器
如果想手动指定程序包安装源:
ESC键 --> boot: linux method
anaconda的工作过程:
安装前的准备配置阶段
1.安装过程中使用的语言: 简体中文
2.键盘布局类型:美国英语式
3.系统安装的目标存储设备:
Basic Storage, 本地磁盘
Special Storage,网络存储, iSCSI, NAS,SAN, ......
4.设置主机名称
5.配置网络接口
6.选择时区
7.管理员密码
8.设定分区方式及MBR安装的位置
9.选择要安装的程序包或程序包组; (Ubuntu不让安装)
安装阶段:
1.有可能运行某些预安装脚本, 完成初始化工作
2.更具准备阶段规划的分区格式进行分区创建并执行格式话安装文件并挂载所有文件系统至指定挂载点;
3.将选定的程序包或程序包组安装至目标位置;
4.安装bootloader至MBR及boot分区中;
5.制作ramdisk文件;
6.如果有必要, 可能会运行安装后脚本;
首次启动:
1.选择许可证信息;
2.创建普通用户;
3.配置内核核心转储(Kdump, Core dump),如果内存小于2GB, Kdump不开启;
当某一时刻,内核核心崩溃时, kdump会将内核崩溃时内存中的所有数据创建成一个映像文件保存到磁盘上; 通过分析此文件的内容,查出内核崩溃的直接或间接原因;
kickstart文件的格式:
命令段:指明各种安装前的配置;
必备命令:
authconfig: 认证方式的配置
authconfig --useshadow --passalgo=sha512
bootloader: 定义bootloader的安装位置和相关配置选项
bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet"
keyboard: 设定键盘的类型
keyboard us
lang:安装过程中的语言类型
lang zh_CN.UTF-8
part: 分区布局及分区使用方式的定义:
part /boot --fstype=ext4 --size=200
part swap --size=2048
part PV_NAME --size=51200 --grow
clearpart: 清除分区
clearpart --none --drives=sda
volgroup: 创建卷组的命令
volgroup VG_NAME --persize=8192 PV_NAME
logvol: 创建逻辑卷的命令
logvol /home --fstype=ext4 --name=lv_home --vgname=VG_NAME --size=10240
logvol / --fstype=ext4 --name=lv_root --vgname=VG_NAME --size=30720
logvol /var --fstype=ext4 --name=lv_var --vgname=VG_NAME --size=10240
logvol /usr --fstype=ext4 --name=lv_usr --vgname=VG_NAME --size=10240
rootpw: 指明超级用户root的密码
rootpw --iscrypted $6$SALT$ENCRYPTED_PASS
timezone: 时区
timezone Asia/Shanghai
可选择命令:
install: 全新安装操作系统
upgrade:升级安装操作系统
text:使用文本界面安装操作系统, 默认是GUI
network: 配置网络接口
network --onboot yes --device eth0 --bootproto static --ip 172.16.254.1 --netmask 255.255.0.0 --noopv6 --hostname a.link.com --gateway= --dns=
firewall:防火墙设置
firewall --disabled
firewall --service=ssh
selinux: SELinux的设置
selinux --disabled
selinux --enforcing
题外话:
如果计划在已经开启防火墙和SELinux的强制模式时, 可以通过以下的几种方式将其关闭:
防火墙:
CentOS 6:
# service iptables stop
# chkconfig iptables off
CentOS 7:
# systemctl stop firewalld.service
# systemctl disable firewalld.service
如果想要让防火墙临时不生效:
# iptables -F 适用于所有的CentOS系统;
SELinux:
1.编辑SELinux的配置文件/etc/sysconfig/selinux(/etc/selinux/config),在配置文件中, 有一行语句为: SELINUX=disabled(disabled (关闭)|enforce (开启)|permissive (警告))
2.编辑grub的启动配置文件/boot/grub/grub.conf
kernel /vmlinuz-VERSION-release ARGS selinux=0
如果想要SELinux临时不限用户行为:
# setenforce 0 == Enforcing --> Permissive
# setenforce 1 == Permissive --> Enforcing
# gentenforce 查看SELinux状态
repo: 安装系统时所使用的repository
repo --name="CentOS" --baseurl=cdrom:sr0 --cost=100
repo --name="CentOS" --baseurl=http://host[:port]/PATH --cost=100
reboot: 安装完成之后重新启动
halt/poweroff: 安装完成之后关闭系统
url:指明安装时使用的repository, 但必须使用url格式;
url --url=http://host[:port]/PATH
firstboot: 控制首次启动
firstboot --disable
脚本段:
%pre: 安装前脚本的开始部分
运行环境: 运行于安装介质上的微型Linux系统环境;
%end
%post: 安装后脚本的开始部分
运行环境: 安装以后的操作系统
%end
程序包/程序包组段:指明要安装的程序包或程序包组以及不安装程序包;
%packages(表示开始)
@PACK_GROUP_NAME: 安装一个程序包组
PACK_NAME: 安装单个指定的程序包
-PACK_NAME: 明确指出不安装的程序包; 有时即便明确指出该项, 被指出的程序包也可能会被安装上;
%end(表示结束)
如何创建kickstart文件:
1.直接以anaconda-ks.cfg为模板,复制之后修改即可;
2.可以使用工具来创建:
如果命令不存在, 则yum install system-config-kickstart安装即可;
示例: # system-config-kickstart &
可以全新创建, 也可以依据其他的ks文件(如anaconda-ks.cfg)来修改生成问的配置文件;
ksvalidator
如果该命令不存在, 可以安装pykickstart-1.74.20--1.el6.noarch
利用一台CentOS 7构建web server, 方法如下:
临时清除防火墙规则, 并将selinux设置为permissive模式:
~]# iptables -F
~]# setenforce 0
启动web服务
~]# systemctl start httpd.service
查看web服务的运行状态, 只要有绿色文字显示的active(running),即为服务正常启动;
~]# systemctl status httpd.service
为CentOS 6提供repository
~]# mkdir /var/www/html/centos_6_repo
~]# mount /dev/sr0 /mnt/cdrom
注意:光驱中放的是CentOS 6的安装光盘的CD1;
~]# cp -a /mnt/cdrom/* /var/www/html/centos_6_repo
到此,web服务器的配置完成;
利用一台已经安装好的CentOS 6操作系统, 创建启动启动光盘:
~]# vim /root/centos6-ks.cfg
#platform=x86,AMD64,orIntelEM64T #version=DEVEL #Firewallconfiguration firewall--disabled #SELinuxconfiguration selinux--disabled #InstallOSinsteadofupgrade install #Usenetworkinstallation network--onbootyes--deviceeth0--bootprotodhcp url--url=" #Rootpassword rootpw--iscrypted$1$iRHppr42$VMesh73wwBqhUTjKp6OYOD. #Systemautorizationinformation auth--useshadow--passalgo=sha512 #Usetextmodeinstall text firstboot--disable #Systemkeyboard keyboardus #Systemlanguage langen_US #SELinuxconfiguration selinux--disabled #Rebootafterinstallation reboot #Systemtimezone timezoneAsia/Shanghai #Systembootloaderconfiguration bootloader--append="rhgbcrashkernel=autoquiet"--location=mbr--driveorder="sda" #CleartheMasterBootRecord zerombr #Partitionclearinginformation clearpart--all #Diskpartitioninginformation part/boot--fstype="ext4"--size=200 partpv.008--size=61440 volgroupmyvy--pesize=4096pv.008 logvol/--fstype=ext4--name=root--vgname=myvg--size=20480 logvolswap--name=swap--vgname=myvg--size=2048 logvol/usr--fstype=ext4--name=usr--vgname=myvg--size=10240 logvol/var--fstype=ext4--name=var--vgname=myvg--size=20480 #repo--name="CentOS"--baseurl=cdrom:sr0--cost=100 %post echo-e'QhdlinkLinuxforLearningServices\n>>/etc/issue sed-i'1,$s@id:[0-9]:initdefault:@id:3:initdefault:@g'/etc/inittab ifconfigeth0172.16.69.2/16 %end %packages @base @core @debugging @basic-desktop @desktop-debugging @desktop-platform @desktop-platform-devel @development @directory-client @fonts @general-desktop @graphical-admin-tools @input-methods @internet-applications @internet-browser @java-platform @legacy-x @network-file-system-client @office-suite @print-client @remote-desktop-clients @server-platform @server-platform-devel @server-policy @workstation-policy @xll mtools pax python-dmidecode oddjob wodim sgpio genisoimage device-mapper-persistent-data systemtap-client abrt-gui desktop-file-utils jpackage-utils samba-winbind certmonger pam_krb5 krb5-workstation openmotif libXmu libXp %end
创建引导光盘:
~]# mkdir myiso
~]# cp -r /mnt/cdrom/isolinux /root/myiso/
注意: 这样的复制方法是将isolinux目录直接复制到myiso目录中, 也就是说isolinux是myiso的子目录;
~]# vim /root/myiso/isolinux/isolinux.cfg
labellinux menulabel^Installorupgradeanexistingsystem menudefault kernelvmlinuz appendiniitrd=initrd.imgks=cdrom:/centos6-ks.cfg
~]# cp /root/centos6-ks.cfg /root/myiso
~]# mkisofs -R -J -T -v --no-emul-boot --boot-load-size 4 --boot-info-table -V "CentOS 6 x86_64 boot" -b isolinux/isolinux.bin -c isolinux/boot.cat -o /root/boot.iso myiso/
创建U盘启动盘
方法一:
~]# dd if=/dev/sr0 of=/dev/sdb
方法二:
~]# fdisk /dev/sdb (将整个U盘分为一个区,并将其分区类型修改为vfat,即在fdisk交互模式中使用t --> b命令完成转换)
~]# mkfs.vfat /dev/sdb1
~]# mount /dev/sdb1 /mnt/usb
~]# mkdir -p /mnt/usb/grub
~]# cp /mnt/cdrom/isolinux/{vmlinuz,initrd.img} /mnt/usb
~]# vim /mnt/usb/grub/grub.conf
default=0 timeout=5 titlethelinuxbootfromusb root(hd0,0) kernel/vmlinuz initrd/initrd.imgks= #将centos6-ks.cfg文件放置于CentOS7的/var/www/html目录中,改名为ks.cfg即可
~]# grub
grub> root (hd1,0)
grub> setup (hd1)