第一部分:准备安装介质
安装archiso工具
sudo pacman -S archiso
复制并自定义配置
# 复制官方配置
cp -r /usr/share/archiso/configs/releng/ ~/archlive
cd ~/archlive
修改包列表
# 删除不需要的包并添加新包
sed -i '/^linux$/d; /^linux-headers$/d; /^broadcom-wl$/d' packages.x86_64
echo -e "linux-lts\nlinux-lts-headers\nzfs-utils\nzfs-dkms" >> packages.x86_64
echo "packages.x86_64 文件已更新完成"
配置pacman源
# 在文件末尾添加archzfs仓库
cat >> pacman.conf << 'EOF'
[archzfs]
SigLevel = TrustAll Optional
Server = http://archzfs.com/$repo/$arch
EOF
pacman-key --recv-keys DDF7DB817396A49B2A2723F7403BD972F75D9D76
pacman-key --lsign-key DDF7DB817396A49B2A2723F7403BD972F75D9D76
# 更新包数据库
pacman -Sy
echo "pacman.conf 已自动配置archzfs仓库"
更新启动配置文件
# 定义需要修改的文件列表
config_files=(
"airootfs/etc/mkinitcpio.d/linux.preset"
"efiboot/loader/entries/01-archiso-x86_64-linux.conf"
"efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf"
"syslinux/archiso_pxe-linux.cfg"
"syslinux/archiso_sys-linux.cfg"
"grub/loopback.cfg"
)
# 批量处理所有配置文件
for file in "${config_files[@]}"; do
if [[ -f "$file" ]]; then
echo "正在更新 $file"
sed -i 's/vmlinuz-linux\([^-]\|$\)/vmlinuz-linux-lts\1/g; s/initramfs-linux/initramfs-linux-lts/g' "$file"
echo "✓ $file 已更新"
else
echo "⚠ 警告: $file 不存在,跳过"
fi
done
echo "所有启动配置文件已更新完成"
构建ISO
mkdir -p ~/isobuild
sudo mkarchiso -v -r -w /tmp/archiso-tmp -o ~/isobuild ~/archlive
构建完成后,ISO文件将位于 ~/isobuild
目录中。
第二部分:启动并配置网络环境
启动到Live环境
配置无线网络
iwctl
在iwctl命令行中:
device list
station wlan0 scan
station wlan0 get-networks
station wlan0 connect SSID_NAME
exit
设置系统时间
timedatectl set-ntp true
配置archzfs仓库和密钥(Live环境)
为了pacstrap安装zfs包,需要在Live环境中也配置archzfs:
# 添加archzfs仓库到Live环境的pacman.conf
cat >> /etc/pacman.conf << 'EOF'
[archzfs]
SigLevel = TrustAll Optional
Server = http://archzfs.com/$repo/$arch
EOF
# 添加ZFS密钥
pacman-key --recv-keys DDF7DB817396A49B2A2723F7403BD972F75D9D76
pacman-key --lsign-key DDF7DB817396A49B2A2723F7403BD972F75D9D76
# 更新包数据库
pacman -Sy
echo "Live环境archzfs配置完成"
启用SSH
passwd root # 设置root密码
systemctl start sshd
ip a # 查看IP地址
第三部分:磁盘分区
识别目标磁盘
ls /dev/disk/by-id
lsblk
fdisk -l
以下示例假设目标磁盘为 =/dev/nvme0n1=,请根据实际情况调整。
创建GPT分区表
gdisk /dev/nvme0n1
在gdisk中执行以下操作:
- 输入
o
创建新的GPT分区表 - 创建EFI系统分区:
- 输入
n
创建新分区 - 分区号:1(默认)
- 起始扇区:默认
- 结束扇区:+1G
- 分区类型:ef00(EFI System Partition)
- 输入
- 创建交换分区:
- 输入
n
创建新分区 - 分区号:2(默认)
- 起始扇区:默认
- 结束扇区:+32G
- 分区类型:8200(Linux swap)
- 输入
- 创建ZFS根分区:
- 输入
n
创建新分区 - 分区号:3(默认)
- 起始扇区:默认
- 结束扇区:默认(使用剩余空间)
- 分区类型:bf00(Solaris Root)
- 输入
- 输入
w
写入分区表并退出
格式化分区
# 格式化EFI分区
mkfs.fat -F32 /dev/nvme0n1p1
# 设置交换分区
mkswap /dev/nvme0n1p2
swapon /dev/nvme0n1p2
查看磁盘ID
ls -lh /dev/disk/by-id/
记录目标磁盘的by-id路径,用于ZFS配置。
第四部分:ZFS配置
创建ZFS存储池
zpool create -f \
-o ashift=12 \
-o autotrim=on \
-o compatibility=off \
-O acltype=posixacl \
-O compression=zstd \
-O relatime=on \
-O xattr=sa \
-O normalization=formD \
-O mountpoint=none \
-O canmount=off \
-O dnodesize=auto \
-O sync=standard \
-O primarycache=all \
-O secondarycache=all \
-O recordsize=128K \
-R /mnt \
zroot /dev/disk/by-id/nvme-SAMSUNG_SSD_970_EVO_Plus_1TB_S4EWNX0M123456A-part3
参数说明:
- =ashift=12=:针对4K扇区磁盘优化
- =autotrim=on=:自动启用TRIM(适用于SSD)
- =compression=zstd=:使用zstd压缩算法
- =relatime=on=:相对atime更新,性能更好
- =xattr=sa=:扩展属性存储在系统属性中
- =dnodesize=auto=:自动调整dnode大小
- =recordsize=128K=:默认记录大小,适合大多数用途
创建ZFS数据集
# 创建根容器数据集
zfs create -o mountpoint=none zroot/ROOT
# 创建系统根数据集
zfs create -o mountpoint=/ -o canmount=noauto -o compression=zstd -o recordsize=128K zroot/ROOT/root
# 创建用户相关数据集
zfs create -o mountpoint=/home -o compression=zstd -o recordsize=128K zroot/home
# 创建系统数据集
zfs create -o mountpoint=/var -o compression=zstd zroot/var
zfs create -o mountpoint=/var/log -o compression=zstd zroot/var/log
zfs create -o mountpoint=/var/cache -o compression=zstd zroot/var/cache
# 创建游戏数据集 - 大文件优化
zfs create \
-o mountpoint=/games \
-o compression=zstd \
-o recordsize=1M \
-o atime=off \
zroot/games
# 创建 Podman 数据集(rootful)- 小文件优化
zfs create \
-o mountpoint=/var/lib/containers \
-o compression=zstd \
-o recordsize=64K \
-o atime=off \
zroot/containers
# 创建临时文件数据集 - 性能优化
zfs create \
-o mountpoint=/tmp \
-o compression=off \
-o sync=disabled \
-o atime=off \
-o devices=off \
-o exec=on \
-o setuid=off \
zroot/tmp
# 创建SMB共享数据集 - 私有共享,性能优化(Samba 另行配置)
zfs create \
-o mountpoint=/share \
-o compression=zstd \
-o recordsize=1M \
-o atime=off \
zroot/share
验证数据集创建
zfs list -t filesystem
设置ZFS缓存文件
# 设置缓存文件
zpool set cachefile=/etc/zfs/zpool.cache zroot
重新导入ZFS池(确保配置正确)
swapoff -a
zpool export zroot
zpool import -d /dev/disk/by-id -R /mnt zroot -N
# 挂载文件系统
zfs mount zroot/ROOT/root
zfs mount -a
# 设置启动文件系统
zpool set bootfs=zroot/ROOT/root zroot
验证挂载
df -h
mount | grep zfs
第五部分:安装Arch Linux
挂载EFI分区
mkdir -p /mnt/boot
mount /dev/nvme0n1p1 /mnt/boot
# 重新启用交换分区
swapon /dev/nvme0n1p2
安装基础系统
pacstrap -K /mnt base base-devel linux-lts linux-lts-headers linux-firmware \
amd-ucode vim man-db man-pages texinfo grub efibootmgr \
networkmanager openssh git wget curl \
zfs-dkms zfs-utils plasma-meta sddm \
samba
说明:
- 使用
linux-lts
而非标准内核以确保ZFS兼容性 - 根据CPU类型选择
amd-ucode
或intel-ucode
- 直接安装桌面环境
plasma-meta
和显示管理器sddm
- 包含ZFS支持包
zfs-dkms
和zfs-utils
生成fstab
genfstab -U -p /mnt >> /mnt/etc/fstab
检查并编辑fstab
vim /mnt/etc/fstab
确保只保留EFI分区和swap分区的条目,移除ZFS相关条目(ZFS自己管理挂载)。
第六部分:系统配置
进入chroot环境
arch-chroot /mnt
配置时区
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
hwclock --systohc
配置语言环境
# 配置语言生成
cat > /etc/locale.gen << EOF
en_US.UTF-8 UTF-8
ja_JP.UTF-8 UTF-8
zh_CN.UTF-8 UTF-8
EOF
# 生成语言文件
locale-gen
# 设置系统语言
echo 'LANG=en_US.UTF-8' > /etc/locale.conf
配置网络
# 设置主机名
echo 'ganymede' > /etc/hostname
# 配置hosts文件
cat > /etc/hosts << EOF
127.0.0.1 localhost
::1 localhost
127.0.1.1 ganymede.localdomain ganymede
EOF
配置pacman和ZFS
# 添加archzfs仓库到pacman.conf
cat >> /etc/pacman.conf << 'EOF'
[archzfs]
SigLevel = TrustAll Optional
Server = http://archzfs.com/$repo/$arch
EOF
添加ZFS密钥:
pacman-key --recv-keys DDF7DB817396A49B2A2723F7403BD972F75D9D76
pacman-key --lsign-key DDF7DB817396A49B2A2723F7403BD972F75D9D76
配置initramfs
vim /etc/mkinitcpio.conf
修改HOOKS行为:
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block zfs filesystems)
确保keyboard在zfs之前,zfs在filesystems之前。
重新生成initramfs:
mkinitcpio -P
配置ZFS服务
# 生成host ID
zgenhostid $(hostid)
# 设置缓存文件
mkdir -p /etc/zfs
zpool set cachefile=/etc/zfs/zpool.cache zroot
# 启用ZFS服务
systemctl enable zfs.target
systemctl enable zfs-import-cache.service
systemctl enable zfs-mount.service
systemctl enable zfs-import.target
zgenhostid的作用与必要性: zgenhostid
用于生成ZFS系统的唯一主机ID,这个ID存储在 /etc/hostid
文件中。它的作用是:
- 防止意外导入属于其他主机的ZFS池,避免数据损坏
- 确保ZFS池只能被正确的主机导入和访问
- 在系统迁移时提供池所有权验证
- 是ZFS多主机环境下的安全机制
安装和配置GRUB
# 安装GRUB到EFI分区
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=ArchLinux
# 编辑GRUB配置
vim /etc/default/grub
修改GRUB_CMDLINE_LINUX_DEFAULT行:
GRUB_CMDLINE_LINUX_DEFAULT="quiet root=ZFS=zroot/ROOT/root"
生成GRUB配置:
grub-mkconfig -o /boot/grub/grub.cfg
创建用户
# 设置环境变量(请替换为实际用户名)
user_new="YOUR_USERNAME"
useradd -m -G wheel -s /bin/bash $user_new
passwd $user_new
配置sudo权限:
EDITOR=vim visudo
取消注释并修改以下行:
%wheel ALL=(ALL:ALL) NOPASSWD: ALL
设置/games目录权限
# 创建游戏目录并设置权限,确保uid1000用户可写入
mkdir -p /games
chown 1000:1000 /games
chmod 755 /games
创建用户缓存和容器数据集
# 创建用户缓存数据集 - 缓存优化,性能导向
zfs create \
-o mountpoint="/home/${user_new}/.cache" \
-o compression=zstd \
-o recordsize=64K \
-o atime=off \
-o sync=disabled \
zroot/cache-${user_new}
# 创建 Podman 数据集(rootless)- 小文件优化
zfs create \
-o mountpoint="/home/${user_new}/.local/share/containers" \
-o compression=zstd \
-o recordsize=64K \
-o atime=off \
zroot/containers-${user_new}
重新挂载数据集
# 退出chroot环境
exit
# 重新挂载所有ZFS数据集
zfs mount -a
# 重新进入chroot环境
arch-chroot /mnt
设置用户目录权限
# 重新设置环境变量(请替换为实际用户名)
user_new="YOUR_USERNAME"
# 设置用户目录权限
chown 1000:1000 "/home/${user_new}/.cache"
chmod 755 "/home/${user_new}/.cache"
chown 1000:1000 "/home/${user_new}/.local/share/containers"
chmod 755 "/home/${user_new}/.local/share/containers"
配置SMB共享
# 设置/share目录权限(仅uid=1000用户可访问)
chown 1000:1000 /share
chmod 700 /share
# 配置Samba配置文件
cat > /etc/samba/smb.conf << 'EOF'
[global]
workgroup = WORKGROUP
security = user
map to guest = never
server string = Arch ZFS Server
[share]
path = /share
guest ok = no
read only = no
valid users = ${user_new}
comment = Private ZFS Share
create mask = 0660
directory mask = 0770
EOF
# 为用户设置SMB密码
smbpasswd -a ${user_new}
# 验证Samba配置
testparm -s
# 启用SMB服务
systemctl enable smb
systemctl enable nmb
echo "SMB共享配置完成:\\\\server\\share"
启用基本服务
systemctl enable NetworkManager
systemctl enable sddm # 启用SDDM显示管理器
Hibernation配置
# 获取swap分区的UUID
SWAP_UUID=$(blkid -s UUID -o value /dev/nvme0n1p2)
# 使用sed添加resume参数到GRUB配置
sed -i "s/root=ZFS=zroot\/ROOT\/root/& resume=UUID=$SWAP_UUID/" /etc/default/grub
# 在mkinitcpio.conf中添加resume钩子
sed -i '/^HOOKS=/ { /resume/!s/ zfs/ resume zfs/ }' /etc/mkinitcpio.conf
# 重新生成initramfs
mkinitcpio -P
# 重新生成GRUB配置
grub-mkconfig -o /boot/grub/grub.cfg
echo "Hibernation配置完成"
配置ZFS定期维护服务
# OpenZFS 2.1.3+ 已包含内置的scrub定时器,无需手动创建
# 创建ZFS trim服务
cat > /etc/systemd/system/zfs-trim@.service << 'EOF'
[Unit]
Description=zpool trim on %i
Documentation=man:zpool-trim(8)
Requires=zfs.target
After=zfs.target
ConditionACPower=true
ConditionPathIsDirectory=/sys/module/zfs
[Service]
Nice=19
IOSchedulingClass=idle
KillSignal=SIGINT
ExecStart=/bin/sh -c '\
if /usr/bin/zpool status %i | grep "trimming"; then\
exec /usr/bin/zpool wait -t trim %i;\
else exec /usr/bin/zpool trim -w %i; fi'
ExecStop=-/bin/sh -c '/usr/bin/zpool trim -s %i 2>/dev/null || true'
[Install]
WantedBy=multi-user.target
EOF
# 创建ZFS trim定时器(每月执行)
cat > /etc/systemd/system/zfs-trim@.timer << 'EOF'
[Unit]
Description=Monthly zpool trim on %i
[Timer]
OnCalendar=monthly
AccuracySec=1h
Persistent=true
[Install]
WantedBy=multi-user.target
EOF
# 启用内置的scrub定时器和自定义的trim定时器(针对zroot池)
systemctl enable zfs-scrub-monthly@zroot.timer
systemctl enable zfs-trim@zroot.timer
echo "ZFS定期维护服务配置完成"
最终验证
# 验证ZFS状态
zpool status
zfs list
# 验证initramfs包含ZFS和resume
lsinitcpio /boot/initramfs-linux-lts.img | grep -E "(zfs|resume)"
# 验证GRUB配置
grep -E "(zroot|resume)" /boot/grub/grub.cfg
# 验证定时器
systemctl list-timers | grep zfs
第七部分:创建Pacman快照管理系统
创建快照管理脚本
cat > /usr/local/bin/zfs-pacman-snapshot << 'EOF'
#!/usr/bin/env bash
# /usr/local/bin/zfs-pacman-snapshot
# Create and prune ZFS snapshots around pacman transactions.
# Snapshots are named: pacman_{pre|post}_YYYYmmdd_HHMMSS
# Per-dataset retention: keep newest MAX_SNAPSHOTS, prune older ones.
set -uo pipefail
SNAPSHOT_PREFIX="pacman"
MAX_SNAPSHOTS=50
DATASETS=("zroot/ROOT/root" "zroot/home")
LOG_FILE="/var/log/zfs-pacman-snapshots.log"
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
# ----- utils -----
log() {
local msg="$1"
# ensure dir exists
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
printf '[%s] %s\n' "$(date '+%F %T')" "$msg" >>"$LOG_FILE"
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || { log "missing command: $1"; return 1; }
}
# Single-instance lock to avoid overlapping hooks
acquire_lock() {
exec 9>/run/zfs-pacman-snapshot.lock || exec 9>/tmp/zfs-pacman-snapshot.lock
flock -n 9 || { log "another instance is running; skipping"; return 1; }
}
# ----- core -----
create_snapshot() {
local phase="$1" # "pre" or "post"
local snap="${SNAPSHOT_PREFIX}_${phase}_${TIMESTAMP}"
log "creating ${phase} snapshots with name: ${snap}"
for ds in "${DATASETS[@]}"; do
if zfs list -H -o name "$ds" >/dev/null 2>&1; then
local full="${ds}@${snap}"
if zfs snapshot "$full" >/dev/null 2>&1; then
log "created: $full"
else
log "error creating: $full"
fi
else
log "dataset not found, skip: $ds"
fi
done
}
cleanup_snapshots() {
log "pruning old pacman snapshots (keep newest ${MAX_SNAPSHOTS} per dataset)"
for ds in "${DATASETS[@]}"; do
zfs list -H -o name "$ds" >/dev/null 2>&1 || continue
# List snapshots for this exact dataset, newest first.
# Use -r to allow listing children then filter exact match on the left of '@'.
# shellcheck disable=SC2016
mapfile -t snaps < <(
zfs list -H -t snapshot -o name -S creation -r "$ds" 2>/dev/null \
| awk -v ds="$ds" -v pfx="$SNAPSHOT_PREFIX" -F'@' '$1==ds && $2 ~ "^"pfx"_" {print $0}'
)
local count="${#snaps[@]}"
if (( count <= MAX_SNAPSHOTS )); then
log "dataset $ds: $count snapshots, no pruning needed"
continue
fi
local to_delete=$((count - MAX_SNAPSHOTS))
log "dataset $ds: $count snapshots, deleting $to_delete older snapshots"
# Delete from index MAX_SNAPSHOTS onward (older ones)
local deleted=0
for ((i=MAX_SNAPSHOTS; i<count; i++)); do
s="${snaps[$i]}"
if zfs destroy "$s" >/dev/null 2>&1; then
((deleted++))
log "destroyed: $s"
else
log "failed to destroy: $s"
fi
done
log "dataset $ds: prune complete, deleted $deleted"
done
}
main() {
# Defensive checks. Never abort pacman; just log and exit 0.
require_cmd zfs || return 0
acquire_lock || return 0
case "${1:-}" in
pre)
create_snapshot "pre"
;;
post)
create_snapshot "post"
cleanup_snapshots
;;
*)
echo "Usage: $0 {pre|post}"
echo " pre - create snapshots before pacman transaction"
echo " post - create snapshots after pacman transaction and prune old ones"
;;
esac
return 0
}
main "$@" || true
exit 0
EOF
# 设置执行权限
chmod +x /usr/local/bin/zfs-pacman-snapshot
测试快照脚本
# 测试创建pre和post快照
echo "测试创建快照..."
/usr/local/bin/zfs-pacman-snapshot pre
sleep 2
/usr/local/bin/zfs-pacman-snapshot post
echo "列出创建的快照:"
zfs list -t snapshot | grep pacman
echo "删除测试快照..."
zfs list -t snapshot | grep pacman | awk '{print $1}' | xargs -r -n1 zfs destroy
echo "验证快照已删除:"
zfs list -t snapshot | grep pacman || echo "无pacman快照,测试完成"
创建Pacman快照钩子
# 创建pacman hook目录
mkdir -p /etc/pacman.d/hooks
# 创建pre-transaction hook
cat > /etc/pacman.d/hooks/00-zfs-pre.hook << 'EOF'
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *
[Action]
Description = Creating ZFS snapshot before package transaction...
When = PreTransaction
Exec = /usr/local/bin/zfs-pacman-snapshot pre
EOF
# 创建post-transaction hook
cat > /etc/pacman.d/hooks/99-zfs-post.hook << 'EOF'
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *
[Action]
Description = Creating ZFS snapshot after package transaction...
When = PostTransaction
Exec = /usr/local/bin/zfs-pacman-snapshot post
EOF
第八部分:完成安装
退出chroot并清理
# 退出chroot环境
exit
# 卸载文件系统
umount /mnt/boot
zfs umount -a
zpool export zroot
重启系统
systemctl reboot
第九部分:首次启动后配置
验证系统状态
# 检查ZFS状态
sudo zpool status
sudo zfs list
# 检查挂载点
df -h
mount | grep zfs
# 检查服务状态
systemctl status zfs.target
systemctl status NetworkManager
systemctl status sddm
# 检查定时器状态
systemctl list-timers | grep zfs
启动ZFS定期维护服务
# 启动定时器
sudo systemctl start zfs-scrub-monthly@zroot.timer
sudo systemctl start zfs-trim@zroot.timer
# 验证定时器状态
systemctl status zfs-scrub-monthly@zroot.timer
systemctl status zfs-trim@zroot.timer
# 查看下次执行时间
systemctl list-timers | grep zfs
验证/games目录权限
# 检查/games目录权限
ls -la /games
id # 确认当前用户ID
# 测试写入权限(假设当前用户是uid1000)
touch /games/test_file
rm /games/test_file
echo "✓ /games目录权限配置正确"
配置SSH公钥认证
# 在需要SSH连接的客户端机器上,复制公钥到服务器
ssh-copy-id username@server_ip
# 在服务器上配置SSH仅允许公钥登录
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config
# 启用SSH服务
sudo systemctl enable sshd
sudo systemctl restart sshd
echo "SSH公钥认证配置完成"
验证SMB共享
# 检查SMB服务状态
sudo systemctl status smb
sudo systemctl status nmb
# 验证ZFS SMB共享配置
zfs get sharesmb zroot/share
# 验证Samba配置文件语法
sudo testparm -s
# 查看共享列表
smbclient -L localhost -U username
# 测试共享访问
ls -la /share
echo "SMB共享验证完成"
SMB用户管理
# 查看当前所有SMB用户
sudo pdbedit -L
# 查看特定用户的详细信息
sudo pdbedit -L -v -u username
# 添加新的SMB用户(用户必须先是系统用户)
sudo smbpasswd -a new_username
# 更改SMB用户密码
sudo smbpasswd username
# 禁用SMB用户(不删除)
sudo smbpasswd -d username
# 启用被禁用的SMB用户
sudo smbpasswd -e username
# 删除SMB用户
sudo smbpasswd -x username
# 检查SMB配置是否合法
sudo testparm
# 查看当前SMB连接状态
sudo smbstatus
echo "SMB用户管理完成"
系统更新
sudo pacman -Syu
安装yay和zrepl
# 安装yay-bin(AUR helper)
sudo pacman -S --needed git base-devel && git clone https://aur.archlinux.org/yay-bin.git && cd yay-bin && makepkg -si
# 使用yay安装zrepl
yay -S zrepl
配置zrepl自动快照系统
sudo mkdir -p /etc/zrepl
sudo tee /etc/zrepl/zrepl.yml << 'EOF'
global:
logging:
- type: stdout
level: info
format: human
jobs:
- name: "system_snapshots"
type: snap
filesystems: {
"zroot/ROOT/root": true,
"zroot/home<": true
}
snapshotting:
type: periodic
prefix: hourly_
interval: 1h
pruning:
keep:
- type: regex
regex: "^pacman_.*" # 保留由 pacman 自动快照创建的快照
- type: last_n
count: 24 # 保留最近24个小时快照
- name: "daily_snapshots"
type: snap
filesystems: {
"zroot/ROOT/root": true,
"zroot/home<": true
}
snapshotting:
type: periodic
prefix: daily_
interval: 24h
pruning:
keep:
- type: regex
regex: "^pacman_.*" # 保留由 pacman 自动快照创建的快照
- type: last_n
count: 30 # 保留最近30天的每日快照
- name: "weekly_snapshots"
type: snap
filesystems: {
"zroot/ROOT/root": true,
"zroot/home<": true
}
snapshotting:
type: periodic
prefix: weekly_
interval: 168h
pruning:
keep:
- type: regex
regex: "^pacman_.*" # 保留由 pacman 自动快照创建的快照
- type: last_n
count: 12 # 保留最近12周的每周快照
- name: "monthly_snapshots"
type: snap
filesystems: {
"zroot/ROOT/root": true,
"zroot/home<": true
}
snapshotting:
type: periodic
prefix: monthly_
interval: 720h
pruning:
keep:
- type: regex
regex: "^pacman_.*" # 保留由 pacman 自动快照创建的快照
- type: last_n
count: 12 # 保留最近12个月的每月快照
EOF
# 启用并启动zrepl服务
sudo systemctl enable zrepl
sudo systemctl start zrepl
# 注意:用户缓存数据集(zroot/cache-*)不包含在快照策略中
# 这些数据集被设计为临时缓存,不需要快照保护
安装常用软件
# 开发工具
sudo pacman -S code firefox
# 系统工具
sudo pacman -S htop neofetch tree
测试hibernation
# 检查swap状态
swapon --show
cat /proc/swaps
# 检查hibernation支持
cat /sys/power/disk
# 测试hibernation
sudo systemctl hibernate
配置zram压缩内存交换
# 安装zram-generator(现代统一的zram管理工具)
sudo pacman -S zram-generator
# 配置zram
sudo tee /etc/systemd/zram-generator.conf << 'EOF'
[zram0]
zram-size = ram * 0.25
compression-algorithm = zstd
swap-priority = 100
fs-type = swap
EOF
# 启动zram设备
sudo systemctl daemon-reload
sudo systemctl start systemd-zram-setup@zram0.service
sudo systemctl enable systemd-zram-setup@zram0.service
# 验证zram配置
echo "zram配置完成,当前状态:"
sudo zramctl
swapon --show
优化zram和磁盘交换配置
# 查看当前交换配置
swapon --show
cat /proc/swaps
# 确认zram优先级高于磁盘交换
# zram应该显示更高的优先级数值
# 设置内存交换倾向性(可选)
# 数值越低,越倾向于使用内存而非交换
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
# 立即应用设置
sudo sysctl vm.swappiness=10
# 验证设置
cat /proc/sys/vm/swappiness
echo "zram和交换优化完成"
echo "zram设备: $(sudo zramctl --output-all | grep -c zram)"
echo "总交换空间: $(free -h | grep Swap | awk '{print $2}')"
第十部分:ZFS维护管理
常用ZFS命令
# 查看存储池状态
zpool status
# 查看数据集
zfs list
# 手动创建快照
sudo zfs snapshot zroot/ROOT/root@manual-$(date +%Y%m%d)
# 列出快照
zfs list -t snapshot
# 删除快照
sudo zfs destroy zroot/ROOT/root@manual-20240101
ZFS维护操作
# 手动执行scrub
sudo zpool scrub zroot
# 查看scrub状态
sudo zpool status -v
# 停止正在进行的scrub
sudo zpool scrub -s zroot
# 手动执行trim
sudo zpool trim zroot
# 查看trim状态
sudo zpool status -t
# 停止正在进行的trim
sudo zpool trim -s zroot
# 查看ZFS ARC统计
cat /proc/spl/kstat/zfs/arcstats | grep -E "(hits|miss|size)"
# 查看压缩比
sudo zfs get compressratio zroot/ROOT/root
# 查看数据集使用情况
sudo zfs get used,available,referenced,compressratio
定时器管理
# 查看所有ZFS相关定时器
systemctl list-timers | grep zfs
# 查看scrub定时器详细信息
systemctl status zfs-scrub-monthly@zroot.timer
# 查看trim定时器详细信息
systemctl status zfs-trim@zroot.timer
# 手动触发scrub服务
sudo systemctl start zfs-scrub-monthly@zroot.service
# 手动触发trim服务
sudo systemctl start zfs-trim@zroot.service
# 查看服务日志
sudo journalctl -u zfs-scrub-monthly@zroot.service
sudo journalctl -u zfs-trim@zroot.service
性能监控
# ZFS性能统计
zpool iostat 1
# 实时监控ZFS I/O
zpool iostat -v 1
# ARC缓存统计
cat /proc/spl/kstat/zfs/arcstats
# 数据集使用情况
zfs get used,available,referenced,compressratio
# zrepl状态
sudo systemctl status zrepl
sudo journalctl -u zrepl -f
快照恢复操作
# 列出可用快照
zfs list -t snapshot | grep zroot/ROOT/root
# 回滚到特定快照(危险操作,会丢失快照后的更改)
sudo zfs rollback zroot/ROOT/root@pacman_pre_20240101_120000
# 克隆快照(安全操作)
sudo zfs clone zroot/ROOT/root@pacman_pre_20240101_120000 zroot/ROOT/recovery
# 挂载克隆的数据集
sudo zfs set mountpoint=/mnt/recovery zroot/ROOT/recovery
sudo zfs mount zroot/ROOT/recovery
# 比较当前系统与快照的差异
sudo zfs diff zroot/ROOT/root@pacman_pre_20240101_120000
第十一部分:故障排除
常见问题
问题1:启动时找不到ZFS池
# 手动导入池
sudo zpool import -f zroot
# 重新生成缓存文件
sudo zpool set cachefile=/etc/zfs/zpool.cache zroot
sudo systemctl restart zfs-import-cache
问题2:ZFS模块未加载
# 手动加载ZFS模块
sudo modprobe zfs
# 检查内核版本兼容性
uname -r
dkms status
问题3:快照创建失败
# 检查磁盘空间
df -h
zpool list
# 检查快照日志
tail -f /var/log/zfs-pacman-snapshots.log
# 手动清理快照
sudo zfs destroy zroot/ROOT/root@old_snapshot_name
问题4:pacman钩子不工作
# 检查钩子文件
ls -la /etc/pacman.d/hooks/
cat /etc/pacman.d/hooks/00-zfs-pre.hook
# 检查脚本权限
ls -la /usr/local/bin/zfs-pacman-snapshot
# 测试脚本
sudo /usr/local/bin/zfs-pacman-snapshot pre
问题5:scrub或trim失败
# 检查池状态
sudo zpool status -v
# 查看详细错误信息
sudo journalctl -u zfs-scrub@zroot.service -n 50
# 检查磁盘健康状态
sudo smartctl -a /dev/nvme0n1
# 手动停止并重新启动操作
sudo zpool scrub -s zroot
sudo zpool scrub zroot
问题6:定时器未按预期执行
# 检查定时器状态
systemctl status zfs-scrub-monthly@zroot.timer
systemctl status zfs-trim@zroot.timer
# 查看定时器日志
sudo journalctl -u zfs-scrub-monthly@zroot.timer
# 重新启用定时器
sudo systemctl disable zfs-scrub-monthly@zroot.timer
sudo systemctl enable zfs-scrub-monthly@zroot.timer
sudo systemctl start zfs-scrub-monthly@zroot.timer
紧急恢复
如果系统无法启动,可以使用制作的Live ISO:
- 启动到Live环境
- 配置archzfs仓库和密钥(参考第二部分2.4节)
- 导入ZFS池:=zpool import -R /mnt zroot=
- 挂载文件系统:=zfs mount zroot/ROOT/root && zfs mount -a=
- 挂载EFI分区:=mount /dev/nvme0n1p1 /mnt/boot=
- 进入chroot:=arch-chroot /mnt=
- 执行修复操作
系统回滚示例:
# 在Live环境中回滚到pacman操作前的快照
zpool import -R /mnt zroot
zfs rollback zroot/ROOT/root@pacman_pre_YYYYMMDD_HHMMSS
zfs mount zroot/ROOT/root
mount /dev/nvme0n1p1 /mnt/boot
arch-chroot /mnt
grub-mkconfig -o /boot/grub/grub.cfg
exit
reboot
常用命令速查
# ZFS管理
sudo zpool status # 查看存储池状态
sudo zfs list # 查看所有数据集
sudo zpool scrub zroot # 手动执行scrub
sudo zpool trim zroot # 手动执行trim
sudo systemctl status zrepl # 查看zrepl状态
# 定时器管理
systemctl list-timers | grep zfs # 查看ZFS定时器
sudo systemctl start zfs-scrub-monthly@zroot.service # 手动执行scrub
sudo systemctl start zfs-trim@zroot.service # 手动执行trim
# Hibernation
sudo systemctl hibernate # 休眠系统
# zram管理
sudo zramctl # 查看zram设备状态
sudo systemctl status systemd-zram-setup@zram0.service # 查看zram服务状态
cat /proc/sys/vm/swappiness # 查看交换倾向性设置
swapon --show # 显示所有交换设备(包括zram)
# 快照管理
sudo /usr/local/bin/zfs-pacman-snapshot pre # 手动创建pre快照
tail -f /var/log/zfs-pacman-snapshots.log # 查看快照日志
zfs list -t snapshot | grep pacman # 查看pacman快照
# 性能监控
zpool iostat 1 # 实时I/O统计
cat /proc/spl/kstat/zfs/arcstats | grep size # ARC缓存大小
sudo zfs get compressratio zroot/ROOT/root # 查看压缩比
# SMB共享管理
zfs get sharesmb zroot/share # 查看ZFS SMB共享配置
sudo systemctl status smb # 检查SMB服务状态
sudo testparm -s # 验证Samba配置语法
smbclient -L localhost -U username # 查看共享列表
sudo smbstatus # 查看当前SMB连接状态
ls -la /share # 检查共享目录权限
# SMB用户管理
sudo pdbedit -L # 查看所有SMB用户
sudo smbpasswd -a username # 添加SMB用户
sudo smbpasswd username # 更改SMB用户密码
sudo smbpasswd -d username # 禁用SMB用户
sudo smbpasswd -e username # 启用SMB用户
sudo smbpasswd -x username # 删除SMB用户
# 维护操作
sudo zpool status -v # 详细池状态(包含scrub信息)
sudo zpool status -t # 查看trim状态
sudo journalctl -u zfs-scrub-monthly@zroot.service # 查看scrub日志
sudo journalctl -u zfs-trim@zroot.service # 查看trim日志
附录:休眠唤醒设备管理
配置休眠唤醒设备(仅电源键唤醒)
在某些系统上,键盘、鼠标等USB设备可能会意外唤醒休眠状态,导致电池耗尽。以下配置确保只有电源键能够唤醒系统。
# 查看当前唤醒设备状态
cat /proc/acpi/wakeup
# 禁用USB控制器唤醒功能
# 根据你的系统,可能需要禁用以下设备(示例):
echo XHC0 | sudo tee /proc/acpi/wakeup # USB3.0 控制器1
echo XHC1 | sudo tee /proc/acpi/wakeup # USB3.0 控制器2
echo XHC2 | sudo tee /proc/acpi/wakeup # USB3.0 控制器3
echo XH00 | sudo tee /proc/acpi/wakeup # USB控制器
# 验证设置(disabled表示已禁用唤醒)
cat /proc/acpi/wakeup
测试休眠唤醒功能
# 休眠系统
sudo systemctl hibernate
# 休眠后,尝试以下操作验证:
# 1. 按键盘任意键 - 应该无法唤醒
# 2. 移动鼠标 - 应该无法唤醒
# 3. 按电源键 - 应该能正常唤醒系统
# 唤醒后检查休眠日志
sudo journalctl -b | grep -i hibernate
# 检查唤醒设备状态是否保持
cat /proc/acpi/wakeup | grep -E "(XHC|XH00)"
附录:Podman 常用命令与日常维护
基本信息与运行
podman info # 查看系统与存储信息
podman run --rm hello-world # 快速自检运行
镜像与容器管理
podman images # 列出镜像
podman ps -a # 列出容器(包含已停止)
podman pull alpine # 拉取镜像
podman run -d --name web -p 8080:80 nginx:alpine
podman logs -f web # 跟随日志
podman exec -it web sh # 进入容器
podman stop web && podman rm web
清理与空间回收
podman image prune -a # 清理未使用镜像
podman container prune # 清理已退出容器
podman volume ls # 查看卷
podman volume prune # 清理未使用卷
podman system df # 存储占用统计
podman system prune -a # 全面清理(谨慎)
Quadlet 自启(推荐,替代 podman generate)
Podman 现已推荐使用 Quadlet(.container 文件)而非 =podman generate systemd=。
- rootless 放置路径:=~/.config/containers/systemd/=
- rootful 放置路径:=/etc/containers/systemd/=
以 Caddy 为例,创建一个 =caddy.container=:
[Unit]
Description=Caddy file server
After=network-online.target
Wants=network-online.target
[Container]
Image=docker.io/caddy:latest
ContainerName=caddy
Volume=/share:/srv/share:ro
PublishPort=8080:8080
Exec=caddy file-server --root /srv/share --listen :8080 --browse
Pull=always
AutoUpdate=registry
[Service]
Restart=always
[Install]
WantedBy=default.target
Quadlet 运行机制要点:
- 段名:源文件使用 [Container];[X-Container] 仅出现在生成输出中。
- 其他段:可额外写入 [Service]、[Install],systemd 会照常解析。
- 重启策略:在 [Container] 中没有 Restart/RestartPolicy;需在 [Service] 中写 Restart=always(Podman 无 unless-stopped 与 always 的区别,always 等价)。
- 自启动:[Install] 中加入 WantedBy=default.target;执行 `systemctl –user daemon-reload` 后,Quadlet 会生成标记为 generated 的 .service 并挂到 default.target。generated 单元不能 enable,但已通过 [Install] 关联目标。
- 开机与 linger:
- 未启用 linger 时,user manager 只在登录后运行,容器登录后才启动。
- 启用 linger 后(`sudo loginctl enable-linger $USER`),user manager 开机即运行,容器随系统自启。
实际使用步骤:
写 .container 到 `~/.config/containers/systemd/`,包含 [Container]、[Service] Restart=always、[Install] WantedBy=default.target。
执行:
systemctl --user daemon-reload # 立即运行(可选,但建议执行一次以立刻生效) systemctl --user start caddy.service
确认:
systemctl --user status caddy.service
如需真正随开机启动(无需登录):
sudo loginctl enable-linger "$USER"
rootless 部署与启动:
mkdir -p ~/.config/containers/systemd
cp caddy.container ~/.config/containers/systemd/
systemctl --user daemon-reload
systemctl --user start caddy.service
# 查看状态/日志
systemctl --user status caddy.service
journalctl --user -u caddy -f
# (可选)开机自启用户服务
loginctl enable-linger "${USER}"
- rootful 部署与启动(系统服务):
sudo mkdir -p /etc/containers/systemd
sudo cp caddy.container /etc/containers/systemd/
sudo systemctl daemon-reload
sudo systemctl start caddy.service
- 自动更新(可选,对应 =AutoUpdate=registry=):
# rootless
systemctl --user enable --now podman-auto-update.timer
# rootful
sudo systemctl enable --now podman-auto-update.timer
提示:rootless 模式下直接映射到宿主 1024 以下端口(如 80)可能受限,若失败可:
- 使用 >=1024 的宿主端口(如 8080:80),或
- 调整 sysctl:sudo sysctl net.ipv4.ip_unprivileged_port_start=0,或改用 rootful。
存储位置(与 ZFS 数据集对应)
- rootful:/var/lib/containers/storage (zroot/containers)
- rootless:~/.local/share/containers/storage (zroot/containers-${user_arch})
创建系统服务持久化配置
# 创建systemd服务来持久化唤醒设备配置
sudo tee /etc/systemd/system/disable-wakeup.service << 'EOF'
[Unit]
Description=Disable USB device wakeup for hibernation
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo XHC0 > /proc/acpi/wakeup; echo XHC1 > /proc/acpi/wakeup; echo XHC2 > /proc/acpi/wakeup; echo XH00 > /proc/acpi/wakeup'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
# 启用服务
sudo systemctl enable disable-wakeup.service
sudo systemctl start disable-wakeup.service
# 验证服务状态
sudo systemctl status disable-wakeup.service
感谢您的耐心阅读!来选个表情,或者留个评论吧!