前言
系统定制在前面的博文中咱们就有谈到过了,不过那个裁减制做有简单了点,只是能让系统跑起来而,没有太多的功能,也没的用户登陆入口,而这里咱们将详细和深刻的来谈谈Linux系统的详细定制过程和实现用户例如、远程登陆和Nginx安装过程、一步一步从头开始定制属于咱们本身的系统。html
正文
首先咱们先来简单的介绍一下咱们这里定制属于本身的Linux系统的基本元素,其中一些相关的信息也能够参考我前面写过的博文linux
一个定制的linux内核+一个定制的busybox就能够定制一个小型的Linux操做系统了,安装Dropbear和Nginx,Linux的组成部分包括内核空间和用户空间、而用户空间其实就是根文件系统、用户空间中又包括有shell和init,busybox他可以模拟数百个咱们系统上带用的命令、固然包括咱们所须要用到的shell、init、getty、login、那定制一个Linux操做系统咱们必需要了解的就是系统启动流程:
POST --> Boot Sequence(MBR) --> BootLoader --> kernel -->/sbin/init
POST:加电自检
Boot Sequence:读到磁盘中的第一个扇区(446)的MBR。
BootLoader:找到MBR中的BootLoader引导加载器、bootloader会找到咱们选定的操做系统或内核去加载对应的内核、而这个Bootloader一般是grub。
kernel:加载内核、内核要完成初始化、bootloader负责把内核读到内存中、内核又一般中压缩的、因此一般内核在内存中展开、而bootloader引导内核启动起来、让内核从他的程序入口处开始执行、因此接下来内核要完成自身的初始化操做、或硬件探测、包括自身执行环境的准备等等都在这里完成。
内核完成初始化的第一步就要去装载用户空间了、有时候为了让内核作得足够小、颇有可能内核中并不具有真正的根文件系统所在设备的驱动、所以咱们要借助于initramfs(CentOS5上被称为initrd)来完成去装载真正根文件系统所在的根文件系统真正的程序、可是这个initramfs可initrf(initramfs:这是一个文件系统、CentOS6上就这么称呼了,initrd:ram disk 这是一个磁盘设备)是个虚拟的根文件系统、是个虚根、他不是咱们系统真正工做起来所使用的根、因此称这个为虚根、内核借助于这个虚根装载驱动以后就要去挂载真正的根设备了、kernel会自动挂载到这个跟文件下、内核会挂载真正的根到这个initramfs虚根的某个目录下、好比说挂载到/mnt/sysroot的目录下、然后再完成根切换、然后咱们的真正的根就能够加载了、那咱们的内核怎么知道挂载的根文件系统是什么呢、那咱们的grub向内核传递参数root等于什么那就是告诉系统根文件系统所在的设备。nginx
/sbin/init:他一般加载四个设备、/sbin/init、/bin/bash、若是内核找不到就去找根下的init、再找不着就去找/bin/sh、/bin/bash、按照这个顺序去找、找到一个就能够启动系统、因此系统启动的第一个进程就启动了、init负责去启动用户空间中真正工做的进程、init自己自己只是负责去生成这些正正工做的进程和回收这些进程的、是内核的第一个、最顶级的管理进程、但不负责具体的工做、虽然init不负责具体工做、但他须要把一个用户空间启动为一个真正完整意义上的用户空间、因此init要结合他的配置文件inittab完成所谓系统初始化的。
在CentOS6上这个文件inittab之因此保留下来是为了跟CentOS5兼容的、其实咱们用不着的、由于init大多数配置文件都位于/etc/init/*.conf目录下全部以.conf结尾的文件、是用于各子系统之间协调的。shell
/sbin/init做用包含如下几步:
一、设定默认运行级别:runlevel -v:查看运行级别
二、系统空间中的进一行初始化、这个要依赖于一个系统初始化脚原本完成的、这个脚本叫rc.sysinit、在有些系统上可能叫rcS、其实都是一个概念、这个初始化包含键盘键映射、初始化没被挂载的文件系统等等。那/etc/rc.sysinit要进行哪些工做、seLinux、udev、键映射、交换分区的激活、挂载额外文件系统、从新以读写方式挂载根文件系统等等。
三、启动指定级别下的服务、后台的守护进程、每一个级别都有一个在/etcg下rcN.d的文件、启动这个文件中全部以S开头的脚本服务、关闭全部以K开头的服务脚本、/etc/rc.local其中以S开头的最后一个服务S99包含rc.local、有些咱们不便于本身写脚本定义的服务能够写到这里来、可是启动以后不会关闭、因此只是执行一些命令咱们能够在这里执行、服务仍是建议使用服务脚本。
四、设定键映射
五、启动虚拟终端、启动这个终端会调用一个叫login的程序、在虚拟终端上打印一个登陆提示符让咱们输入
六、若是设备默认级别为5的话还能够启动图形终端
init在早期是个串型的init、或者说传统意义是的init、sysV风格的、这种程序启动任何服务、运行任何程序完成系统初始化时通通以串型模式进行的、因此速度很是慢、以致于后来有了并型运行的init、启动速度也比较快。vim
准备工做:centos
系统裁减咱们说过、为了可让定制好的系统能够放到别的机器上动行、咱们要把他作到一个独立的硬盘上去、因此首先咱们在宿主机上添加一块SCSI的硬盘安全
添加硬盘,重启bash
分3个主分区
第一个主分区(作boot分区):50M
第二个主分区(作/根分区):512M
第三个主分区(作swap分区):256M服务器
n p 1 +50M n p 2 +512M n p 3 +256M t 3 82 w
第一步:编译内核或定制内核框架
一、获取内核程序包,能够到官网下载:http://ftp.redhat.com/pub/redhat/linux/enterprise/6Server/en/os/SRPMS/
这里咱们使用的内核版本是3.13.6的版本
解压内核文件,这里咱们以make allnoconfig来编译安装,本身选择要编译的功能(确保系统上的编译环境)
安装依赖包
咱们把这些内容所有编译进内核、不编译成模块、*号表示编译进内核(M表示以模块的方式装载)
注意:如下号标识的选项必定要选择号,不然系统没法正常启动
[]64-bit kernel :64位操做系统的内核
General setup --> Local version --> -MyLinux: 给内核定一个本身的版本
Processor type and features --> Processor family --> (X)Generic-x86-64:这里是CPU类型、这个是通用x86-64
[]Symmetric multi-processing support:选择CPU支持多核心处理
[]Enable loadable module support:选择内核动态模块加载
Bus options (PCI etc.) --> []PCI suppor:支持PCI总线
Device Drivers --> <>SCSI device support -->[]SCSI disk support要支持SCSI硬盘
Device Drivers -->Fusion MPT device support (NEW) --> <>Fusion MPT ScsiHost drivers for SPI、<>Fusion MPT misc device (ioctl) driver、[]Fusion MPT logging facility:支持对硬盘的驱动
File systems --> <>The Extended 4 (ext4) filesystem:支持文件系统
Executable file formats / Emulations --> []Kernel support for ELF binaries、[]Write ELF core dumps with partial segments (NEW)、 <>Kernel support for scripts starting with #!:可执行文件的格式
Device Drivers -->Input device support --> []Keyboards -> <>AT keyboard (NEW) []Mice:支持输入输出设备、好比健盘
Device Drivers > USB support > <> Support for Host-side USB > <>UHCI HCD (most Intel and VIA) support、<>OHCI HCD (USB 1.1) support、<>EHCI HCD (USB 2.0) support:USB设备驱动
Device Drivers > Generic Driver Options > [] Maintain a devtmpfs filesystem to mount at /dev []Automount devtmpfs at /dev, after the kernel mounted the rootfs
[] Networking support ---> > Networking options[] TCP/IP networking []IP:multicasting []IP: advanced router[]IP: policy routing []IP: verbose route monitoring[] IP: kernel level autoconfiguration[]IP: DHCP support[]IP: BOOTP support[] IP: RARP support<>IP: tunneling <>Unix domain sockets<> UNIX: socket monitoring interface:支持协议
Device Drivers > Network device support > Ethernet driver support[]Intel devices (NEW)<>Intel(R) PRO/1000 Gigabit Ethernet support<>Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support:只要Intel的、其余的他都去掉、这是选择网卡设备的驱动程序
[ ]Wireless:这个无线网、咱们去掉去、用不着
OK、到这里保存退出、把配置文件复制一份出来、前面磁盘格式化并且都挂载好了、这里咱们就把grub安装到boot下::
出现警告:
warning: Clock skew detected. Your build may be incomplete
解决办法:
(使用date命令从新设置时间格式是:date -s "MM/DD/YYYY hh:mm:ss"):
清除编译产生的文件
再次执行
make -j 4 bzImage
cp arch/x86/boot/bzImage /mnt/boot/
第二步:编译Busybox、让busybox提供一个sh程序、busybox能够模拟n种sh、能够模拟bash的特性、上面咱们有介绍过了
到busybox官网下载busybox程序包:http://www.busybox.net
解压到当前目录下就能够了:
==============================
报错:
Loaded plugins: fastestmirror, security
Loading mirror speeds from cached hostfile
解决方法:
==============================
make menuconfig时就选择这项就能够了、其余的都使用默认选项:
Busybox Settings -->Build Options -->[*] Build BusyBox as a static binary (no shared libs):把busybox编译也静态二进制,不用共享库
给grub提供一个配置文件
default=0
timeout=5
title Mini Linux (3.13.6-MyLinux_chinasoft)
root (hd0,0)
kernel /bzImage ro root=/dev/sda2 init=/sbin/init
给小系统提供一个rc.sysinit、/mnt/sysroot/etc/rc.d/rc.sysinit、若是没有这个目录就本身建立、再提供一个/mnt/sysroot/etc/fstab文件
/dev/sda1 /boot ext4 defaults 0 0
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
/dev/sda2 / ext4 defaults 0 0
/dev/sda3 swap swap defaults 0 0
密码也设置为:busybox
root:x:0:0:root:/root:/bin/sh
busybox:x:502:503::/home/busybox:/bin/sh
提供一个登陆欢迎信息、建立一个issue文件
MyLinux is CentOS release 6.5
Kernel \r on an \m
提供主机名
HOSTNAME=mylinux.chinasoft.com
提供命令提示符和环境变量
export PS1='[\u@\h \A \W]\$ '
PATH="/usr/local/sbin:/usr/local/bin:/sbin/:/bin:/usr/sbin:/usr/bin:$PATH"
==============================
到这里咱们的配置有了基本框架,此时把宿主机挂起,建立一个自定义虚拟机,把咱们制做有系统的那张硬盘放到自定义的虚拟机上运行:
若是第一个终端登陆不了能够切换到其余终端上登陆,按ctrl+alt+F2(F3\F4\F5\F6)能够切换到不一样的终端上去登陆的、这里咱们登陆成功了:
测试
启动报错:是由于make menuconfig处没有选择文件系统支持
远程登陆和ngix访问
OK、到这里咱们本身定制的Linux能够跑起来了、接下来咱们来实现远程登陆和Nginx的访问:
切换到宿主主上、下载dropbear-2013.58.tar.bz2和Nginx到本地:
一、解压安装dropbear
生成两个密钥文件
验证一下生的这两个文件
二、服务脚本/etc/rc.d/init.d/dropbear
#!/bin/bash
#
#
dsskey=/etc/dropbear/dropbear_dss_host_key
rsakey=/etc/dropbear/dropbear_rsa_host_key
lockfile=/var/lock/subsys/dropbear
pidfile=/var/run/dropbear.pid
dropbear=/usr/local/sbin/dropbear
dropbearkey=/usr/local/bin/dropbearkey
[ -r /etc/rc.d/init.d/functions ] && . /etc/rc.d/init.d/functions
[ -r /etc/sysconfig/dropbear ] && . /etc/sysconfig/dropbear
keysize=${keysize:-1024}
port=${port:-22}
gendsskey() {
[ -d /etc/dropbear ] || mkdir /etc/dropbear
echo -n "Starting generate the dss key: "
$dropbearkey -t dss -f $dsskey &> /dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
success
echo
return 0
else
failure
echo
return 1
fi
}
genrsakey() {
[ -d /etc/dropbear ] || mkdir /etc/dropbear
echo -n "Starting generate the rsa key: "
$dropbearkey -t rsa -s $keysize -f $rsakey &> /dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
success
echo
return 0
else
failure
echo
return 1
fi
}
start() {
[ -e $dsskey ] || gendsskey
[ -e $rsakey ] || genrsakey
if [ -e $lockfile ]; then
echo -n "dropbear daemon is already running: "
success
echo
exit 0
fi
echo -n "Starting dropbear: "
daemon --pidfile="$pidfile" $dropbear -p $port -d $dsskey -r $rsakey
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
touch $lockfile
return 0
else
rm -f $lockfile $pidfile
return 1
fi
}
stop() {
if [ ! -e $lockfile ]; then
echo -n "dropbear service is stopped: "
success
echo
exit 1
fi
echo -n "Stopping dropbear daemon: "
killproc dropbear
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
rm -f $lockfile $pidfile
return 0
else
return 1
fi
}
status() {
if [ -e $lockfile ]; then
echo "dropbear is running..."
else
echo "dropbear is stopped..."
fi
}
usage() {
echo "Usage: dropbear {start|stop|restart|status|gendsskey|genrsakey}"
}
case $1 in
start)
start ;;
stop)
stop ;;
restart)
stop
start
;;
status)
status
;;
gendsskey)
gendsskey
;;
genrsakey)
genrsakey
;;
*)
usage
;;
esac
三、脚本配置文件/etc/sysconfig/dropbear
keysize=2048
port=22022
export PATH=/usr/local/sbin:$PATH
启动服务并查看端口22022是否已经处于监听状态、并在本地尝试链接登陆:
dropbear在本机安装成功而且成功启动链接上去了
Xshell:\> ssh 192.168.8.40 22022
将该功能移植到咱们的定制系统,以前咱们写过一个脚本用来移植命令:
#!/bin/bash
#
dirPath=/mnt/sysroot
clearcmd(){
if which $1 &> /dev/null;then
cmdPath=which --skip-alias $1
else
echo "Command not exist!"
return 4
fi
}
cpCmd(){
dirName=dirname $1
[ -d ${dirPath}${dirName} ] || mkdir -p ${dirPath}${dirName}
[ -f ${dirPath}${cmdPath} ] || cp $1 ${dirPath}${dirName}
}
cpLib(){
for i in ldd $1 | grep -o "/[^[:space:]]\{1,\}"
;do
dirLib=dirname $i
[ -d ${dirPath}${dirLib} ] || mkdir -p ${dirPath}${dirLib}
[ -f ${dirPath}$i ] || cp $i ${dirPath}${dirLib}
done
}
while true;do
read -p "Enter a command:" cmd
if [ "$cmd" == 'quit' ];then
echo "quit!"
exit 0
fi
clearcmd $cmd
[ $? -eq 4 ] && continue
cpCmd $cmdPath
cpLib $cmdPath
done
把这三个命令移植过去就能够了:dropbear、dropbearkey、scp、dbclient、bash、复制完后就去建立这个目录/mnt/sysroot/etc/dropbear、然后为移植过去的dropbear生成两个密钥文件:
dropbear要认证用户、而认证用户要用到名称解析、这就意味着libnss库要复制过去、libnss库框架、然后给nss提供配置文件:
cp -d 是指带链接的拷贝:
只保留如下几项、其余的都不须要:
passwd: files
shadow: files
group: files
hosts: files dns
在用户登陆时dropbear认为用户的默认shell并不在/etc/shells下所在的用户shell中的话、他是不容许登陆的、那咱们就得给dropbear提供一个安全shell的配置文件了:
/bin/sh
/bin/hush
/bin/ash
/sbin/nologin
/bin/bash
dropbear启动时在/var/run/下会生成一个pid文件,而这个目录咱们尚未建立
到这里咱们定制的系统还不能远程登陆、当你远程登陆时、所登陆的终端都是远程/dev/pts的伪终端、这个伪终端是个伪文件系统、只要你的内核编译时支持这个文件系统、他就可使用、固然、咱们的目标机上尚未:
加一行
devpts /dev/pts devpts defaults 0 0
再建立/dev/pts这个目录:
OK、咱们先来测试一下dropbear远程登陆看可不能够登陆得上去、把宿主机挂起或关机、启动咱们的目标机、因为咱们的/dev/pts启动目标机时能够会从新挂载的问题、会把/dev/pts下的目录给覆盖掉、因此咱们进入目标机后能够在/dev/下建立pts这个目录、IP要设置在同一个网段内:
修改定制机的IP(避免和宿主机混淆)
ifconfig eth0 192.168.8.49
route add default gw 192.168.8.254
实现页面Nginx访问
这里咱们用的版本是Nginx-1.4.二、这里咱们以最简单的方式进行安装并运行服务起来:
解决依赖关系:
--prefix=/usr/local:指定第三方软件安装目录
--conf-path=/etc/nginx/nginx.cnf:指定主配置文件的路径
--error-log-path=/var/log/nginx/error.log:指定错误日志存放路径
--http-log-path=/var/log/nginx/access.log:指定访问日志
--group=nginx:以nginx用户身份运行、反正不要以管理员的身份去运行
--group=nginx:nginx用户组
其余的选项都是nginx默认选项、咱们都去掉
接着移植nginx到目标机上去、用上面的那个复制命令的脚本:
Enter a command:nginx
Enter a command:consoletype
Enter a command:quit
quit!
复制nginx下的配置文件到目标机上、而启动nginx须要nginx用户、因此用户也得追加到passwd文件中去、然后再给nginx添加一个测试页面就OK了:
<h1>Welcome to Nginx</h1>
<h1>Shenzhen huanying nin!</h1>
给nginx提供一个服务脚本
#!/bin/sh
#
#
. /etc/rc.d/init.d/functions
. /etc/sysconfig/network
[ "$NETWORKING" = "no" ] && exit 0
nginx="/usr/local/sbin/nginx"
prog=$(basename $nginx)
NGINX_CONF_FILE="/etc/nginx/nginx.conf"
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile=/var/lock/subsys/nginx
make_dirs() {
user=nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=[]∗[]∗.*/\1/g' -
options=$nginx -V 2>&1 | grep 'configure arguments:'
for opt in $options; do
if [ echo $opt | grep '.*-temp-path'
]; then
value=echo $opt | cut -d "=" -f 2
if [ ! -d "$value" ]; then
mkdir -p $value && chown -R $user $value
fi
fi
done
}
start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
make_dirs
echo -n $"Starting $prog: "
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog: "
killproc $prog -QUIT
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
configtest || return $?
stop
sleep 1
start
}
reload() {
configtest || return $?
echo -n $"Reloading $prog: "
killproc $nginx -HUP
RETVAL=$?
echo
}
force_reload() {
restart
}
configtest() {
$nginx -t -c $NGINX_CONF_FILE
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
exit 2
esac
而在nginx启动时须要依赖于日志目录和pid文件目录、因此咱们要事先给nginx建立这两目录先、还给建立锁文件:
OK、咱们启动定制的目标系统、再启动dropbear和nginx、而服务也能够正常启动了、测试咱们的nginx吧、若是服务脚本使用不了那就是里面能够有一些依赖函数或一些命令没有全都移植到目标机上、不过没关系、咱们能够手动启动服务器、这个问题都不大、最后测试完没什么就poweroff关机吧、若是nginx启动不了就从新把文件系统挂载为可读写就OK了:
nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (30: Read-only file system)
2016/03/10 19:22:02 [emerg] 78#0: mkdir() "/usr/local/client_body_temp" failed (30: Read-only file system)
至此,咱们的定制linux已完成,能够根据实际状况继续增长功能
总结下主要步骤:
一、准备目标磁盘二、提供bzImage三、提供busybox建议静态编译:事先安装glibc-static四、准备根文件系统(1) 复制编译安装完成的busybox(2) 补全所须要的其它目录五、为init提供配置文件etc/inittabetc/rc.d/rc.sysint六、提供虚拟终端,同时账号密钥等文件(1)编辑etc/inittab::respawn:/sbin/getty 19200 tty1::respawn:/sbin/getty 19200 tty2(2)为目标系统提供passwd, group, shadow七、主机名和banner(1) /etc/sysconfig/network文件编辑rc.sysinit,添加[ -r /etc/sysconfig/network ] && . /etc/sysconfig/network[ -z "$HOSTNAME" -o "$HOSTNAME" == "(none)" ] && HOSTNAME="localhost"/bin/hostname $HOSTNAME(2) 编辑/etc/issueWelcome to MageEdu MiniLinuxkernel \r八、提供ssh服务(1) 九、提供nginx服务(1) 编辑安装并移植nginx(2) 为目标系统上的nginx提供配置文件(3) 提供测试网页