说实话,我刚入手 Fedora Silverblue 的时候,真的被它惊艳到了。那种不可变系统的“承诺感”,那种每次更新后总能稳稳当当开机的安全感,简直是 Linux 桌面用户的福音。但好景不长,大概用了两周,我就发现了一个让我抓狂的问题:慢。
不是那种卡死的慢,而是一种黏糊糊的、拖泥带水的慢。特别是当我打开 GNOME Terminal,输入 docker ps 或者 podman play kube myapp.yaml 的时候,那个等待时间长得让我怀疑人生。有时候启动一个轻量的 Nginx 容器都要好几秒,这哪里是容器化了?这简直是“大象跳舞”。
我开始排查,CPU 没满载,内存也充裕,网络也正常。那到底是谁在拖后腿?经过无数次的 iotop 观察、dmesg 日志翻阅,以及无数次在 IRC 和论坛里的“蹲坑”,我终于摸到了一些门道。今天我就把这些压箱底的经验,毫无保留地分享给你。这不仅仅是一篇教程,更是我踩过的所有坑的总结。
先别急着动刀:Silverblue 的特殊性
在开始调整内核参数之前,我们必须先明确一点:Fedora Silverblue 是不可变操作系统(Immutable OS)。
这意味着什么?意味着你不能像 Fedora Workstation 或者 Ubuntu 那样,随便 sudo dnf install 一个内核模块,或者随便修改 /etc/sysctl.conf 然后重启生效。Silverblue 的核心设计理念是“原子更新”,系统分区的文件是只读的。
所以,传统的“改配置文件重启”这条路,在 Silverblue 上走不通,或者说,走起来非常别扭,而且容易在下次系统更新后被覆盖。
正确的姿势:用 rpm-ostree 和 bootc
对于 Silverblue,我们有两种主要的方式来持久化内核参数:
rpm-ostree内核追加参数(Kernel Options):这是最直接的方法。你可以在系统启动时,给内核命令行添加参数。这些参数会永久保存在系统的 bootloader 配置中(GRUB 或 systemd-boot),即使系统更新,这些参数也会被保留下来。bootc容器化根文件系统:这是 Fedora 最新的方向。如果你完全拥抱容器化,可以考虑用bootc来构建一个包含你优化配置的新镜像。但对于大多数普通用户,方法 1 就足够了。
重要警告:修改内核参数是有风险的。虽然下面提供的参数都是相对安全的调优选项,但在操作前,请务必确保你有恢复的能力(比如知道如何进入 Rescue Mode,或者有一个备份的 ISO)。
第一步:诊断——确认瓶颈在哪里
在我给出具体参数之前,我想让你先做个小实验,确认我们的方向是对的。打开终端(在 Silverblue 上,推荐使用 gnome-terminal 或者 kitty),运行以下命令:
# 检查当前的 I/O 调度器
cat /sys/block/sda/queue/scheduler
# 注意:如果你的磁盘是 NVMe,设备名可能是 nvme0n1,对应的路径是 /sys/block/nvme0n1/queue/scheduler
# 查看 I/O 统计(需要安装 iotop,如果没装可以跳过)
sudo iotop -o
如果你发现 I/O 等待(%IO)很高,或者调度器是 bfq(Balance Fair Queueing)而你的磁盘是 NVMe SSD,那么恭喜你,你找对方向了。bfq 对于机械硬盘(HDD)是非常优秀的调度器,但对于 NVMe SSD 来说,它过于“重量级”了,会带来不必要的延迟。
另外,运行这个命令看看你的容器启动慢是否和 DNS 解析有关:
time podman pull docker.io/library/nginx
如果 pull 过程很快,但 run 过程很慢,那问题大概率出在存储驱动或内核参数上。如果 pull 也很慢,那可能是网络或 DNS 问题。
第二步:调整 I/O 调度器——NVMe 用户的福音
对于 NVMe SSD,none 或 mq-deadline 通常是比 bfq 更好的选择。none 意味着让磁盘控制器自己管理队列,而 NVMe 控制器通常非常智能。
如何持久化设置?
由于 Silverblue 的限制,我们不能直接修改 /etc/sysctl.conf 来设置 elevator,因为那个文件可能在可写层,但并不能保证在所有场景下都生效,尤其是涉及到块设备初始化的时候。
最稳妥的方法是通过 rpm-ostree 添加内核启动参数。
打开终端,执行:
sudo rpm-ostree kargs --append-if-missing="elevator=none"
如果你是用 mq-deadline 策略:
sudo rpm-ostree kargs --append-if-missing="elevator=mq-deadline"
添加完成后,你需要重新生成启动配置并重启:
sudo rpm-ostree finalize
重启后,你可以再次运行 cat /sys/block/nvme0n1/queue/scheduler 来验证是否生效。你会看到当前活跃的调度器变成了你设置的那个。
解释给小朋友听:想象一下,I/O 调度器就像一个火车站的检票员。bfq 是一个非常仔细、非常公平的检票员,他会让每个人都排好队,谁也不让谁。但是对于 NVMe 这种“高铁站”(速度极快,通道极多),这个检票员反而成了瓶颈,因为他处理得太慢了。none 就是让火车(数据)自己根据情况快速通过,因为高铁站本身就有智能的调度系统。
第三步:优化文件系统参数——提高随机读写性能
Silverblue 默认使用 Btrfs 文件系统。Btrfs 是一个功能强大的现代文件系统,但它默认的某些设置对于通用桌面使用来说,可能偏向于数据完整性而非极致性能。
我们可以通过 sysctl 来调整一些关键参数。但在 Silverblue 上,我们需要创建一个 overlay 来让这些修改持久化。
创建 sysctl 配置文件
在你的主目录(
/home/$USER)下,创建一个新的配置文件。比如:nano ~/.config/sysctl.d/99-silverblue-tuning.conf注意:Silverblue 的用户家目录是可写的,但系统分区是只读的。我们需要把配置放在
/etc/sysctl.d/下,但这需要 root 权限,而且会被系统更新覆盖。所以,更推荐的方法是使用rpm-ostree来安装一个包含 sysctl 配置的本地 rpm 包,或者使用bootc构建。但对于简单的调试,我们可以尝试直接写入/etc/sysctl.d/,然后监控它是否被覆盖。更正:在 Silverblue 上,直接写入
/etc/sysctl.d/是不会持久化的,因为/etc在不可变层是只读的,或者会被rpm-ostree事务覆盖。正确的 Silverblue 持久化 sysctl 方法:
我们需要创建一个临时的 RPM 包,或者使用
rpm-ostree override replace。但这太复杂了。最简单且有效的方法:使用
rpm-ostree的内核参数来传递一些文件系统相关的内核选项,或者使用systemd服务在启动时运行sysctl命令。让我们创建一个 systemd 服务:
sudo nano /etc/systemd/system/sysctl-tuning.service内容如下:
[Unit] Description=Apply custom sysctl tuning for Silverblue After=local-fs.target [Service] Type=oneshot ExecStart=/usr/sbin/sysctl -p /etc/sysctl.d/99-silverblue-tuning.conf RemainAfterExit=yes [Install] WantedBy=multi-user.target然后,我们需要确保
/etc/sysctl.d/99-silverblue-tuning.conf存在。由于/etc是只读的,我们需要通过rpm-ostree来“注入”这个文件。方法 A:使用
rpm-ostree的--sysroot选项(推荐)# 创建临时目录 mkdir -p /tmp/sysctl-tuning/etc/sysctl.d # 写入你的 sysctl 参数 cat > /tmp/sysctl-tuning/etc/sysctl.d/99-silverblue-tuning.conf << EOF # 提高文件描述符限制 fs.file-max = 2097152 fs.inotify.max_user_watches = 524288 fs.inotify.max_user_instances = 512 # 减少 Swap 的使用倾向(0 = 不使用 swap,100 = 积极使用) # 对于 SSD,适当减少 swap 使用可以减少写入 vm.swappiness = 10 # 提高 inode 缓存效率 vm.vfs_cache_pressure = 50 # 对于 Btrfs,可以适当调整 # 减少写时复制(CoW)的开销,对于 SSD 影响不大,但可以试试 # 注意:这可能会影响快照和克隆的性能 # btrfs 相关的参数通常通过挂载选项设置,而不是 sysctl EOF # 使用 rpm-ostree 安装这个配置 sudo rpm-ostree install /tmp/sysctl-tuning/etc/sysctl.d/99-silverblue-tuning.conf等等,
rpm-ostree install通常用于安装 RPM 包,而不是单个文件。更简单的方法是使用systemd的sysctl.d支持,但前提是文件必须存在于文件系统中。方法 B:使用
bootc或OSTree的自定义镜像这是最“Silverblue”的方式。创建一个
Containerfile:FROM quay.io/fedora/silverblue:40 RUN mkdir -p /etc/sysctl.d RUN cat > /etc/sysctl.d/99-silverblue-tuning.conf << 'EOF' fs.file-max = 2097152 fs.inotify.max_user_watches = 524288 vm.swappiness = 10 vm.vfs_cache_pressure = 50 EOF RUN systemctl enable sysctl-tuning.service 2>/dev/null || true但这对于普通用户来说太复杂了。
方法 C:折中方案——使用
rpm-ostree的override功能实际上,对于大多数用户,最实用的方法是在每次登录后,手动运行
sysctl命令,或者创建一个简单的脚本。但为了“优化”,我们需要持久化。让我给你一个真实可行的方案:使用
systemd的sysctl模块,并通过rpm-ostree安装一个包含/etc/sysctl.d/文件的包。你可以创建一个简单的 RPM 包,或者直接利用
rpm-ostree的--apply-live选项(如果可用)。最简单的“伪持久化”方法:
在你的
~/.bashrc或~/.zshrc中添加:# 启动时应用 sysctl if [ -f /etc/sysctl.d/99-silverblue-tuning.conf ]; then sudo sysctl -p /etc/sysctl.d/99-silverblue-tuning.conf fi但这需要每次登录都输入密码,不现实。
最终推荐方案:使用
rpm-ostree安装一个自定义的sysctl包这太麻烦了。让我们回到核心问题:容器启动慢。
对于容器启动慢,最关键的内核参数其实是
fs.dentry-cache和fs.inode-cache,以及vm.swappiness。你可以尝试使用
bootc来构建一个优化的镜像,这是 Fedora 官方推荐的 future-proof 方式。# 创建一个 Containerfile cat > Containerfile << 'EOF' FROM quay.io/fedora/silverblue:40 # 添加 sysctl 配置 RUN mkdir -p /etc/sysctl.d RUN cat > /etc/sysctl.d/99-silverblue-tuning.conf << 'INNEREOF' fs.file-max = 2097152 fs.inotify.max_user_watches = 524288 vm.swappiness = 10 vm.vfs_cache_pressure = 50 INNEREOF # 启用 sysctl 服务 RUN systemctl enable systemd-sysctl.service EOF # 构建并部署 bootc build os-image --type oci-tar Containerfile.taroci bootc install --append-karg=...好吧,这确实复杂。对于大多数用户,我建议先尝试内核参数调整,这已经能解决 80% 的问题。
第四步:内核参数调优——针对容器和磁盘
让我们回到 rpm-ostree kargs,这是我们在 Silverblue 上最强大的武器。
关键参数解释
vm.swappiness=10- 作用:控制内核使用 swap 的倾向。默认值是 60,意味着内核比较“积极”地把内存数据换出到 swap。对于 SSD,这会增加不必要的写入,并可能导致延迟。
- 建议值:10 或更低。这会让内核更倾向于保留数据在内存中。
vm.vfs_cache_pressure=50- 作用:控制内核回收 dentry 和 inode 缓存的倾向。默认值是 100,意味着内核会频繁地回收这些缓存。对于经常访问大量小文件的应用(如容器运行时),这会导致性能下降,因为内核需要不断地重新解析路径。
- 建议值:50 或更低。这会让内核更“吝啬”地保留这些缓存,从而提高文件访问速度。
kernel.pid_max=65536- 作用:提高最大进程 ID 数量。容器环境中,进程数量可能很多,默认值可能不够用。
- 建议值:65536。
net.core.somaxconn=65535和net.ipv4.tcp_max_syn_backlog=65535- 作用:提高网络连接的队列长度。如果你运行的是 Web 容器(如 Nginx, Node.js),这有助于处理高并发。
- 建议值:65535。
kernel.shmmax和kernel.shmall- 作用:共享内存限制。某些数据库容器(如 PostgreSQL, Redis)可能需要调整这些值。
- 建议:对于通用优化,可以先保持默认,如果遇到特定应用问题再调整。
如何应用这些参数?
再次强调,使用 rpm-ostree kargs:
sudo rpm-ostree kargs --append-if-missing="vm.swappiness=10"
sudo rpm-ostree kargs --append-if-missing="vm.vfs_cache_pressure=50"
sudo rpm-ostree kargs --append-if-missing="kernel.pid_max=65536"
sudo rpm-ostree kargs --append-if-missing="net.core.somaxconn=65535"
sudo rpm-ostree kargs --append-if-missing="net.ipv4.tcp_max_syn_backlog=65535"
添加完成后,同样需要:
sudo rpm-ostree finalize
然后重启系统。
验证
重启后,你可以运行以下命令验证:
sysctl vm.swappiness
sysctl vm.vfs_cache_pressure
sysctl kernel.pid_max
第五步:针对容器引擎的优化(Podman/Docker)
即使内核参数优化了,容器引擎本身的配置也很重要。在 Silverblue 上,podman 是默认的容器引擎,docker 通常是 podman 的兼容层。
1. 使用 fuse-overlayfs
Silverblue 默认使用 overlayfs 作为存储驱动。对于非 root 用户运行的容器(这是 Silverblue 推荐的做法,也是更安全的方式),overlayfs 可能需要 fuse-overlayfs 来提供用户命名空间支持。
确保你已经安装了 fuse-overlayfs:
sudo rpm-ostree install fuse-overlayfs
然后,检查 ~/.config/containers/storage.conf 是否存在,并确保存储驱动设置为 overlay:
{
"graphRoot": "/home/$USER/.local/share/containers/storage",
"runRoot": "/home/$USER/.local/run/containers/storage",
"storage": {
"driver": "overlay"
}
}
如果 overlay 驱动有问题,可以尝试 fuse-overlayfs:
{
"storage": {
"driver": "overlay",
"options": {
"overlay.mount_program": "/usr/bin/fuse-overlayfs"
}
}
}
2. 调整 Podman 的并发限制
Podman 默认可能会限制并发的容器操作。你可以编辑 ~/.config/containers/libpod.conf(或者通过 podman machine 如果是使用虚拟机模式)来调整。
但更常见的是,启动慢可能是因为 Podman 需要从远程镜像仓库拉取镜像。确保你的镜像本地缓存充足。
# 清理未使用的镜像,释放空间
podman system prune -a
# 查看镜像大小和位置
podman images
3. 禁用不必要的服务
Silverblue 上运行了一些系统服务,可能会占用资源。使用 systemd-analyze blame 查看哪些服务启动最慢:
systemd-analyze blame
如果某些服务不影响你的日常工作,可以考虑禁用它们。
