前言
上次用 Gentoo 还是上次 GentooWSL,中间隔了两三年,各方面水平都不可同日而语。最近在考虑 Void 之外的新发行版作为主系统,先花大力气试了试 FreeBSD/GhostBSD,ZFS 体验极佳,可惜硬件支持远逊于 Linux。来回对比,可能还是 Gentoo 比较符合要求,再次尝试,同时使用 ZFS 作为 rootfs 并启用 UEFI。
文档
- Downloads: Admin CD + Stage 3 (desktop profiles | systemd1)
- Gentoo AMD64 Handbook
- Gentoo Linux 手册:安装 Gentoo
- ZFS/rootfs
第三方教程:
- Gentoo 安装教程,make.conf 配置可以看看,其他有点过时
- Setting up Gentoo in WSL,也有点简略,因为是 WSL 环境,步骤和虚拟机不太一样
- 从零开始:GentooLinux 新手安装教程,有点照本宣科,和官方文档没区别,反而简略了不少内容
LiveCD
开始下了 LiveGUI USB Image,然鹅基于 KDE,体积过于庞大。
而且什么都有多份,浏览器三四个,聊天软件七八个,编辑器也一大堆。
感觉不错的就 Kdenlive 和 ghostwriter,其他都是老熟人。
这是纯 LiveCD,没有安装选项 2,于是换回 Minimal Installation CD Admin CD。
步骤
安装步骤列表,#实操 章节的划分标准,见于 About the Gentoo Linux Installation。
Step | Result |
---|---|
1 | 启动镜像 |
2 | 联网 |
3 | 分区 |
4 | 准备 Chroot |
5 | 配置编译 (Portage, USE, binpkg) |
6 | 安装内核 (kernel, initramfs via dracut, zfs kmod) |
7 | 配置系统 |
8 | 安装系统工具 |
9 | 配置 bootloader |
10 | 收尾 |
实操
1-2. 准备
- 官网/镜像站下载 Admin CD + Stage 3 (desktop profiles | systemd),还有 UEFI 使用的 BOOTX64.EFI
- Admin CD 用于启动,只有这个和最大的 LiveGUI USB Image 内置 ZFS 工具
- tarball/EFI 直接 rsync 同步到虚拟机
- 通读上面贴的文档,了解大概的流程
- 以 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
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 构建无关的收尾工作。
- Gentoo 配置到
/etc/portage/make.conf
- 顺带在 Termux 配置,直接 export
# termux.zsh
RUSTFLAGS="${RUSTFLAGS} -C target-cpu=native"
export RUSTFLAGS