DevOps

为什么要构建自己的 LiveCD

  1. 进行一些本地化修改;
  2. 对默认设置不满意;
  3. 对镜像的预装不满意。

Ubuntu-LiveCD.png

构建条件

  1. 一个运行 Ubuntu 的设备(虚拟机也是可以的,但不推荐 WSL1/2,因为 WSL2 经过实际测试会出现一些问题)。
  2. 确保已经安装 dosfstoolssquashfs-toolsxorrisogrub-commongrub-pc-bingrub-efi软件包。还有 nano 文本编辑器。
sudo apt-get install --no-install-recommends -y debootstrap squashfs-tools  xorriso dosfstools mtools grub-efi grub-pc-bin nano
  1. 全程终端操作,需要 sudo 权限。

准备目录

准备一个空文件夹作为工作目录。这个空文件夹所在分区不能是 NTFS、FAT32 格式。

然后在这个文件夹中创建 target、livecd 这两个文件夹。target 里面是目标系统,livecd 是 ISO 文件夹目录。

livecd 里面要创建 casper boot EFI preseed 等文件夹

export CHROOT=$PWD/target
sudo mkdir -p $CHROOT livecd/{casper,boot/grub,EFI/boot}

准备镜像

  • 基础系统

构建基础系统有两种方式:

  1. 利用 debootstrap 构建一个基础系统。
  2. 解压 Ubuntu Base。

debootstrap 是 Debian 系发行版的一个实用工具,允许您基于在线的软件源构建一个属于自己的 Debian 系发行版的基本系统。

Ubuntu Base 是 Ubuntu 的基本系统,说通俗点,就是 Ubuntu 帮你打包好的 debootstrap 后的基本系统。

如果你想使用 debootstrap 工具构建一个基本系统,请运行:debootstrap focal chroot https://mirrors.aliyun.com/ubuntu

sudo debootstrap --no-check-gpg --variant=minbase --arch=amd64 --exclude=gcc-9-base,gcc-10-base --components=main,restricted,universe,multiverse \
   --include=bash-completion,systemd-sysv,locales,nano,casper,console-setup,netplan.io,whiptail focal $CHROOT https://mirrors.aliyun.com/ubuntu
  • 配置软件源,因为默认是不完善的。
sudo chroot $CHROOT tee /etc/apt/sources.list << EOF
deb https://mirrors.aliyun.com/ubuntu focal main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu focal-security main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu focal-updates main restricted universe multiverse
EOF
  • 挂载特殊文件系统

你需要先挂载一些特殊的文件系统。比如 dev proc sys run。

sudo mount -B /dev $CHROOT/dev
sudo chroot $CHROOT mount none -t proc /proc
sudo chroot $CHROOT mount none -t sysfs /sys
sudo chroot $CHROOT mount none -t devpts /dev/pts

sudo chroot $CHROOT bash -s << EOF
truncate -s 0 /etc/machine-id
ln -fs /etc/machine-id /var/lib/dbus/machine-id
dpkg-divert --local --rename --add /sbin/initctl
ln -s /bin/true /sbin/initctl
EOF
  • 更新软件源

我们先更新一下软件源,升级一下基础系统里的软件包。

sudo chroot $CHROOT apt-get update
sudo chroot $CHROOT env DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
  • 安装 Linux 内核

这一步是必要的,安装的内核还将用于 ISO 镜像的引导。

sudo sed -i 's|COMPRESS=lz4|COMPRESS=lzma|' $CHROOT/etc/initramfs-tools/initramfs.conf
sudo chroot $CHROOT apt-get install -y linux-image-generic-hwe-20.04 grub-*-
  • 复制内核到光盘镜像
sudo mv $CHROOT/boot/vmlinuz-**-**-generic livecd/casper/vmlinuz
sudo mv $CHROOT/boot/initrd.img-**-**-generic livecd/casper/initrd.img
  • 给目标系统安装最小化桌面
sudo chroot $CHROOT env DEBIAN_FRONTEND=noninteractive apt-get install -y fonts-noto-cjk-extra language-pack-gnome-zh-hans ubuntu-desktop-minimal \
   networkd-dispatcher netplan.io firefox- gedit- eog- evince- gnome-characters- gnome-user-docs- gnome-font-viewer- gnome-online-accounts- \
   gnome-disk-utility- gnome-screenshot- gnome-logs- ubuntu-docs- fonts-deva- snapd- cups- cups-*- ibus- ibus-*-
sudo tee $CHROOT/etc/netplan/01-network-manager-all.yaml << EOF
# Let NetworkManager manage all devices on this system
network:
  version: 2
  renderer: NetworkManager
EOF

自定义配置

到这里结束之后,你可以在这个 chroot 容器里面进行自定义的设置,你想要预装什么软件,也可以操作。在容器里的操作和在本机操作的命令是相似甚至一致的。

  • 添加额外 apt 源
# 添加 VSCode 源
curl -sL https://packages.microsoft.com/keys/microsoft.asc | sudo gpg --dearmor -o $CHROOT/etc/apt/trusted.gpg.d/microsoft.gpg
echo "deb [arch=amd64] https://packages.microsoft.com/repos/code stable main" | sudo tee $CHROOT/etc/apt/sources.list.d/vscode.list
echo "deb [arch=amd64] https://packages.microsoft.com/repos/edge stable main" | sudo tee $CHROOT/etc/apt/sources.list.d/microsoft-edge.list

# 添加 cmake 源
curl -sL https://apt.kitware.com/keys/kitware-archive-latest.asc | sudo gpg --dearmor -o $CHROOT/etc/apt/trusted.gpg.d/kitware.gpg
echo "deb https://apt.kitware.com/ubuntu/ focal main" | sudo tee $CHROOT/etc/apt/sources.list.d/kitware.list

curl -sL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo gpg --dearmor -o $CHROOT/etc/apt/trusted.gpg.d/docker.gpg
echo "deb https://mirrors.aliyun.com/docker-ce/linux/ubuntu/ focal stable" | sudo tee $CHROOT/etc/apt/sources.list.d/docker-ce.list
  • 安装字体
sudo unzip $HOME/fonts.zip -d $CHROOT/usr/share/fonts/truetype/microsoft
sudo chroot $CHROOT env DEBIAN_FRONTEND=noninteractive apt-get install -y gnome-tweaks

# 额外字体
echo msttcorefonts msttcorefonts/accepted-mscorefonts-eula select true | sudo chroot $CHROOT debconf-set-selections
sudo chroot $CHROOT apt-get install -y ttf-mscorefonts-installer
sudo chroot $CHROOT debconf-show ttf-mscorefonts-installer
  • 个性化设置
sudo sed -i 's|\\w|\\W|g' $CHROOT/etc/skel/.bashrc

sudo mkdir -p $CHROOT/etc/dconf/profile $CHROOT/etc/dconf/db/local.d

sudo tee $CHROOT/etc/dconf/profile/user << EOF
user-db:user
system-db:local
EOF

sudo tee $CHROOT/etc/dconf/db/local.d/01-desktop << EOF
[org/gnome/desktop/media-handling]
automount=false

[org/gnome/desktop/interface]
font-name='微软雅黑 11'
document-font-name='微软雅黑 11'

[org/gnome/desktop/wm/preferences]
titlebar-font='微软雅黑 Bold 11'
EOF

sudo chroot $CHROOT dconf update

sudo mkdir $CHROOT/etc/docker
sudo tee $CHROOT/etc/docker/daemon.json << EOF
{
  "data-root": "/opt/docker",
  "registry-mirrors": [ "https://hub-mirror.c.163.com" ],
  "log-driver": "journald",
  "log-level": "warn",
  "bridge": "none",
  "debug": false
}
EOF

清理容器

到这一步,目标系统已经配置完毕了,下面应当进行清理。

sudo chroot $CHROOT apt-get autoremove --purge -y
for i in /dev/pts /dev /proc /sys; do sudo umount $CHROOT$i; done
sudo chroot $CHROOT bash -s << EOF
cat /dev/null > /etc/machine-id
rm /sbin/initctl
dpkg-divert --rename --remove /sbin/initctl
EOF

打包容器

# 建立清单
sudo chroot $CHROOT dpkg-query -W --showformat='${Package} ${Version}\n' | sudo tee livecd/casper/filesystem.manifest
# 打包目标系统
sudo mksquashfs $CHROOT livecd/casper/filesystem.squashfs -noappend -wildcards -e "var/cache/*" -e "var/log/*" -e "var/lib/apt/lists/*" -e "usr/share/man/*"

ISO 镜像的制作

  • 创建 GRUB 引导文件
# 生成引导菜单
sudo tee livecd/boot/grub/grub.cfg << EOF
search --set=root --file /casper/vmlinuz
insmod all_video
set timeout=30
menuentry "Ubuntu Live" {
   linux /casper/vmlinuz boot=casper net.ifnames=0 locale=zh_CN.UTF-8 toram fsck.mode=skip quiet splash --
   initrd /casper/initrd.img
}
menuentry "Ubuntu persistent" {
   linux /casper/vmlinuz boot=casper net.ifnames=0 locale=zh_CN.UTF-8 persistent fsck.mode=skip quiet splash --
   initrd /casper/initrd.img
}
EOF

# 创建 GRUB EFI 引导文件
sudo grub-mkstandalone --format=x86_64-efi --output=livecd/EFI/boot/bootx64.efi --locales="" --fonts="" \
   "boot/grub/grub.cfg=livecd/boot/grub/grub.cfg"
sudo LC_CTYPE=C bash -s << EOF
dd if=/dev/zero of=efiboot.img bs=1M count=3 && \
mkfs.vfat efiboot.img && \
mmd -i efiboot.img efi efi/boot && \
mcopy -i efiboot.img livecd/EFI/boot/bootx64.efi ::efi/boot/
EOF

# 创建 GRUB LEGACY 引导文件
sudo grub-mkstandalone --format=i386-pc --output=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=livecd/boot/grub/grub.cfg"
cat /usr/lib/grub/i386-pc/cdboot.img core.img > bios.img
  • ISO 的生成
sudo xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -volid "UBUNTU" -output Ubuntu-20.04-LiveCD-x86_64.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 efiboot.img \
   -graft-points "livecd" "/EFI/efiboot.img=efiboot.img" "/boot/grub/bios.img=bios.img"
参考资料
https://github.com/mvallim/live-custom-ubuntu-from-scratch
https://manpages.ubuntu.com/manpages/focal/man7/casper.7.html

Comment

This is just a placeholder img.