1. 为什么我选了 Ubuntu 20.04 而不是更新的 22.04/24.04
动手之前先说结论:这台机器装双系统的目的很明确,就是要跑 CUDA 相关的训练和推理任务,顺带保留 Windows 用来处理一些只能跑在 Windows 下的工程软件。目标定下来之后,选哪个 Ubuntu 版本就成了第一个需要拍板的事。
很多人第一反应是"装新不装旧",直接上 22.04 甚至 24.04。我一开始也是这么想的,直到我把手头的几张卡和几套依赖在虚拟机里过了一遍,才发现 20.04 对老一些的 N 卡驱动和 CUDA 版本兼容性反而更省心。20.04 的长期支持周期足够长,官方仓库里 nvidia-driver 系列覆盖的版本区间也比较宽,遇到老卡不用去手动编译内核模块。
具体到我这台机器的配置,是 Intel 平台加一张算力中等偏上的独立显卡,主板固件是 UEFI 模式,开了 Secure Boot。这三条信息决定了后面几乎所有踩坑的方向:UEFI 决定分区方式必须是 GPT,Secure Boot 决定驱动签名会被校验,独显决定必须处理 NVIDIA 驱动和内核模块签名的问题。
还有一个容易被忽略的点,就是 20.04 的安装镜像下载。官网原版镜像在部分网络环境下拖得比较慢,很多人的做法是找国内镜像站,下载完务必核对 SHA256。我曾经因为一个下载不完整的镜像,装到一半报"无法读取压缩包",来回折腾了一个多小时才发现是镜像损坏,这种低级坑其实完全可以避免。
提示:镜像下载完成后,在 Windows 下用 certutil -hashfile 文件名 SHA256 拿到的值,和官网公布的值逐位对比,比凭感觉看"文件大小差不多"靠谱得多。
另外提醒一句,双系统不是唯一选择。如果你只是想临时验证某个环境,虚拟机装 Ubuntu 反而更灵活,随时快照回滚。但涉及显卡直通、CUDA 性能这类需求,虚拟机的损耗和配置复杂度会让你怀疑人生,这时候物理双系统才是正解。这个判断在动手之前想清楚,能省掉后面一半的返工。
2. U 盘启动盘制作与 UEFI 固件里那几个必须改的设置
很多人卡在安装界面进不去,或者装完发现 Windows 启动项没了,根源往往在固件设置和启动盘制作这一步就埋下了。这一节把这块拆开讲透。
2.1 启动盘工具的选择逻辑
写盘工具有不少,我最后用的是 Rufus。选它的理由很实际:它能明确区分 MBR 和 GPT 两种分区方案,写入时还能选择"以 ISO 镜像模式写入"还是"以 DD 镜像模式写入"。Ubuntu 20.04 的镜像推荐走 DD 模式,这样写出来的盘对 UEFI 启动的支持最稳定。
如果你用的是其他工具,比如 balenaEtcher,也能用,它默认就是 DD 模式,写盘过程更傻瓜。Ventoy 是另一条路,把多个 ISO 拷进 U 盘直接启动,适合喜欢折腾多系统镜像的人,但它对 Secure Boot 的处理需要额外配置,新手不建议一上来就用。
写盘之前有一个动作必须做:把 U 盘里原来的数据备份走。写盘是整盘覆盖,没有后悔药。
2.2 Secure Boot 到底该不该关
这是双系统里争议最大的一个点。我的建议是:先留着 Secure Boot 开着装,如果装完进不去系统,再考虑关掉,而不是一上来就关。
为什么这么说。Secure Boot 的作用是校验启动阶段的签名,防止未签名的引导程序被加载。Ubuntu 20.04 的安装镜像本身是支持 Secure Boot 的,装机过程通常没问题。真正会出问题的是装完 NVIDIA 驱动之后——驱动模块默认没有签名,Secure Boot 开着就会拒绝加载,表现就是进入系统后分辨率异常、nvidia-smi报错。
处理办法有两个方向。一是彻底关闭 Secure Boot,最省事,代价是牺牲了这层校验。二是保留 Secure Boot,在装驱动时给内核模块签名,也就是走 MOK 那套流程。我在下面第 5 节会详细讲签名怎么做。
还有一点要提醒:不同主板固件里 Secure Boot 开关的位置差异很大,有的在 Security 菜单下,有的藏在 Boot 菜单里。如果找不到,直接搜你主板型号加"关闭 Secure Boot",比在菜单里瞎翻快。
2.3 固件设置清单
进 BIOS/UEFI 之后,我会按下面这张表逐项确认,避免遗漏:
| 设置项 | 建议值 | 原因 |
|---|---|---|
| Boot Mode | UEFI Only | 保证和 Windows 同一模式,否则启动项互相看不见 |
| Secure Boot | 先 Enabled | 镜像支持,装驱动出问题时再处理 |
| Fast Boot | Disabled | 快速启动可能让 U 盘启动项不显示 |
| SATA Mode | AHCI | 换成 RAID 会导致两个系统都识别不到盘 |
| CSM | Disabled | 和 UEFI Only 保持一致 |
尤其注意 Fast Boot 和 SATA Mode 这两项。我见过有人装完 Ubuntu 之后 Windows 直接蓝屏,排查半天发现是装系统前顺手改了 SATA 模式。Windows 尤其对存储控制器模式敏感,这个改动两个系统都得跟着适应,能不碰就别碰。
3. 分区方案:给 Ubuntu 留多少、怎么切
分区是双系统里最容易一刀切错、后面几乎无法挽回的环节。Windows 装在整盘上的话,Ubuntu 安装器会提示"是否覆盖整个磁盘",一旦点了,Windows 就没了。所以进安装界面之前,先在 Windows 里把空间腾出来。
3.1 在 Windows 里压缩卷
打开磁盘管理,找到系统盘,右键压缩卷。这里有个硬性限制:Windows 只能压缩到它认为"不可移动文件"之后的位置,所以实际能压缩出来的空间往往小于你预期的。如果压不动,多半是页面文件或系统还原点在占位,关掉系统保护再试。
我一般给 Ubuntu 留 200 GB 起步。跑 CUDA 的人要额外考虑:模型文件、数据集、conda 环境动辄几十个 G,200 G 只是入门。如果做深度学习,建议 400 G 以上,或者干脆单独挂一块盘给 Linux。
3.2 手动分区的切法
安装类型那一步,一定要选"其他选项"(Something else),手动指定分区。我这里的分法是这样的:
- EFI 系统分区:Windows 已经建了一个,直接复用,不要新建第二个。多 EFI 分区是两个系统互相看不见启动项的经典原因。
- 根分区 /:ext4,给 150 G 左右。
- 交换分区 swap:内存足够大(32 G 以上)的话,可以给 16 G 意思一下,或者直接用 swapfile。
- home 分区:剩下的空间全给 /home,ext4。这样以后重装系统,个人数据不会丢。
EFI 分区复用这一点我再强调一次。安装器会默认勾选一个 EFI 分区用于安装引导程序,如果它试图新建一个,说明它没认出现有的那个。这时候要手动把 Windows 的 EFI 分区设为挂载点 /boot/efi,并确保"格式化"不勾选。
3.3 引导程序装在哪
"安装启动引导器的设备"这一栏,选整块盘(比如 /dev/sda),不要选某个分区。选分区容易导致引导记录写错位置。装完之后,固件的启动菜单里应该同时能看到 Windows Boot Manager 和 ubuntu 两项,这就是理想状态。
注意:分区操作前,务必确认自己选中的空余空间来自压缩出来的那部分,而不是 Windows 分区本身。装错一次,Windows 分区被覆盖,数据恢复的成本比重新装系统高太多。
4. 装完之后第一件事:GRUB 和默认启动顺序
装完重启,如果直接进了 Ubuntu 而没看到选择菜单,别慌,这是正常现象——很多机器默认不显示 GRUB 菜单,或者超时时间设成了 0。这一节讲怎么把双系统的启动入口理顺。
4.1 让 GRUB 菜单显示出来
先确认能进系统,然后编辑 GRUB 配置。打开终端:
sudo nano /etc/default/grub找到这两行:
GRUB_TIMEOUT_STYLE=hidden GRUB_TIMEOUT=0改成:
GRUB_TIMEOUT_STYLE=menu GRUB_TIMEOUT=10然后更新配置:
sudo update-grub重启之后,你应该能看到一个菜单,里面列着 Ubuntu、Ubuntu 高级选项,以及一项形如"Windows Boot Manager"的条目。看到 Windows 这一项,说明 os-prober 成功识别到了 Windows 引导。
4.2 Windows 没出现在菜单里怎么办
这是双系统最常见的症状之一。原因通常是 os-prober 没被启用。在 20.04 上,默认安装 os-prober 可能是禁用状态,需要手动开:
sudo apt install os-prober sudo nano /etc/default/grub在文件末尾加上:
GRUB_DISABLE_OS_PROBER=false保存后重新sudo update-grub,观察输出里有没有出现"Found Windows Boot Manager"这类字样。如果出现了,菜单里就会多出 Windows 项。
如果还是找不到,多半是 Windows 的 EFI 引导文件位置异常,可能是装系统时引导写到了别的分区。这时候可以手动确认一下 Windows 的 EFI 文件在不在:
sudo ls /boot/efi/EFI/正常情况下会有 Microsoft、ubuntu 两个目录。只有 ubuntu 没有 Microsoft,说明 Windows 引导文件不在这块 EFI 分区上,需要挂载对应的分区把它找出来。
4.3 设置默认启动系统
有些人希望默认进 Windows,把 Linux 当备选。做法是把菜单里的顺序调一下,或者直接改默认项。先用这个命令看各启动项的编号:
grep -E "menuentry |submenu " /boot/grub/grub.cfg记下你想默认启动的那一项的顺序号(从 0 开始),然后编辑 /etc/default/grub:
GRUB_DEFAULT=0把 0 换成对应编号。更稳妥的做法是用名称指定:
GRUB_DEFAULT="Windows Boot Manager (on /dev/sda1)"名称根据你实际看到的菜单项来写。改完记得sudo update-grub。我个人习惯默认进 Ubuntu,因为大部分时间在 Linux 下干活,Windows 项放在菜单里手动选就行。
5. NVIDIA 驱动:Secure Boot 下最大的坑
前面几节都是铺垫,这一节才是真正让人抓狂的地方。Secure Boot 开着的情况下装 NVIDIA 驱动,大概率会遇到模块加载失败,nvidia-smi直接报 "NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver"。
5.1 先看清自己踩的是哪个坑
这个报错背后至少有三种不同原因,症状相似但处理方式完全不同。先做个对照:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| nvidia-smi 报通信失败,lspci 能看到显卡 | 驱动模块没加载 | dmesg 看模块签名/加载错误 |
| nvidia-smi 无输出,重启后偶尔正常 | 驱动版本和内核不匹配 | 检查是否装了 dkms |
| X 起不来,日志有 glxserver_nvidia 加载失败 | 驱动装完没重建 initramfs | 看 Xorg 日志 |
拿我自己遇到的那次来说,lspci | grep -i nvidia能正常列出显卡,说明硬件识别没问题,问题在驱动层。接着看内核日志:
sudo dmesg | grep -i nvidia输出里出现了签名相关的字样,基本就实锤了——Secure Boot 拒绝了未签名的模块。
5.2 用官方仓库装驱动(推荐路径)
装驱动的路子有三条:系统附加驱动(Software & Updates 里的 Additional Drivers)、官方 runfile、以及 NVIDIA 官方 PPA。我推荐第三条,即官方仓库加 PPA,它对 Secure Boot 和 DKMS 的配合最规范。
先加 PPA 并更新:
sudo add-apt-repository ppa:graphics-drivers/ppa sudo apt update看仓库里能装哪些版本:
ubuntu-drivers devices输出了推荐版本之后,直接装:
sudo ubuntu-drivers autoinstall它会自动选择推荐版本,并通过 DKMS 编译模块。DKMS 的好处是内核升级后模块会自动重编译,省得每次升级内核驱动就挂掉。
5.3 Secure Boot 下的 MOK 签名流程
如果用ubuntu-drivers autoinstall装驱动,过程中会弹出一个蓝色的配置界面,问你"是否要为内核模块设置密码以用于 Secure Boot"。这一步千万不能跳过。
流程是这样:你输入一个临时密码,装完后重启,主板会弹出一个 MOK 管理界面(MokManager),选中"Enroll MOK"→"Continue"→输入刚才那个密码,完成注册。走完这一步,驱动模块就被信任了,Secure Boot 可以继续开着。
如果当时手滑跳过了,或者没看清提示,重启后驱动不加载,可以手动补签:
sudo mokutil --import /var/lib/shim-signed/mok/MOK.der系统会提示你设置一个密码,重启后同样进 MokManager 完成注册。注意 MOK.der 的实际路径可能因驱动版本不同而不同,找不到的话用:
sudo find / -name "MOK.der" 2>/dev/null5.4 实在搞不定就临时关掉 Secure Boot
我不推荐一上来就关,但如果是赶时间的场景,关掉确实是成本最低的解法。进 BIOS 把 Secure Boot 设为 Disabled,重启后驱动大概率就能正常加载。验证方法是:
nvidia-smi能出一张表,显示驱动版本、CUDA 版本、显卡型号和显存占用,就说明彻底通了。
提示:关掉 Secure Boot 后如果 Windows 侧有依赖它的服务(比如某些安全启动相关的启动保护),可能需要重新调整。改之前心里有数就行。
5.5 一个容易被忽略的收尾动作
装完驱动,别急着开工,先做两件事。一是重建 initramfs,命令是:
sudo update-initramfs -u二是确认 glx 相关模块正常。之前提到过日志里有 "failed to load module glxserver_nvidia" 的报错,这类问题往往就是驱动装完没有更新 initramfs 造成的,更新之后重启基本能解决。我把这个动作固定成流程的一部分,后面再没踩过这个坑。
6. 两个系统互相救急:引导损坏后的修复思路
双系统用久了,迟早会遇到一个系统进不去、需要从另一个系统里动手修的情况。这种"跨系统修复"是双系统的独有场景,很多人到这一步就重装了,其实大部分情况可以救回来。
6.1 Windows 引导被打乱,怎么从 Ubuntu 修
场景是这样的:某次固件更新或者误操作之后,开机直接进 Ubuntu,Windows 项在 GRUB 里也没了。这时候先在 Ubuntu 终端确认 Windows 的 EFI 文件还在:
sudo ls /boot/efi/EFI/Microsoft/Boot/能看到 bootmgfw.efi 这类文件,说明文件没丢,只是引导项丢了。接着重建 GRUB 配置:
sudo os-prober sudo update-grub如果 os-prober 没找到,可以把 Windows 的引导复制一份到固件能识别的默认路径,或者用 efibootmgr 手动添加启动项:
sudo efibootmgr -c -d /dev/sda -p 1 -L "Windows Boot Manager" -l "\EFI\Microsoft\Boot\bootmgfw.efi"这条命令的意思是在第一块盘的第一分区上,新建一个名为 Windows Boot Manager 的启动项,指向对应的 efi 文件。参数里的盘和分区号要根据实际情况改,写错了会出现一个无效启动项,用sudo efibootmgr能看到当前所有项,无效的用-b 编号 -B删掉。
6.2 Ubuntu 引导坏了,从 Windows 侧修
反过来,Ubuntu 进不去,需要从 Windows 修。这一步稍微麻烦点,因为 Windows 原生没有读取 ext4 的工具。思路是做一个 Ubuntu 的 Live USB,从中启动,挂载原系统的根分区,进行 chroot 后重装 GRUB。
先看分区结构:
sudo fdisk -l找到原来的根分区(比如 /dev/nvme0n1p5),挂载它:
sudo mount /dev/nvme0n1p5 /mnt sudo mount /dev/nvme0n1p1 /mnt/boot/efi然后绑定必要的目录并 chroot:
for i in /dev /dev/pts /proc /sys /run; do sudo mount --bind $i /mnt$i; done sudo chroot /mnt进到 chroot 环境后,重装 GRUB:
grub-install /dev/nvme0n1 update-grub退出并重启,引导大概率就回来了。这套流程我在一次内核升级失败后用过一次,当时以为要重装系统,结果二十分钟就恢复了。
6.3 修复时最容易犯的错
第一个错是挂载点搞混,把 /boot/efi 挂错分区。挂错的话 grub-install 会往错误的 EFI 分区写引导文件,结果是引导修好了但另一个系统的引导被覆盖。挂载前用lsblk -f看清楚每个分区的文件系统类型,FAT32 的才是 EFI 分区。
第二个错是 chroot 之前忘了 bind /dev 和 /proc。少了这两个,grub-install 会因为找不到设备节点失败,报的错还很含糊,容易让人以为是 GRUB 本身有问题。
7. 双系统共存下的几个日常参数调整
系统跑起来之后,还有一些日常性质的调整,看似是小问题,不注意就会反复浪费你的时间。
7.1 时间差 8 小时的问题
这个几乎人人都会遇到。原因是 Windows 把 BIOS 时间当作本地时间处理,Linux 默认当作 UTC。结果就是每次切换系统,时间都要偏一次。解决方式有两个方向,我选的是改 Linux,让它和 Windows 保持一致:
timedatectl set-local-rtc 1 --adjust-system-clock这条命令让 Linux 也把硬件时钟当本地时间。代价是夏令时切换时可能有点小问题,但对中国用户来说不涉及夏令时,实际使用中没什么影响。也可以反过来改 Windows 注册表让它用 UTC,看个人习惯。
7.2 默认启动和快速启动的配合
前面说过固件里的 Fast Boot 要关。这里补充一个 Windows 侧的设置,叫"快速启动"(Fast Startup),它和固件里的 Fast Boot 是两回事。Windows 的快速启动会让关机变成一种混合休眠状态,共享的 NTFS 分区如果被 Ubuntu 挂载,可能出现文件系统不一致甚至只读挂载的情况。
关掉它的位置在控制面板的电源选项里,找到"选择电源按钮的功能"→"更改当前不可用的设置",把"启用快速启动"取消勾选。如果你在 Ubuntu 下挂载 Windows 分区时遇到只读或者报错,先检查这一项。
7.3 显卡驱动的版本选择心得
驱动不是越新越好。新版本驱动对老卡的支持有时会退化,而且新驱动往往绑定更新的 CUDA 版本,可能和你现有环境不兼容。我的做法是锁定一个经过实测稳定的版本,在装好之后把相关包标记为保持:
sudo apt-mark hold nvidia-driver-<版本号>这样系统更新时不会把它顺手升上去。等真的需要新特性了,再手动解锁升级。这个习惯帮我避开了好几次"更新完驱动环境就崩"的糟心事。
如果确实是做深度学习,还要注意驱动版本和 CUDA 运行库版本的对应关系。不用死记硬背,装完驱动后nvidia-smi右上角会显示该驱动支持的最高 CUDA 版本,照这个上限去选 CUDA 工具包,基本不会出问题。
7.4 卸载 Ubuntu 的正确姿势
用一阵子之后想回退到单 Windows,也别直接格盘了事。正确的顺序是:先在 Windows 里用 efibootmgr 的 Windows 版本(bcdedit)或者 EasyUEFI 之类的工具,把 Ubuntu 的启动项删掉,确认 Windows 能独立启动;然后进磁盘管理,把 Linux 相关分区删掉,合并回 Windows 分区;最后再调整引导。顺序反了的话,先删分区会导致引导残留在 EFI 分区里,开机可能出现一个找不到系统的启动项,虽然能手动跳过,但心里膈应。
我在另一台机器上卸载 Ubuntu 时就图快,直接删了分区,结果 Windows 启动菜单里一直留着一个无效项,最后专门做了个 Live USB 用 efibootmgr 清掉的。所以这一步宁可慢一点,按顺序来。
8. 我在这套流程里总结出的几条硬经验
装了不止一次双系统之后,有几条经验我是用真金白银的时间换来的,写在这里给准备动手的人省点弯路。
第一,装系统之前把所有重要数据备份到别的物理盘上。分区操作是不可逆的,任何"我看清楚了"的自信在系统崩溃面前都不值钱。备份不是走形式,而是给自己留退路。
第二,动手前把 BIOS 里的关键设置先确认一遍再装,尤其是 SATA 模式、启动模式和 Secure Boot 这三项。这三项在装机前定好,比装完之后再来回折腾要省事十倍。
第三,驱动问题优先用官方仓库解决,别一开始就抱着 runfile 硬刚。runfile 装起来自由,但它和内核升级、Secure Boot 的配合都需要你手动维护,时间成本很高。官方仓库加 DKMS 的组合虽然版本不是最新,但胜在稳定省心。
第四,养成动手前查日志的习惯。dmesg、journalctl -b、Xorg 日志这几个地方,藏着大部分问题的答案。很多人遇到报错就上网搜,其实自己的机器早就把原因写在日志里了。看日志这个技能,比记住任何一条具体命令都有价值。
第五,双系统的价值在于两个系统都能正常用,而不是装完就完事。装完之后花点时间验证:两个系统能不能各自正常启动、互相能不能看到对方的分区、驱动有没有正常工作、时间对不对。这些验证做一遍,后面用起来才踏实。
第六,也是我觉得最重要的一条——别把双系统当成炫技。如果你的工作流里 90% 的时间只用一个系统,那另一个系统的存在意义就不大,反而会带来引导、分区、驱动上持续的小麻烦。想清楚自己到底需要不需要,比会装更重要。每次有人问我值不值得装双系统,我都会先问一句:你打算用另一个系统干什么?答不上来的,我一般建议他先用虚拟机试试水。真正需要物理双系统的场景,其实远比想象中少。