再探 Gentoo

前言

上次用 Gentoo 还是上次 GentooWSL,中间隔了两三年,各方面水平都不可同日而语。最近在考虑 Void 之外的新发行版作为主系统,先花大力气试了试 FreeBSD/GhostBSD,ZFS 体验极佳,可惜硬件支持远逊于 Linux。来回对比,可能还是 Gentoo 比较符合要求,再次尝试,同时使用 ZFS 作为 rootfs 并启用 UEFI。

文档

第三方教程:

LiveCD

开始下了 LiveGUI USB Image,然鹅基于 KDE,体积过于庞大。 而且什么都有多份,浏览器三四个,聊天软件七八个,编辑器也一大堆。 感觉不错的就 Kdenlive 和 ghostwriter,其他都是老熟人。 这是纯 LiveCD,没有安装选项 2,于是换回 Minimal Installation CD Admin CD。

步骤

安装步骤列表,#实操 章节的划分标准,见于 About the Gentoo Linux Installation

StepResult
1启动镜像
2联网
3分区
4准备 Chroot
5配置编译 (Portage, USE, binpkg)
6安装内核 (kernel, initramfs via dracut, zfs kmod)
7配置系统
8安装系统工具
9配置 bootloader
10收尾

实操

1-2. 准备

  1. 官网/镜像站下载 Admin CD + Stage 3 (desktop profiles | systemd),还有 UEFI 使用的 BOOTX64.EFI
    • Admin CD 用于启动,只有这个和最大的 LiveGUI USB Image 内置 ZFS 工具
    • tarball/EFI 直接 rsync 同步到虚拟机
  2. 通读上面贴的文档,了解大概的流程
  3. 以 UEFI 模式启动 Admin CD3 并安装必要的软件包
/etc/init.d/sshd start # start sshd
passwd root # initiate root passwd as it's disabled by default
ip a # confirm network is working

3-4. 分区与初始化

导入 libvirt,启动后直接从 host OS SSH 过去,先简单分个区。 照例,GPT,100M FAT32,剩下全部给 ZFS,无 swap。

$ fdisk -l
Disk /dev/vda: 10 GiB, 10737418240 bytes, 20971520 sectors
Disk /dev/loop0: 679.59 MiB, 712605696 bytes, 1391808 sectors

# 分区, 100M EFI, no swap
cfdisk /dev/vda

$ fdisk -l
Disk /dev/vda: 10 GiB, 10737418240 bytes, 20971520 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
Disklabel type: gpt
Disk identifier: 72B714EC-8CED-4AD6-8CAB-4C730F4217C0

Device      Start      End  Sectors  Size Type
/dev/vda1    2048   206847   204800  100M EFI System
/dev/vda2  206848 20969471 20762624  9.9G Linux filesystem

创建分区 4

💡 Tip

这里默认 zpool 名称为 zroot,和文档里的 tank 不一样,后面自行代入替换。

mkfs.vfat -F 32 /dev/vda1

zgenhostid -f
modprobe zfs

zpool create -f \
	-o ashift=12 \
	-o autotrim=on \
	-o compatibility=openzfs-2.1-linux \
	-O acltype=posixacl \
	-O xattr=sa \
	-O relatime=on \
	-O compression=lz4 \
	-m none zroot /dev/vda2

创建 ZFS:

ℹ️ Note

这里只配置了 //home,也可以添加其他的。

zfs create -o mountpoint=none zroot/os
zfs create -o mountpoint=/ -o canmount=noauto zroot/os/gentoo
zfs create -o mountpoint=/home zroot/home

zpool set bootfs=zroot/os/gentoo zroot

导出后再次导入并挂载到 /mnt

zpool export zroot
zpool import -N -R /mnt/gentoo zroot

# mount the filesystem
zfs mount zroot/os/gentoo
zfs mount zroot/home

# verify mountpoints
$ mount -t zfs
root/os/gentoo on /mnt/gentoo type zfs (rw,relatime,xattr,posixacl,casesensitive)
zroot/home on /mnt/gentoo/home type zfs (rw,relatime,xattr,posixacl,casesensitive)

# update device symlink
udevadm trigger

在 host OS 用 rsync 同步 tarball 和 EFI 文件到 /mnt/gentoo

# host OS
cd /path/to/tarball
curl -L https://get.zfsbootmenu.org/efi -o BOOTX64.EFI

rsync -av stage3-amd64-desktop-systemd-*.tar.xz gentoo:/mnt/gentoo/stage3.tar.xz
rsync -av BOOTX64.EFI gentoo:/mnt/gentoo/BOOTX64.EFI

现在解压 stage3 tarball

cd /mnt/gentoo

date # 确认时间正常

tar xpvf stage3.tar.xz --xattrs-include='*.*' --numeric-owner -C /mnt/gentoo
rm stage3.tar.xz

vim /mnt/gentoo/etc/portage/make.conf

Admin CD 自带 vim,这点不错。完整 make.conf#Portage

Chroot 准备工作:

cp --dereference /etc/resolv.conf /mnt/gentoo/etc/
cp /etc/hostid /mnt/gentoo/etc

arch-chroot /mnt/gentoo

💡 Tip

后面如果暂停,可以从这里继续。重新挂载并进入 chroot 即可,参考命令如下。

zpool import -N -R /mnt/gentoo zroot
zfs mount zroot/os/gentoo
zfs mount zroot/home
udevadm trigger

cd /mnt/gentoo
arch-chroot /mnt/gentoo

4-5. Chroot

ℹ️ Note

下面的步骤都是在 Chroot 环境中执行的,确保不是在 /mnt/gentoo 外部!

挂载 BL:

mkdir /efi
mount /dev/vda1 /efi

配置 Portage:

💡 Tip

为了避免东一榔头西一锤子的混乱局面,所有 Portage/USE flags 均记录在 #Portage/#USE,有的内容可能在正文中省略。

# download official ebuilds snapshot
emerge-webrsync

# setup mirror
emerge --oneshot app-portage/mirrorselect
# choose utsc https
mirrorselect -i -o >> /etc/portage/make.conf

# install vim
emerge app-editors/vim app-vim/vim-spell-en

# check news
eselect news list
eselect news read

# choose profile
$ eselect profile list
 [24]  default/linux/amd64/23.0/desktop/systemd (stable) *

Binpkg

最关键的步骤来了,使用预编译二进制:

# /etc/portage/binrepos.conf/gentoobinhost.conf
# https://www.gentoo.org/downloads/mirrors/#CN

[binhost]
priority = 9999
# sync-uri = https://distfiles.gentoo.org/releases/<arch>/binpackages/<profile>/x86-64/
sync-uri = https://mirrors.ustc.edu.cn/gentoo/releases/amd64/binpackages/23.0/x86-64/

然后在 Portage 配置加入下面的内容,默认使用二进制:

# /etc/portage/make.conf

# use binary package
FEATURES="${FEATURES} getbinpkg"
# require signatures
FEATURES="${FEATURES} binpkg-request-signature"

配置验证密钥:

getuto

后面安装软件包的时候就可以使用 --getbinpkg / -g 避免本机编译:

emerge -g app-editors/vim app-vim/vim-spell-en

💡 Tip

后文有的用 -g 有的没用,并不是瞎写的,过于底层或者编译很快的软件包选择编译,需要耗时配置/编译且不那么底层的就直接下载二进制包。

6-7. Chroot·续

这里先不重建 world,但 systemd 还是得搞。

时区:

# this IS correct!
# ../ is "relative to the link location", NOT the current directory
ln -sf ../usr/share/zoneinfo/Asia/Shanghai /etc/localtime

语言:

sudo tee -a /etc/locale.gen &>/dev/null << "EOF"
en_US.UTF-8 UTF-8
fr_FR.UTF-8 UTF-8
ja_JP.UTF-8 UTF-8
ko_KR.UTF-8 UTF-8
zh_CN.GB18030 GB18030
zh_CN.GBK GBK
zh_CN.UTF-8 UTF-8
EOF

locale-gen

eselect locale list
eselect locale set 4
env-update && source /etc/profile && export PS1="(chroot) ${PS1}"

安装固件和 CPU 微代码:

emerge --autounmask-write sys-kernel/linux-firmware
emerge --config sys-kernel/gentoo-kernel # rebuild kernel
emerge -g sys-firmware/sof-firmware sys-firmware/intel-microcode

安装 bootloader 并生成 Initramfs:

💡 Tip

文档列了两种实现:Debian 的 installkernel 和 SystemD 的 kernel-install。虽然要安装的软件包名为 sys-kernel/installkernel,实际上两种都包含在内,使用 SystemD 时不需要手动修改为 kernel-install

emerge sys-kernel/installkernel

终于到了安装内核的环节,这里需要回到 ZFS/rootfs Kernel 篇章 安装:

# install distributed kernel and required zfs module
emerge sys-kernel/gentoo-kernel-bin
emerge sys-fs/zfs sys-fs/zfs-kmod

# configure dracut
mkdir -p /etc/dracut.conf.d
vim /etc/dracut.conf.d/zol.conf
# /etc/dracut.conf.d/zol.conf
nofsck="yes"
add_dracutmodules+=" zfs "

Rebuild initramfs:

emerge --config sys-kernel/gentoo-kernel-bin

之后又回到 handbook:

# emerge sys-kernel/gentoo-sources

$ eselect kernel list
Available kernel symlink targets:
  [1]   linux-6.12.21-gentoo-dist *

接着创建分区表,注意 ZFS 分区不需要填写,EFI 也不能自动挂载 (noauto):

$ blkid

/dev/vda2: LABEL="zroot" UUID="14585777708174386111" UUID_SUB="13091064257831750964" BLOCK_SIZE="4096" TYPE="zfs_member" PARTUUID="19a5e0ec-f490-4a4c-8d07-501688fc8827"
/dev/vda1: UUID="ADD5-5227" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="6ec96ff1-0b5f-464f-9bdc-523283542772"
# /etc/fstab
#UUID=14585777708174386111       /       zfs     0       1
UUID=ADD5-5227  /efi       vfat    noauto        0       2
tmpfs   /tmp    tmpfs   defaults,nosuid,nodev   0       0

配置系统文件:

echo gentoo > /etc/hostname

emerge net-misc/dhcpcd
systemctl enable dhcpcd

vim /etc/hosts
# 127.0.0.1 gentoo
# ::1 gentoo

passwd

# init
systemd-machine-id-setup

$ systemd-firstboot --prompt
en

systemctl preset-all --preset-mode=enable-only

8. 安装系统工具

SystemD 大而全,不少可以跳过,剩下必需的:

emerge -g sys-apps/mlocate # file index
emerge -g app-shells/bash-completion

# SSH
systemctl enable sshd
systemctl enable getty@tty1.service

# NTPD (ntpd-rs 需要 Rust toolchain,告辞)
emerge net-misc/chrony
systemctl enable chronyd.service

# filesystem: ext4, ntfs
# https://wiki.gentoo.org/wiki/Filesystem
emerge sys-fs/e2fsprogs sys-fs/ntfs3g sys-block/io-scheduler-udev-rules

# wireless
emerge net-wireless/iw net-wireless/wpa_supplicant

配置新用户:

foo=ciallo
useradd -m -G wheel,audio,video,portage,usb,cdrom -s /bin/bash --create-home $foo
passwd $foo

# configure sudo
emerge app-admin/sudo
VISUAL=vim visudo
unset foo

9. 配置 Bootloader

这里又要回到 ZFS/rootfs

# enable zfs support
echo "sys-boot/grub libzfs" > /etc/portage/package.use/10grub

# emerge sys-boot/grub
emerge --update --newuse sys-boot/grub # rebuild grub

zfs set org.zfsbootmenu:commandline="quiet loglevel=4" zroot/os

mkdir -p /efi/EFI/BOOT
mv BOOTX64.EFI /efi/EFI/BOOT/BOOTX64.EFI
emerge sys-boot/efibootmgr

(chroot) livecd / # efibootmgr -c -d /dev/vda1 -p 1 -L "ZFSBootMenu" -l \\EFI\\BOOT\\BOOTX64.EFI

$ grub-install --target=x86_64-efi --efi-directory=/efi --removable
Installing for x86_64-efi platform.
Installation finished. No error reported.

grub-mkconfig -o /boot/grub/grub.cfg

Time to exit chroot:

(chroot) livecd # exit

cd
# umount -l /mnt/gentoo/dev{/shm,/pts,}
umount -n -R /mnt/gentoo
zpool export zroot

Now remove the live image and reboot.

10. 收尾

💡 Tip

如果到这里重启能够顺利进入系统,建议先关机备份,或者建个硬盘快照,方便后续玩炸了随时回滚。

首先配置 mDNS,便于后续通过 gentoo.local SSH,不用再反复修改 IP。

Chroot·续没有重建 world,既然能够正常启动,现在开始重建。下面使用 --getbinpkg 参数,部分软件包默认会忽略,始终从源码编译,列表很清楚,觉得不对就配置到 /etc/portage/package.use

# update world
sudo emerge --ask --update --deep --newuse --getbinpkg @world # sudo emerge -auDNg @world
# remove obsolete packages
sudo emerge --ask --depclean

配置默认 editor:

eselect editor list
sudo eselect editor set vim
. /etc/profile

Doas,Gentoo 默认不支持 persist,使用 USE flag 编译支持 persist 特性的二进制:

echo "app-admin/doas persist" | sudo tee /etc/portage/package.use/10doas
sudo emerge app-admin/doas

sudo -e /etc/doas.conf
sudo chown -c root:root /etc/doas.conf
sudo chmod -c 0400 /etc/doas.conf
doas eselect (Ctrl+C)
doas eselect # 这里应该不需要密码

repos.conf:

doas emerge app-eselect/eselect-repository dev-vcs/git
doas eselect repository list
doas eselect repository enable gentoo git
# edit repos.conf per TUNA instruction
sudo -e /etc/portage/repos.conf/eselect-repo.conf

doas mv /var/db/repos/gentoo /var/db/repos/gentoo.old
doas emerge --sync
doas rm -r /var/db/repos/gentoo.old
# /etc/portage/repos.conf/eselect-repo.conf

[gentoo]
location = /var/db/repos/gentoo
sync-type = git
# sync-uri = https://github.com/gentoo-mirror/gentoo.git
sync-uri = https://mirrors.tuna.tsinghua.edu.cn/git/gentoo-portage.git

Python

刚好赶在 Python3.13 即将于 2025-05-01 变为默认 Python 版本 的窗口期。直接全部改为 python3_13 ZFS 会报错,明明 sys-fs/zfs 已经支持这个 target,没办法,只能单独配置:

# /etc/portage/pacakge.use/10python

# force Python3.13 earlier
*/* PYTHON_TARGETS: -* python3_13
*/* PYTHON_SINGLE_TARGET: -* python3_13
sys-fs/zfs PYTHON_TARGETS: -* python3_12 python3_13
# sys-fs/zfs PYTHON_SINGLE_TARGET: -* python3_12

或者参考下面的配置逐步更新,更安全但需要重建三次 world,三倍耗时,我肯定不这么干:

# /etc/portage/pacakge.use/10safepython

# safer approach (take much longer)
# First, enable both Python 3.12 and Python 3.13, and then upgrade
*/* PYTHON_TARGETS: -* python3_12 python3_13
*/* PYTHON_SINGLE_TARGET: -* python3_12

# Then switch PYTHON_SINGLE_TARGET and run the second batch of upgrades
*/* PYTHON_TARGETS: -* python3_12 python3_13
*/* PYTHON_SINGLE_TARGET: -* python3_13

# Finally, switch to the final version and upgrade
*/* PYTHON_TARGETS: -* python3_13
*/* PYTHON_SINGLE_TARGET: -* python3_13

升级命令:

sudo emerge --ask --depclean
sudo emerge -1UDg @world
sudo emerge --ask --depclean

提前更新的麻烦就是 2025-05-01 默认 Python 版本变更后,需要记得删除上面的配置,不然下次 Python3.14 变为默认 Python 版本时效果会变成 defer update。

Debug

6-7. Chroot·续,这里安装 sys-kernel/linux-firmware 不能用 -g,因为预编译的二进制不符合 USE flag,需要手动运行 dispatch-conf 更新配置:

$ dispatch-conf
u

# etc-update
/etc/portage/package.use/00video_cards
+# required by sys-kernel/gentoo-kernel-6.12.21::gentoo
+# required by virtual/dist-kernel-6.12.21::gentoo
+# required by sys-kernel/linux-firmware-20250311::gentoo
+# required by sys-kernel/linux-firmware (argument)
+>=sys-kernel/installkernel-50 dracut

完成配置 Bootloader 启动不能,排查半天,还是 gemini-2.5-pro 提醒说 admin cd 压根就没以 UEFI 模式启动。打开 virt-manager 一看还真是 BIOS 启动。一番搜索解决了 KVM + UEFI 的历史难题,libvirt 安装 void-vtoyboot 大概也能一并解决。

xi edk2-ovmf

virt-manager: Edit -> Preferences -> New VM -> x86 Firmware -> UEFI

看到这里没有 BIOS 选项不要担心,在创建 VM 时除了指定各种固件,也可以改回 BIOS。

启动正常:

ls /sys/firmware/efi/efivars/

❓ 收尾阶段 rebuild world,内核没有正确安装,提示 /boot/efi 没有挂载,重启直接 panic。

因为分区表写错了,Gentoo 各类文档写的都是 /efi,包括 ZFS 的那个 EFI 也是存到 /efi/EFI/BOOT/BOOTX64.EFI,从 /boot/efi 改回 /efi 然后重装一大堆东西修好了。

Portage

  • profile version 23.0 开始不再建议在 Make.conf 设置 CHOST
  • Dotfiles 新增 FCFLAGS/FFLAGS,删除 CHOST, PYTHON_SINGLE_TARGET, PYTHON_TARGETS
# /etc/portage/make.conf
# https://wiki.gentoo.org/wiki//etc/portage/make.conf
# c.f. /usr/share/portage/config/make.conf.example

COMMON_FLAGS="-O2 -pipe"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
FCFLAGS="${COMMON_FLAGS}"
FFLAGS="${COMMON_FLAGS}"
RUSTFLAGS="${RUSTFLAGS} -C target-cpu=native"

MAKEOPTS="-j5"
EMERGE_DEFAULT_OPTS="--keep-going=y --with-bdeps=y"
GRUB_PLATFORMS="efi-64" # GRUB + UEFI
ACCEPT_LICENSE="* -@EULA"
USE="dist-kernel" # post-install hook to rebuild kmod (e.g. ZFS)

# use binary package
FEATURES="${FEATURES} getbinpkg"
# require signatures
FEATURES="${FEATURES} binpkg-request-signature"

USE

配置 cpuid2cpuflags

emerge --oneshot app-portage/cpuid2cpuflags

cpuid2cpuflags

echo "*/* $(cpuid2cpuflags)" > /etc/portage/package.use/00cpu-flags

内核:

# automatically generate an initramfs on each kernel installation
echo "sys-kernel/installkernel grub dracut -systemd" >> /etc/portage/package.use/installkernel

ZFS:

# enable zfs support
echo "sys-boot/grub libzfs" > /etc/portage/package.use/10grub

显卡 挺麻烦的:

# /etc/portage/package.use/00video_cards
*/* VIDEO_CARDS: intel virgl
# required by sys-kernel/gentoo-kernel-6.12.21::gentoo
# required by virtual/dist-kernel-6.12.21::gentoo
# required by sys-kernel/linux-firmware-20250311::gentoo
# required by sys-kernel/linux-firmware (argument)
>=sys-kernel/installkernel-50 dracut

本地化:

  • LINGUAS: 用于语言显示?好像不设置也行?
  • L10N: 通常用于 language pack
  • 没搞懂怎么用,先不管
# echo "*/* LINGUAS: en_US zh_CN en zh" > /etc/portage/package.use/00local
# echo "*/* L10N: en-US zh-CN en zh" > /etc/portage/package.use/localization

杂项

ℹ️ Note

这里列的都是实操之后与 Gentoo 构建无关的收尾工作。

RUSTFLAGS

  • Gentoo 配置到 /etc/portage/make.conf
  • 顺带在 Termux 配置,直接 export
# termux.zsh
RUSTFLAGS="${RUSTFLAGS} -C target-cpu=native"
export RUSTFLAGS

  1. 这里选择 SystemD 是因为打算顺便折腾 systemd-nspawn,而且 Alpine 也使用 OpenRC,没什么稀奇的。 ↩︎

  2. 这其实是因为 Gentoo 本来就没有 installer,啥都需要手动操作…… ↩︎

  3. 对于 QEMU/virt-manager 而言,就是安装 OVMF 固件并配置默认启动方式为 UEFI,详见 #Debug ↩︎

  4. 做到这里才发现又下错镜像了,应该下 Admin CD 而不是 Minimal Installation CD。前者在 Advanced choices 里,带有 OpenZFS 相关工具。 ↩︎

Vinfall's Geekademy

Sine īrā et studiō


通过 virt-manager + OVMF 固件使用 UEFI 模式启动 Admin CD,安装 Gentoo (desktop+systemd profile) 并实现 ZFS on rootfs w/ UEFI。


发布 2025-04-25
更新 2025-04-28
全文 3532 字
签名 html asc

#compile #dev #distro #filesystem #gentoo #linux #setup