custom linux live

准备(GNU/Linux Debian/Ubuntu)

安装构建环境所需的应用程序。

sudo apt-get install \
    binutils \
    debootstrap \
    squashfs-tools \
    xorriso \
    grub-pc-bin \
    grub-efi-amd64-bin \
    mtools
mkdir $HOME/live-ubuntu-from-scratch

引导程序

构建基础系统

sudo debootstrap \
   --arch=amd64 \
   --variant=minbase \
   22.04 \
   $HOME/live-ubuntu-from-scratch/chroot \
   https://mirrors.aliyun.com/ubuntu/

debootstrap 用于从头开始创建 Debian 基础系统,而不需要dpkgapt的可用性。它通过从镜像站点下载 .deb 文件并将其解压缩到最终可以chroot到的目录中来做到这一点。

外部挂载点

sudo mount --bind /dev $HOME/live-ubuntu-from-scratch/chroot/dev
sudo mount --bind /run $HOME/live-ubuntu-from-scratch/chroot/run

由于将更新和安装的一些软件包(其中包括grub),这些挂载点在chroot环境中是必需的。

定义 chroot 环境

Unix操作系统上的chroot是一种更改当前运行进程及其子进程的明显根目录的操作。在这种修改后的环境中运行的程序无法命名(因此通常无法访问)指定目录树之外的文件。术语“chroot”可以指 chroot 系统调用或 chroot 包装程序。修改后的环境称为 chroot jail

访问chroot环境

sudo chroot $HOME/live-ubuntu-from-scratch/chroot

配置挂载点、家庭和语言环境

挂载无 -t proc /proc
挂载无 -t sysfs /sys
挂载无 -t devpts /dev/pts
导出 HOME=/root
导出 LC_ALL=C
这些挂载点在chroot环境中是必需的,因此我们能够顺利完成安装。

设置自定义主机名 echo "ubuntu-fs-live" > /etc/hostname

配置 apt sources.list

cat <<EOF > /etc/apt/sources.list
deb http://us.archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse
deb-src http://us.archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse
deb http://us.archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://us.archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
deb http://us.archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://us.archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse
EOF

更新包索引

apt-get update

安装systemd

apt-get install -y libterm-readline-gnu-perl systemd-sysv systemd是 Linux 的系统和服务管理器。它提供了积极的并行化能力,使用套接字和 D-Bus 激活来启动服务,提供守护进程的按需启动,使用 Linux 控制组跟踪进程,维护挂载和自动挂载点,并实现精细的基于事务依赖的服务控制逻辑。

配置 machine-id 并转移

dbus-uuidgen > /etc/machine-id
ln -fs /etc/machine-id /var/lib/dbus/machine-id

该/etc/machine-id文件包含在安装或引导期间设置的本地系统的唯一机器 ID。机器 ID 是一个以换行符结尾的十六进制 32 个字符的小写 ID。从十六进制解码时,这对应于 16 字节/128 位值。此 ID 可能并非全为零。

dpkg-divert --local --rename --add /sbin/initctl
ln -s /bin/true /sbin/initctl

dpkg-divert是用于设置和更新转移列表的实用程序。

安装 Live System 所需的软件包

apt-get install -y \
    sudo \
    ubuntu-standard \
    casper \
    lupin-casper \
    discover \
    laptop-detect \
    os-prober \
    network-manager \
    resolvconf \
    net-tools \
    wireless-tools \
    wpagui \
    locales \
    grub-common \
    grub-gfxpayload-lists \
    grub-pc \
    grub-pc-bin \
    grub2-common
apt-get install -y --no-install-recommends linux-generic

图形安装程序

apt-get install -y \
    ubiquity \
    ubiquity-casper \
    ubiquity-frontend-gtk \
    ubiquity-slideshow-ubuntu \
    ubiquity-ubuntu-artwork

安装过程中将出现tui对话框,无需做任何配置修改。

安装窗口管理器

apt-get install -y \
    plymouth-theme-ubuntu-logo \
    ubuntu-gnome-desktop \
    ubuntu-gnome-wallpapers

安装有用的应用程序

apt-get install -y \
    clamav-daemon \
    terminator \
    apt-transport-https \
    curl \
    vim \
    nano \
    less

安装 Visual Studio Code (可选)

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/
echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list
rm microsoft.gpg

apt-get update
apt-get install -y code

安装 Google Chrome (可选)

wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list

apt-get update
apt-get install google-chrome-stable

安装 JDK (可选)

apt-get install -y \
     openjdk-8-jdk \
     openjdk-8-jre

移除不需要的应用 (可选)

apt-get purge -y \
     transmission-gtk \
     transmission-common \
     gnome-mahjongg \
     gnome-mines \
     gnome-sudoku \
     aisleriot \
     hitori

删除不用的软件包

apt-get autoremove -y

重新配置

生成语言配置

dpkg-reconfigure locales
# 选择语言和默认语言

重新配置 resolvconf

dpkg-reconfigure resolvconf

配置网络

cat <<EOF > /etc/NetworkManager/NetworkManager.conf
[main]
rc-manager=resolvconf
plugins=ifupdown,keyfile
dns=dnsmasq
[ifupdown]
managed=false
EOF

dpkg-reconfigure network-manager

清理 chroot 环境

# If have installed software
truncate -s 0 /etc/machine-id

# Remove the diversion
rm /sbin/initctl
dpkg-divert --rename --remove /sbin/initctl

# Clean up
apt-get clean
rm -rf /tmp/* ~/.bash_history
umount /proc
umount /sys
umount /dev/pts
export HISTSIZE=0
exit

# Unbind mount points
sudo umount $HOME/live-ubuntu-from-scratch/chroot/dev
sudo umount $HOME/live-ubuntu-from-scratch/chroot/run

映像目录并填充

cd $HOME/live-ubuntu-from-scratch
mkdir -p image/{casper,isolinux,install}
sudo cp chroot/boot/vmlinuz-**-**-generic image/casper/vmlinuz
sudo cp chroot/boot/initrd.img-**-**-generic image/casper/initrd
sudo cp chroot/boot/memtest86+.bin image/install/memtest86+

wget --progress=dot https://www.memtest86.com/downloads/memtest86-usb.zip -O image/install/memtest86-usb.zip
unzip -p image/install/memtest86-usb.zip memtest86-usb.img > image/install/memtest86
rm image/install/memtest86-usb.zip

Grub 配置

cd $HOME/live-ubuntu-from-scratch
touch image/ubuntu

创建 /image/isolinux/grub.cfg

cat <<EOF > image/isolinux/grub.cfg

search --set=root --file /ubuntu

insmod all_video

set default="0"
set timeout=30

menuentry "Try Ubuntu FS without installing" {
   linux /casper/vmlinuz boot=casper quiet splash ---
   initrd /casper/initrd
}

menuentry "Install Ubuntu FS" {
   linux /casper/vmlinuz boot=casper only-ubiquity quiet splash ---
   initrd /casper/initrd
}

menuentry "Check disc for defects" {
   linux /casper/vmlinuz boot=casper integrity-check quiet splash ---
   initrd /casper/initrd
}

menuentry "Test memory Memtest86+ (BIOS)" {
   linux16 /install/memtest86+
}

menuentry "Test memory Memtest86 (UEFI, long load time)" {
   insmod part_gpt
   insmod search_fs_uuid
   insmod chain
   loopback loop /install/memtest86
   chainloader (loop,gpt1)/efi/boot/BOOTX64.efi
}
EOF

创建 manifest

在接下来的步骤中,清单的创建很重要,因为它告诉我们每个包的哪个版本安装在 Live 版本中,以及哪些包将在将要安装的版本中删除或维护(保留在硬盘中)。

cd $HOME/live-ubuntu-from-scratch

sudo chroot chroot dpkg-query -W --showformat='${Package} ${Version}\n' | sudo tee image/casper/filesystem.manifest
sudo cp -v image/casper/filesystem.manifest image/casper/filesystem.manifest-desktop
sudo sed -i '/ubiquity/d' image/casper/filesystem.manifest-desktop
sudo sed -i '/casper/d' image/casper/filesystem.manifest-desktop
sudo sed -i '/discover/d' image/casper/filesystem.manifest-desktop
sudo sed -i '/laptop-detect/d' image/casper/filesystem.manifest-desktop
sudo sed -i '/os-prober/d' image/casper/filesystem.manifest-desktop

压缩 chroot

cd $HOME/live-ubuntu-from-scratch
# 创建 squashfs
sudo mksquashfs chroot image/casper/filesystem.squashfs
# 生成 filesystem.size
printf $(sudo du -sx --block-size=1 chroot | cut -f1) > image/casper/filesystem.size

Squashfs是一个高度压缩的 Linux 只读文件系统。它使用 zlib 压缩来压缩文件、inode 和目录。系统中的 inode 非常小,所有块都被打包以最小化数据开销。支持大于 4K 的块大小,最大支持 64K。 Squashfs旨在用于一般只读文件系统、存档使用(即在可能使用 .tar.gz 文件的情况下)以及需要低开销的受限块设备/内存系统(例如嵌入式系统)。

创建磁盘说明

README文件通常可以在 Linux LiveCD 安装光盘上找到,例如 Ubuntu Linux 安装光盘;通常命名为“ README.diskdefines ”并且可以在安装过程中被引用。

cd $HOME/live-ubuntu-from-scratch

# Create file image/README.diskdefines
cat <<EOF > image/README.diskdefines
#define DISKNAME  Ubuntu from scratch
#define TYPE  binary
#define TYPEbinary  1
#define ARCH  amd64
#define ARCHamd64  1
#define DISKNUM  1
#define DISKNUM1  1
#define TOTALNUM  0
#define TOTALNUM0  1
EOF

为 LiveCD 创建 ISO 映像 (BIOS + UEFI)

cd $HOME/live-ubuntu-from-scratch/image

# 创建 grub UEFI 映像
grub-mkstandalone \
   --format=x86_64-efi \
   --output=isolinux/bootx64.efi \
   --locales="" \
   --fonts="" \
   "boot/grub/grub.cfg=isolinux/grub.cfg"

# 创建包含 EFI 引导加载程序的 FAT16 UEFI 引导磁盘映像
(
   cd isolinux && \
   dd if=/dev/zero of=efiboot.img bs=1M count=10 && \
   sudo mkfs.vfat efiboot.img && \
   LC_CTYPE=C mmd -i efiboot.img efi efi/boot && \
   LC_CTYPE=C mcopy -i efiboot.img ./bootx64.efi ::efi/boot/
)

# 创建 grub BIOS 映像
grub-mkstandalone \
   --format=i386-pc \
   --output=isolinux/core.img \
   --install-modules="linux16 linux normal iso9660 biosdisk memdisk search tar ls" \
   --modules="linux16 linux normal iso9660 biosdisk search" \
   --locales="" \
   --fonts="" \
   "boot/grub/grub.cfg=isolinux/grub.cfg"

# 组合可引导的 grub cdboot.img
cat /usr/lib/grub/i386-pc/cdboot.img isolinux/core.img > isolinux/bios.img

# 生成md5sum.txt
sudo /bin/bash -c "(find . -type f -print0 | xargs -0 md5sum | grep -v "\./md5sum.txt" > md5sum.txt)"

# 使用命令行从镜像目录创建iso
sudo xorriso \
   -as mkisofs \
   -iso-level 3 \
   -full-iso9660-filenames \
   -volid "Ubuntu from scratch" \
   -output "../ubuntu-from-scratch.iso" \
   -eltorito-boot boot/grub/bios.img \
      -no-emul-boot \
      -boot-load-size 4 \
      -boot-info-table \
      --eltorito-catalog boot/grub/boot.cat \
      --grub2-boot-info \
      --grub2-mbr /usr/lib/grub/i386-pc/boot_hybrid.img \
   -eltorito-alt-boot \
      -e EFI/efiboot.img \
      -no-emul-boot \
   -append_partition 2 0xef isolinux/efiboot.img \
   -m "isolinux/efiboot.img" \
   -m "isolinux/bios.img" \
   -graft-points \
      "/EFI/efiboot.img=isolinux/efiboot.img" \
      "/boot/grub/bios.img=isolinux/bios.img" \
      "."

另一种方法,如果前一个失败,创建一个混合 ISO

# 创建 ISOLINUX (syslinux) 启动菜单
cat <<EOF> isolinux/isolinux.cfg
UI vesamenu.c32
MENU TITLE Boot Menu
DEFAULT linux
TIMEOUT 600
MENU RESOLUTION 640 480
MENU COLOR border       30;44   #40ffffff #a0000000 std
MENU COLOR title        1;36;44 #9033ccff #a0000000 std
MENU COLOR sel          7;37;40 #e0ffffff #20ffffff all
MENU COLOR unsel        37;44   #50ffffff #a0000000 std
MENU COLOR help         37;40   #c0ffffff #a0000000 std
MENU COLOR timeout_msg  37;40   #80ffffff #00000000 std
MENU COLOR timeout      1;37;40 #c0ffffff #00000000 std
MENU COLOR msg07        37;40   #90ffffff #a0000000 std
MENU COLOR tabmsg       31;40   #30ffffff #00000000 std
LABEL linux
 MENU LABEL Try Ubuntu FS
 MENU DEFAULT
 KERNEL /casper/vmlinuz
 APPEND initrd=/casper/initrd boot=casper
LABEL linux
 MENU LABEL Try Ubuntu FS (nomodeset)
 MENU DEFAULT
 KERNEL /casper/vmlinuz
 APPEND initrd=/casper/initrd boot=casper nomodeset
EOF
# 包括 syslinux bios 模块
apt install -y syslinux-common && \
cp /usr/lib/ISOLINUX/isolinux.bin isolinux/ && \
cp /usr/lib/syslinux/modules/bios/* isolinux/

# 从镜像目录创建iso
sudo xorriso \
   -as mkisofs \
   -iso-level 3 \
   -full-iso9660-filenames \
   -volid "Ubuntu from scratch" \
   -output "../ubuntu-from-scratch.iso" \
 -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin \
 -eltorito-boot \
     isolinux/isolinux.bin \
     -no-emul-boot \
     -boot-load-size 4 \
     -boot-info-table \
     --eltorito-catalog isolinux/isolinux.cat \
 -eltorito-alt-boot \
     -e /EFI/boot/efiboot.img \
     -no-emul-boot \
     -isohybrid-gpt-basdat \
 -append_partition 2 0xef EFI/boot/efiboot.img \
   "$HOME/live-ubuntu-from-scratch/image"

制作可启动的 USB 映像

sudo dd if=ubuntu-from-scratch.iso of=<device> status=progress oflag=sync

小结

生成的 ISO 可以在虚拟机中进行测试,例如VirtualBox或写入媒体并从标准 PC 启动。