
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 决定分区方式必须是 GPTSecure 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 ModeUEFI Only保证和 Windows 同一模式否则启动项互相看不见Secure Boot先 Enabled镜像支持装驱动出问题时再处理Fast BootDisabled快速启动可能让 U 盘启动项不显示SATA ModeAHCI换成 RAID 会导致两个系统都识别不到盘CSMDisabled和 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 环境动辄几十个 G200 G 只是入门。如果做深度学习建议 400 G 以上或者干脆单独挂一块盘给 Linux。3.2 手动分区的切法安装类型那一步一定要选其他选项Something else手动指定分区。我这里的分法是这样的EFI 系统分区Windows 已经建了一个直接复用不要新建第二个。多 EFI 分区是两个系统互相看不见启动项的经典原因。根分区 /ext4给 150 G 左右。交换分区 swap内存足够大32 G 以上的话可以给 16 G 意思一下或者直接用 swapfile。home 分区剩下的空间全给 /homeext4。这样以后重装系统个人数据不会丢。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_STYLEhidden GRUB_TIMEOUT0改成GRUB_TIMEOUT_STYLEmenu GRUB_TIMEOUT10然后更新配置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_PROBERfalse保存后重新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/grubGRUB_DEFAULT0把 0 换成对应编号。更稳妥的做法是用名称指定GRUB_DEFAULTWindows 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 couldnt communicate with the NVIDIA driver。5.1 先看清自己踩的是哪个坑这个报错背后至少有三种不同原因症状相似但处理方式完全不同。先做个对照现象可能原因排查方向nvidia-smi 报通信失败lspci 能看到显卡驱动模块没加载dmesg 看模块签名/加载错误nvidia-smi 无输出重启后偶尔正常驱动版本和内核不匹配检查是否装了 dkmsX 起不来日志有 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 修场景是这样的某次固件更新或者误操作之后开机直接进 UbuntuWindows 项在 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然后绑定必要的目录并 chrootfor i in /dev /dev/pts /proc /sys /run; do sudo mount --bind $i /mnt$i; done sudo chroot /mnt进到 chroot 环境后重装 GRUBgrub-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% 的时间只用一个系统那另一个系统的存在意义就不大反而会带来引导、分区、驱动上持续的小麻烦。想清楚自己到底需要不需要比会装更重要。每次有人问我值不值得装双系统我都会先问一句你打算用另一个系统干什么答不上来的我一般建议他先用虚拟机试试水。真正需要物理双系统的场景其实远比想象中少。