将物理机正使用的操作系统制作成LiveCD笔记[未测试]
作者:张华 发表于:2013-09-30
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明
( http://blog.csdn.net/quqi99 )
1, 使用物理机上的相关目录制作根文件系统
1)准备块设备
dd if=/dev/zero of=/bak/images/livecd.img bs=10M count=1024
mkfs.ext4 /bak/images/livecd.img
sudo mount -o loop /bak/images/livecd.img /mnt
2)拷贝物理机上的相关目录,并删除不必要的文件减小体积,因为LiveCD要采用专用的模块故删掉模块,到时候再安装新内核。
sudo mkdir /mnt/system
sudo cp -a /{bin,etc,lib,lib64,sbin,root,usr} /mnt/system/
cd /mnt/system
sudo rm -rf usr/src
sudo rm -rf lib/modules
sudo rm -f lib/udev/write_*
sudo rm -f etc/udev/rules.d/70*
3)创建/etc/fstab与/etc/mtab, 注意,因为是LiveCD,并没有挂载根分区,而是proc和sys等启动过程必要的分区。
在initrd切换到根文件系统之前, 挂载信息不会体现在/etc/mtab文件中,为保持一致,我们也添加/etc/mtab文件。
cat > /mnt/system/etc/fstab << EOF
none /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devpts /dev/pts devpts gid=4,mode=620 0 0
tmpfs /dev/shm tmpfs defaults 0 0
EOF
cat > /mnt/system/etc/mtab << EOF
none /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devpts /dev/pts devpts gid=4,mode=620 0 0
EOF
如果不是LiveCD,而是一个可以直接启动的镜像的话, 这个文件可以不变。
除非根文件系统所在的块设备是个新的才需要给它设置卷标(如:tune2fs -L my-rootfs ubuntute.img),然后修改/etc/fstab中的UUID。
sudo mount -o loop ubuntut.img /mnt
sudo vi /mnt/etc/fstab
UUID=my-rootfs / ext4 defaults 0 0
4) 可将这些目录压缩成一个块设备:
sudo mksquashfs bin etc lib lib64 sbin root usr SYSTEM.img
这样,initrd就可以解压这些目录(mount -o loop -t squashfs /mnt/SYSTEM.img /mnt/system),
如果是LIVECD这个目录是只读的,所以可以创建一个在tmpfs文件系统,然后用aufs将这两个(一个可写的/SYSTEM和SYSTEM.img挂载的只读的/mnt/system)合起来再挂载到/SYSTEM上。
注意:/SYSTEM即作源目录又作为目标目录,aufs将它们理解成两个不同的目录,不会发生冲突。
sudo mount -t tmpfs tmpfs /SYSTEM
sudo mount -t aufs -o dirs=/SYSTEM=rw:/mnt/system=ro aufs /SYSTEM
然后再在initrd里补齐其他目录,并设置相应的权限,这样就是一个完整的根文件系统了。
sudo mkdir -pv dev proc sys tmp mnt home root
sudo chmod 1777 tmp
sudo 0700 root
sudo mkdir -pv var/{run,log,lock,mail,spool}
sudo mkdir -pv var/{opt,cache,lib/{misc,locate},local}
sudo touch var/run/utmp var/log/{btmp,lastlog,wtmp}
sudo chgrp utmp var/run/utmp var/log/lastlog
sudo chmod 644 var/run/utmp var/log/lastlog
2, 编译内核, 以下配置都应该编译进内核,而不是模块,所以应是”*”,而不是”m”。
在运行make menuconfig之前先打AUFS的patch, 内核中没有AUFS的代码,要先打patch(撤销patch加-R参数) ,选择origin/aufs3.9分支(因为内核用的是3.9版本)。
git clone http://git.code.sf.net/p/aufs/aufs3-standalone
cd aufs3-standalone/
git checkout -b aufs3.9 origin/aufs3.9
cd /bak/images/download/linux-2.6
git checkout -b v3.9 v3.9
patch -p1 < /bak/images/download/aufs3-standalone/aufs3-kbuild.patch
patch -p1 < /bak/images/download/aufs3-standalone/aufs3-base.patch
patch -p1 < /bak/images/download/aufs3-standalone/aufs3-proc_map.patch
patch -p1 < /bak/images/download/aufs3-standalone/aufs3-standalone.patch
patch -p1 < /bak/images/download/aufs3-standalone/aufs3-loopback.patch
cp -av /bak/images/download/aufs3-standalone/{fs,include} ./
1),支持initrd [默认已经是”*”了]
General setup -> Initial RAM fielsystem and RAM disk(initramfs/initrd) support
Device Drivers -> Block devices -> RAM block device support,并设置”Default RAM disk size(kbytes)”不小于16384.
2), Loop Device的支持 [默认已经是”*”了]
Device Drivers -> Block devices -> Loopback device support
3), SquashFS文件系统的支持,SquashFS文件系统用于将目录压缩成块设备 [默认已经是”*”了]
File system -> Miscellaneous filesystems -> SquashFS 4.0 – Squashed file system support
4), AUFS文件系统的支持, 用于将不同目录的文件合在一个目录下. LiveCD的SquashFS不可写,所以在TmpFS上创建可写的文件系统,然后用AUFS将它们连起来。
File system -> Miscellaneous filesystems -> Aufs (Advance multi layered unification filesystem) support
-> Detect direct branch access (bypassing aufs)
-> NFS-exportable aufs
-> Readdir in userspace
-> Respect the attributes (mtime/ctime mainly) of special files
-> Ramfs (initramfs/rootfs) as an aufs branch
5), EXT2文件系统支持,initrd一般使用ext2文件系统。
File system -> Second extended fs support,及其下的所有子项也都打*项,
6), ISO960文件系统的支持 [默认已经是”*”了]
File system -> CD-ROM/DVD filesystems -> ISO 9660 CDROM file system support
7), CDROM设备的支持 [默认已经是”*”了]
Divice Drivers -> SCSI device support -> SCSI disk support
-> SCSI generic support
-> SCSI CDROM support
8), [可选]如果是做LIVEUSB的话,在上面的基础上,还要加一个驱动:
USB设备驱动 [默认已经是”*”了],
Device Drivers -> HID Devices
-> USB support
LiveUSB一般采用VFAT或EXT3文件系统
File system -> Ext3 jouralling file system support, diable“Default to ‘data=ordered’ in ext3″,然后enable它下列所有的子项
File system -> DOS/FAT/NT Filesystems, 将MSDOS编译进内核,将VFAT编译成模块(因为VFAT并非内核启动过程中必须支持的文件系统)
9), 最后编译安装内核及模块
编译内核, make -j 4
安装内核,cp arch/x86/boot/bzImage /mnt/boot/livecd-kernel
安装模块
3, 创建initramfs
可以根据已有系统创建initramfs,也可以从头创建initramfs。
1) 我们先说前者,使用mkinitrd命令可生成已有的/boot/initramfs-3.9.10-100.fc17.x86_64.img生成一个新的,-f指这个的新的initramfs的路径,
其后的3.9.8-100.fc17.x86_64是指/lib/modules/3.9.8-100.fc17/, 添加新模块用–with参数:
sudo mkinitrd -f /boot/initramfs-3.9.10-100.fc17.x86_64.new.img 3.9.8-100.fc17.x86_64 –with usb-storage
还有一种方法是,解压initramfs,修改了之后,再重新生成即可。
mkdir /tmp/tmp && cd /tmp/tmp
sudo gzip -cd /boot/initramfs-3.9.10-100.fc17.x86_64.img |sudo cpio -id
修改了之后,再重新生成即可,
find . -print |cpio –quiet -c -o |gzip -9 > /boot/initramfs-3.9.10-100.fc17.x86_64.new.img
2)如果从重开始创建intramfs的话,首先创建一些目录:
1, cd /mnt/initramfs && mkdir bin etc lib proc sys
2,/bin目录,即下面init脚本用到的所有命令都得拷过来
cp -a /bin/{bash,chgrp, cp, grep, mkdir,sed,dd,cat,chmod,mount,sleep} bin
cp -a usr/bin/{touch,killall} bin
cp -a /sbin/{switch_root,udevd,udevadm} bin
3,/lib目录,可以使用一个脚本将/bin目录脚本的ldd所依赖的库全部持过来
cp -a /lib/udev lib
cp -a /etc/udev etc
sudo ./create_lib.sh$MYLINUX
$ cat create_lib.sh
ROOT=$1
libs=`find $ROOT/bin-type f -perm /111 -exec “ldd” {} \;|cut -d \> -f 2|cut-d -f 1|sort |uniq`
echo $libs
for lib in $libs
do
if [ -f $lib ];then
if [ !-f $ROOT/$lib ] ;then
dir=`dirname $ROOT$lib`
if [ ! -d $dir ];then
mkdir -pv $dir
fi
cp -av $lib $ROOT$lib
if [ -h $lib ]; then
source=`dirname $lib`/`readlink $lib`
cp -av $source $ROOT$source
echo $source >> liblist
fi
fi
fi
done
echo “Done!”
4, 用户及组信息,
cp -a /etc/{group, passwd} etc
5, 创建一个空的fstab,
touch etc/fstab
6,创建LiveCD的卷标,这个和下面init脚本中的要一致
echo “mylivecd” > /mnt/LABEL
7,首先创建init脚本,解释见脚本中的注释:
#!/bin/bash
##先要加载内核文件系统sysfs,以及很多地方都要用到的proc文件系统
mount -t proc proc /proc
mount -t sysfs sysfs /sys
##使用udev加载dev设备到内存中(tmpfs)
mount -n -t tmpfs -o mode=0755 udev /dev
##启动udev设备需先创建三个特殊设备文件console, null和stdin
mknod -m 600 /dev/console c 5 1
mknod -m 666 /dev/null c 1 3
mknod -m 666 /dev/stdin c 22 0
chmod 1777 /dev/shm
##避免如果uevent_helper里值是/sbin/hotplug时发消息给/sbin/hotplug
echo “” > /sys/kernel/uevent_helper
##使用udev创建设备
udevd –daemon
mkdir -p /dev/.udev/queue
udevadm trigger
udevadm settle
##initramfs执行完之后会switch_root到/SYSTEM目录,所以先创建一些mount要用到的目录
export SYSTEM=/SYSTEM
mkdir -p ${SYSTEM} /mnt
mount -t tmpfs tmpfs /mnt
mkdir -p /mnt/{cdrom,system}
##搜索LiveCD所在的设备,光盘的卷标位于32808节点开始的32个字节,找到之后去掉前后空格再比较
CDROM_OK=”F”
while [ “${CDROM_OK}” = “F” ]
do
for i in $(cat /proc/sys/dev/cdrom/info | grep “drive name” \
| sed ‘s@drive name:@@g’)
do
LABEL=$(dd if=/dev/${i} bs=1 skip=32808 count=32 2>/dev/null)
LABEL=$(echo “${LABEL}” | grep -o “[^ ]\+\(\+[^ ]\+*”)
if [ “${LABEL}” = “mylivecd” ]; then
mount -t iso9660 /dev/${i} /mnt/cdrom
CDROM_OK=”T”
break;
fi
done
if [ “${CDROM_OK}” = “F” ]; then
sleep 3
fi
done
##LIVECD的挂载(/mnt/system)目录是只读的(mount -o loop -t squashfs /mnt/SYSTEM.img /mnt/system),
##所以再创挂载一个可写目录/SYSTEM在内存tmpfs文件系统之上,最后用aufs将这两个目录合起来再挂载到/SYSTEM目录
mount -t tmpfs tmpfs ${SYSTEM}
mount -o loop -t squashfs /mnt/cdrom/SYSTEM.img /mnt/system
mount -t aufs -o dirs=${SYSTEM}=rw:mnt/system=ro aufs ${SYSTEM}
##创建除SYSTEM.img中bin,etc,lib,lib64,sbin,root,usr以外的最终根文件系统所需要的其他目录
mkdir -p ${SYSTEM}/{dev,proc,sys,tmp,mnt,initrd,home}
chmod 1777 ${SYSTEM}/tmp
chmod 0700 ${SYSTEM}/root
mkdir -p ${SYSTEM}/var/{run,log,lock,mail,spool}
mkdir -p ${SYSTEM}/var/{opt,cache,lib/{misc,locate},local}
mkdir -p ${SYSTEM}/usr/src{,-all,-tmp}
mount -t tmpfs tmpfs ${SYSTEM}/usr/src-tmp
mount -o loop -t squashfs /mnt/cdrom/SOURCES.img ${SYSTEM}/usr/src-all
mount -t aufs -o dirs=${SYSTEM}/usr/src-tmp=rw:${SYSTEM}/usr/src-all aufs ${SYSTEM}/usr/src
case $(cat /proc/cmdline | awk -F’book=’ ‘{print $2}’ | awk ‘{print $1}’) in
CROSS)
ln -s cross-sources ${SYSTEM}/usr/src/sources
ln -s cross-patches ${SYSTEM}/usr/src/patches
;;
HURD)
ln -s hurd-sources ${SYSTEM}/usr/src/sources
ln -s hurd-patches ${SYSTEM}/usr/src/patches
;;
LOCAL | *)
ln -s local-sources ${SYSTEM}/usr/src/sources
ln -s local-patches ${SYSTEM}/usr/src/patches
;;
esac
touch ${SYSTEM}/var/run/utmp ${SYSTEM}/var/log/{btmp,lastlog,wtmp}
chgrp utmp ${SYSTEM}/var/run/utmp ${SYSTEM}/var/log/lastlog
chmod 664 ${SYSTEM}/var/run/utmp ${SYSTEM}/var/log/lastlog
killall udevd
##initrd使用pivot_root命令针对挂载在根文件系统上的设备进行切换,
##但initramfs本身就直接建立在根文件系统(rootfs,tmpfs的一个实例)之上,
##不存在挂载,pivot_root无法完成任务,所以使用switch_root, switch_root相当于:
## find -xdev / -exec rm ‘{}’ ‘;’ && cd /newmount && mount –move . / && chroot . && exec init
exec switch_root ${SYSTEM} /sbin/init
8, 使用linux kernel源码里的gen_iniramfs_list.sh和gen_init_cpi脚本生成initramfs
cd /mnt/initramfs/..
sh ./gen_initramfs_list.sh initramfs > file_list
./gen_init_cpio file_list > initramfs.img
gzip -9 initramfs.img
cp initramfs.img.gz /mnt/boot/
4, 安装grub
1)创建目录,mkdir -p /mnt/boot/grub
2)安装grub模块文件
cp -a /usr/lib/grub/i386-pc/*.mod /mnt/boot/grub
cp -a /usr/lib/grub/i386-pc/*.lst /mnt/boot/grub
3)创建grub配置文件
cat /mnt/boot/grub/grub.cfg
set timeout=5
menuentry “LiveCD for make GNU/Linux” {
linux /boot/livecd-kernel book=LOCAL
initrd /boot/initramfs.img.gz
}
menuentry “LiveCD for cross make GNU/Linux” {
linux /boot/livecd-kernel book=CROSS
initrd /boot/initramfs.img.gz
}
menuentry “LiveCD for make GNU/Hurd” {
linux /boot/livecd-kernel book=HURD
initrd /boot/initramfs.img.gz
}
insmod vbe
set gfxpayload=800x600x16
5, 创建livecd启动文件,grub-mkimage命令将iso9660,linux和biosdkist模块合并一个模块组合文件,再用cat命令合并cdboot.img
grub-mkimage -o core.img iso9660 linux biosdisk
cat /usr/lib/grub/i386-pc/cdboot.img core.img > /mnt/boot/livecd.img
6, 使用mkisofs生成iso文件
mkisofs -R -boot-info-table -b /mnt/boot/livecd.img -V ‘mylived” -o mylivecd.iso iso
总结,
如果不是将物理机正使用的操作系统做成LiveCD的话,只是想将物理机正使用的操作系统做一个OpenStack镜像的话,我想应该不用这么周折。
不过这些我都没有测试,只是我理论上的想象。怎么做具有多个分区的镜像呢?有空再研究吧。
1)准备块设备
dd if=/dev/zero of=/bak/images/livecd.img bs=10M count=1024
mkfs.ext4 /bak/images/openstack.img
sudo mount -o loop /bak/images/openstack.img /mnt
2)拷贝物理机上的相关目录{bin,etc,lib,lib64,sbin,root,usr},并删除不必要的文件减小体积。
注意:这里和上面不同的地方是不需要删除lib/modules,因为我们不需要重新编译内核
sudo mkdir /mnt
sudo cp -a /{bin,etc,lib,lib64,sbin,root,usr} /mnt
sudo rm -rf usr/src
sudo rm -f lib/udev/write_*
sudo rm -f etc/udev/rules.d/70*
因为根文件系统所在的块设备的UUID ( 可用“sudo fdisk -l && sudo blkid lxc.img”命令检查)变化了,所以要更新/etc/fstab文件
UUID=00b037f0-8332-42e2-abf2-04207283b7f6 / ext4 defaults 1 1
或者使用tune2fs给这个新设备设置一个新标签:tune2fs -L my-rootfs /bak/images/openstack.img,还要改/etc/fstab, 改成“LABEL=my-rootfs / ext4 defaults 0 0”
这样/boot/grub/grub.conf文件里的kernel段,下面两种方式都是可以的(如果是USB启动的话,设备名总是会变,还是用UUID为好):
kernel /vmlinux ro root=LABEL=/ rhgb quiet
kernel /vmlinux ro root=UUID=my-rootfs rhgb quiet
3)不需要重新编译内核,因为不是livecd,额外的驱动似乎不必要
4)initramfs也不需要重新生成,因为不是livecd, 不需要为livecd定制什么,
但是对于initramfs里除bin,etc,lib,lib64,sbin,root,usr以外的最终根文件系统所需要的其他目录
##创建除SYSTEM.img中bin,etc,lib,lib64,sbin,root,usr以外的最终根文件系统所需要的其他目录{dev,proc,sys,tmp,mnt,initrd,home}还应该要创建的。
mkdir -p /mnt/{dev,proc,sys,tmp,mnt,initrd,home}
chmod 1777 /mnt/tmp
chmod 0700 /mnt/root
mkdir -p /mnt/var/{run,log,lock,mail,spool}
mkdir -p /mnt/var/{opt,cache,lib/{misc,locate},local}
mkdir -p /mnt/usr/src{,-all,-tmp}
touch /mnt/var/run/utmp ${SYSTEM}/var/log/{btmp,lastlog,wtmp}
chgrp utmp /mnt/var/run/utmp /mnt/var/log/lastlog
chmod 664 /mnt/var/run/utmp /mnt/var/log/lastlog
5)应该就完了
或者2)3)4)步直接通过dd命令全部拷过来了再删除不必要的目录,如: losetup -a && dd /dev/sda7 /dev/loop0
2013.10.05更新:
如果是qcow2格式的镜像文件,可以使用nbd打开, (还可以用kpartx或者guestfish)
1, nbd可以查看qcow2镜像中的分区,指定max_part参数开启nbd模块,默认nbd的增加分区的功能是关闭的,这个参数指定了一个nbd设备可以有多少个分区。
modprobe nbd max_part=8
2, 加载qcow2镜像到nbd设备中
$ sudo qemu-nbd –connect=/dev/nbd0 /bak/images/centos6.4.img
$ ls /dev/nbd0*
/dev/nbd0 /dev/nbd0p1 /dev/nbd0p2 /dev/nbd0p3
$ sudo fdisk -l /dev/nbd0
Disk /dev/nbd0: 21.2 GB, 21172846592 bytes
255 heads, 63 sectors/track, 2574 cylinders, total 41353216 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000591db
Device Boot Start End Blocks Id System
/dev/nbd0p1 2048 18434047 9216000 83 Linux
/dev/nbd0p2 18434048 20482047 1024000 82 Linux swap / Solaris
/dev/nbd0p3 * 20482048 41353215 10435584 83 Linux
3, sudo mount /dev/nbd0p3 /mnt2/
一个制作根文件系统的脚本:
#!/bin/bash
# vim: set ts=4 sw=4 et nu
set -e
usage=”Usage: $0 <name>”
name=$1
if [ -z “$name” ]; then
echo $usage
exit 1;
fi
libvirt_xml=”/bak/images/lxc/$name/libvirt.xml”
rootfs=”/bak/images/lxc/$name/rootfs”
echo “Initializing rootfs: $rootfs”
mkdir -p $rootfs
mkdir -p $rootfs/home
mkdir -p $rootfs/opt
mkdir -p $rootfs/proc
mkdir -p $rootfs/sys
mkdir -p $rootfs/root
mkdir -p $rootfs/media
mkdir -p $rootfs/mnt
mkdir -p $rootfs/srv
mkdir -p $rootfs/var
for d in bin etc lib lib64 mnt sbin selinux usr var; do
echo “Preparing files /$d …”
#rsync -ap “/$d/” “$rootfs/$d”
mkdir -p $rootfs/$d && mount –bind /$d $rootfs/$d
done
rm -rf “$rootfs/var/cache/*”
echo “Creating /dev”
dev_path=”$rootfs/dev”
rm -rf $dev_path
mkdir -p $dev_path
mknod -m 666 ${dev_path}/null c 1 3
mknod -m 666 ${dev_path}/zero c 1 5
mknod -m 666 ${dev_path}/random c 1 8
mknod -m 666 ${dev_path}/urandom c 1 9
mkdir -m 755 ${dev_path}/pts
mkdir -m 1777 ${dev_path}/shm
mknod -m 666 ${dev_path}/tty c 5 0
mknod -m 666 ${dev_path}/tty0 c 4 0
mknod -m 666 ${dev_path}/tty1 c 4 1
mknod -m 666 ${dev_path}/tty2 c 4 2
mknod -m 666 ${dev_path}/tty3 c 4 3
mknod -m 666 ${dev_path}/tty4 c 4 4
mknod -m 600 ${dev_path}/console c 5 1
mknod -m 666 ${dev_path}/full c 1 7
mknod -m 600 ${dev_path}/initctl p
mknod -m 666 ${dev_path}/ptmx c 5 2
echo “Creating network config eth0”
cat <<EOF > ${rootfs}/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet
USERCTL=yes
PEERDNS=yes
IPV6INIT=no
EOF
#echo “Creating network config resolv.conf”
#cat <<EOF > ${rootfs}/etc/resolv.conf
#nameserver 8.8.8.8
#EOF
echo “Creating network config sysconfig/network”
# set the hostname
cat <<EOF > ${rootfs}/etc/sysconfig/network
NETWORKING=yes
HOSTNAME=${name}
EOF
echo “Creating config fstab”
#
cat <<EOF > ${rootfs}/etc/fstab
none /dev/pts devpts defaults 0 0
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0
none /dev/shm tmpfs defaults 0 0
EOF
echo “Creating etc/hosts”
# set minimal hosts
cat <<EOF > $rootfs/etc/hosts
127.0.0.1 localhost $name
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
EOF
# selinux
echo “Creating selinux”
cat <<EOF > $rootfs/etc/selinux/config
SELINUX=disabled
SELINUXTYPE=targeted
EOF
#
echo “Creating init for guest”
cat <<EOF > $rootfs/bin/lxc_guest_init.sh
#!/bin/bash
export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
export PS1=”[\u@\h \W]\\$ ”
mount -t devtmpfs none /dev
mount -t devpts none /dev/pts
mount -t tmpfs none /dev/shm
/etc/init.d/network start
/etc/init.d/sshd start
exec /bin/bash
EOF
chmod 755 “$rootfs/bin/lxc_guest_init.sh”