双子系统(仮)环境安装指南

Author Avatar
Equim 2017年10月31日
  • 在其它设备中阅读本文章
Read: 54 minWords: 13,525Last Updated: 18-02-07Written in: AsciiDocLicense: CC-BY-NC-4.0

[1]

本文旨在提供一个以 Windows 10 x64 为宿主机,以 VirtualBox 为驱动,构建一个高度优化、高度集成的 Arch Linux x64 虚拟机的双子系统(仮)环境安装指南。

本文提及的是“双子系统(仮)”,而不是常见定义的,包含多重引导的“双系统”。

关于双子系统(仮)

本章将对双子系统(仮)进行各方面的介绍,也阐明了使用它的原因。该章篇幅较长,想直接开始的请跳到正片

双子系统(kari),英Futago System (Kari),日ふたルシステム(かり。这其实是我自己起的中二名字,本意是想与真正意义上的“双系统”区分开。

双子系统(仮)的核心是高集成、高可用、高优化,去除了不必要的功能(这也是选择 Arch Linux 的原因之一),并能很好地集成到宿主机上,用起来和物理机差别无几。具体来说,虚拟机到宿主机之间主要通过 NAT 端口映射进行交流,既能保持隔离,又能很好地方便宿主机去集成。软件的力量远比硬件强得多,比如哪怕虚拟机仅提供 SSH 服务,宿主机都能很好地非常充分地利用其与虚拟机进行互动(包括 Shell、文件系统、X11 等)。

而真正意义上的“双系统”,指的是在同一台物理机上安装两个操作系统,并通过多重引导选择启动。有关这类“双系统”的安装教程在网上已经遍地都是了。

鉴于双子系统(仮)的高度集成性,下文统称该环境下的虚拟机为妹妹机(Imouto),宿主机为姐姐机(Oneechan)。

双子系统(仮)会很适合你如果你
  1. 是 Dev 或 Ops

  2. 喜欢 POSIX,喜欢 ISO C,喜欢 gcc 工具链,喜欢性能

  3. 能耐得住折腾

  4. 积累了足够的 Linux Shell/Coreutils 或 Cygwin/MSYS2 使用经验,不依赖图形界面

  5. 不愿放弃 Office、QQ 和游戏等开发之外的需求

  6. 能很好地理解“工作不是生活的全部”

双子系统(仮)不适合你如果你
  1. 习惯用 Visual Studio、msvc 工具链,性能无关紧要

  2. 倾向于开箱即用,不喜欢折腾

  3. 没有足够的 Linux Shell/Coreutils 或 Cygwin/MSYS2 使用经验,依赖于图形界面

  4. 正是为了放弃游戏才选择的 GNU/Linux

  5. 只是为了 KDE、GNOME 的某些特性(比如主题)才选择的 GNU/Linux

  6. 不太理解“工作不是生活的全部”

优点

  1. 高度的集成性。通过 SSHFS 和端口映射,可以无缝地用姐姐机的编辑器/IDE 在妹妹机上工作

  2. 良好的性能,较低的占用。见下文 POSIX 水平测验

  3. 安全快捷。NAT 即防火墙,控制权归于姐姐。VM 即沙盒,可以快速地备份恢复

  4. 拥有完整的 Linux 内核和文件系统。可以跑 Docker,可以使用 symlink/fifo 等特性,可以挂载 USB,且 Arch Linux 本身就易于扩展和定制

  5. 直接利用姐姐机的网络,无需复杂的以太网/WiFi 设置

  6. 无界面,无需复杂的显卡/WM 设置

缺点

  1. 无法更高效地榨干硬件,无法利用 GPU

  2. 目前市面上所有针对 Win 的 SSHFS 实现都不稳定,无论是商业的还是开源的。归根结底是因为目前 Windows 上还没有一个稳定的 FUSE 实现。

  3. 如要使用 GUI,过程会比较迂回曲折

Why Not XXX

本章将解释为什么我选择了双子系统(仮)而不是 XXX。

Why not 双系统

真正意义上的双系统是相互排斥的。你没有办法在启动到 Windows 之后想去运行 Linux 上的应用,反过来也如此,除非两者的内核与文件系统互相兼容(例如两个系统都是 Windows,或者一个 OpenBSD 一个 Ubuntu 之类的),倒是确实有办法。

这种矛盾会造成诸多不便。例如你在 Windows 的 QQ 里下载了一个文件想拿到 Linux 上用,或者你在 Linux 上交叉编译了一个 Windows 的可执行文件想拿到原生 Windows 上运行,怎么办呢?虚拟机?那双系统不白装了?wine?哪有原生方便。重启吧。

为什么会有人安装双系统?在我看来,那是因为不管哪个操作系统都有它的短处,更具体地说是“无法满足我们需求的地方”,例如 Windows 实现了 POSIX 吗?众多游戏和工业软件能在 Linux 上跑吗?我们本想扬长避短,多重引导这种机制却又令我们没法同时扬两者之长,避两者之短。在我看来这并不是完美的方案。

纵然,好处也是有的。你可以充分地利用硬件,榨干某个操作系统的特性,也能拥有更加流畅的 GUI 体验。然而工作不是生活的全部。难道为了一个好用的终端、tmux,为了unistd.h,我就要抛下我的 PS、PR、Office、FL Studio、foobar、PotPlayer、IDM 吗?也许你会说,这些东西在 Linux 下都有对应的替代品,那么我喜欢的游戏呢?它们能找到替代品吗?如果 Wine 足够完美,为什么还会有 WineHQ 呢?

Why not WSL

首先我要承认我确实没有用过 WSL,下面有关 WSL 的描述多是一些用过的人的说法与我自己主观臆测。

就我个人之前的体验而言,我对微软的产品确实没多大好感。WSL 给我的印象就是不太正经[2]

对于太多的问题,我实在是不能确定,比如

  • 能使用的文件系统有哪些?我能自由地分区、自由地使用 LVM/RAID/LUKS/TrueCrypt/VeraCrypt、自由地格式化吗?

  • symlink/fifo/unix socket 这些特殊文件能用吗?

  • 能删除正在使用的文件吗?

  • 能为 WSL 单独分配网卡与 MAC 地址吗?

  • 能跑 Docker 吗?

  • 我能 dd 挂载在 Windows 上的驱动器吗?

  • WSL 能挂载 Windows 的文件系统,那么我能反过来在 Windows 上挂载 WSL 的文件系统吗?

  • 足够安全吗?

也许问的点细了一点,但还是希望用过 WSL 的朋友能与我交流一下,并回答上面这些问题。

相比之下,VM 自由度更高,也是很成熟的技术。我可以装任意我想装的系统,同时 VM 又是个沙盒,恢复快照就是一瞬间的事。

最后

Why not Cygwin/MSYS2

我自己就在用 MSYS2。

Cygwin/MSYS2 已经很大程度上满足了我日常的很多需求,所以并不是说它们不好,而是它们有太多的局限性。不说别的,就以 Win32 创建进程的那个开销来说,fork(2) 在 Cygwin/MSYS2 是下相当昂贵的,甚至还不算很稳定,这直接导致了以调用 fork(2) 为基础的 shell 应用显得很慢[3],更不用说 Cygwin/MSYS2 的 fork(2) 本身就经常会失败[4]

此外,Cygwin/MSYS2 与原生 Windows 在很多层面都也不兼容。

终端层面上,用基于 VT100 模拟的、支持 ASCII escape 的 mintty 去跑一些 Windows 原生的 CLI 应用,很容易就会出问题,尤其是当程序调用了 Windows Console API 的时候。如果你在 mintty 下直接运行 Windows 版的 node,会发现 REPL prompt 始终不会出现,这正是因为它利用了 Windows Console API,与 mintty 不兼容。如果你试着用 Windows 的方式去判断一个 mintty 的 fd[5]是不是 tty 的话,会惊奇地发现永远是 false。

$ test -t 0 && echo true || echo false
true
$ node -pe '!!process.stdin.isTTY'
false

在 Cygwin/MSYS2 终端下运行 Windows 原生 CLI 应用的一个解决方案是 winpty,可以理解为是 ConEmu 的 cygwin-connector 的一个反向实现[6]。但它也有个致命的缺陷,它只能在 stdin/stdout 这两个 fd 都是 tty 的时候才能使用,这也就意味着当 stdin/stdout 只要有一个被重定向时就无法使用 winpty。

在刚刚的例子中,如果我们用了 winpty 的话

$ winpty node -pe '!!process.stdin.isTTY'
true

信号层面上,Cygwin/MSYS2 的信号遵循 POSIX,与 Windows 也不兼容[7]。用 Cygwin/MSYS2 的方式发送的信号,就算 Windows 下有对应版本,也无法正确地传达到指定的 Windows 原生应用上。举一个简单的例子

signal.go
package main

import (
	"fmt"
	"os"
	"os/signal"
)

func main() {
	defer fmt.Println("Signal caught")

	c := make(chan os.Signal)
	signal.Notify(c, os.Interrupt)

	fmt.Println(<-c)
}
$ go env GOOS
windows

$ go run signal.go
^C (1)
$ ps -W | grep -P 'go-build.*signal\.exe' | wc -l
1 (2)
$ jobs | wc -l
0 (2)

$ # 打开任务浏览器手动清理泄漏的进程
$ # ...

$ go build signal.go
$ ./signal
^C (1)
$ ps -W | grep -P 'signal\.exe' | wc -l
0
1按下 ^C 之后,表现上是程序退出了,但什么都没有输出。
2可以看出,这个进程从 Cygwin/MSYS2 的 shell 里泄漏了。

同样地,用 winpty 可以缓解这个问题。

$ winpty ./signal
^Cinterrupt
Signal caught

安装双子系统(仮)之后,在妹妹机下将不再会有这些问题。

Why not Vagrant

说来惭愧,Vagrant 是我在写完这篇文章大概两个星期后才了解到的。

不采用 Vagrant 主要有以下几点原因:

  • 出发点不同。Vargrant 的目的是为了在团队间保持环境的一致[8],也更适用于团队而不是个人。而双子系统(仮)是为了更无缝、更高效地在 Windows 下使用定制性强的 GNU/Linux。还是那句话,工作不是生活的全部,我们用虚拟机不只是为了开发

  • 如果要更好的定制,还需要一定的 Ruby 基础。

Why not VMware

打个可能不太恰当的比方,VirtualBox 和 VMware 的关系就好比 PostgreSQL 和 Oracle 的关系。我们没有必要大炮打蚊子,而且我相信有系统洁癖的人更不乐意去装 VMware。

VirtualBox 简单易用且足够满足我们的需求,并不需要笨重的 VMware。

Why not Ubuntu/CentOS/Fedora/xxxBSD

为什么我选择了 Arch Linux?对于这个问题,请先参阅 Arch Wiki

我想我大概不用在此太费口舌了。它简洁(KISS),现代,实用。仓库与上游跟进速度超快且不乱带私货,出了问题可以直接找上游。还有 AUR 这种神器,已经很好地体现了其超高的自由度与社区的热度。用来当妹妹系统再适合不过了。

尽管如此,Arch Linux 的安装是最容易卡住新人的地方。本文的重点也在如何安装 Arch Linux 上。

POSIX 水平测验

UnixBench 5.1.3 为“试卷”,本章将对双子系统(仮)的 POSIX 水平进行粗略的评测。

尽管 UnixBench 考察的主要是 POSIX 而不是硬件,但考虑到三次评测均基于相同的硬件条件,已经统一了控制变量,因而这些结果仍然具有一定的参考性。毕竟在大多数情况下 POSIX 是我们选择 linux 最主要的理由之一。

评测使用的 CPU 为 Intel® Core™ i5-7200U CPU @ 2.50GHz x 4,架构均为 x86_64。测验流程为:

$ wget https://github.com/kdlucas/byte-unixbench/archive/v5.1.3.zip
$ unzip byte-unixbench-5.1.3.zip
$ cd byte-unixbench-5.1.3/UnixBench
$ make
$ ./Run

姐姐机的成绩

姐姐机的 POSIX 接口由 MSYS2 提供,结果可作为“及格线”来理解。

单核水平

时间跨度:19:22:49 - 19:50:57; 28m 08s

TestScoreUnitTimeIters.BaselineIndex
Dhrystone 2 using register variables44726152.1lps10.0 s7116700.03832.6
Double-Precision Whetstone5491.2MWIPS9.3 s755.0998.4
Execl Throughput120.8lps29.9 s243.028.1
File Copy 1024 bufsize 2000 maxblocks353203.4KBps30.0 s23960.0891.9
File Copy 256 bufsize 500 maxblocks94264.8KBps30.0 s21655.0569.6
File Copy 4096 bufsize 8000 maxblocks836913.0KBps30.0 s25800.01443.0
Pipe Throughput347603.3lps10.0 s712440.0279.4
Pipe-based Context Switching98949.6lps10.0 s74000.0247.4
Process Creation166.7lps30.1 s2126.013.2
Shell Scripts (1 concurrent)482.8lpm60.1 s242.4113.9
Shell Scripts (8 concurrent)96.6lpm60.2 s26.0161.0
System Call Overhead968738.6lps10.0 s715000.0645.8
System Benchmarks Index Score:312.1
多核(4)水平

时间跨度:20:45:11 - 21:13:31; 28m 20s

TestScoreUnitTimeIters.BaselineIndex
Dhrystone 2 using register variables86104692.1lps10.1 s7116700.07378.3
Double-Precision Whetstone18892.5MWIPS9.6 s755.03435.0
Execl Throughput262.4lps29.6 s243.061.0
File Copy 1024 bufsize 2000 maxblocks533311.0KBps30.0 s23960.01346.7
File Copy 256 bufsize 500 maxblocks138711.3KBps30.0 s21655.0838.1
File Copy 4096 bufsize 8000 maxblocks1320875.3KBps30.0 s25800.02277.4
Pipe Throughput824513.8lps10.1 s712440.0662.8
Pipe-based Context Switching258788.3lps10.6 s74000.0647.0
Process Creation348.1lps30.1 s2126.027.6
Shell Scripts (1 concurrent)738.7lpm60.2 s242.4174.2
Shell Scripts (8 concurrent)99.7lpm60.5 s26.0166.2
System Call Overhead2186973.1lps10.1 s715000.01458.0
System Benchmarks Index Score:595.5

妹妹机的成绩

进行评测时,妹妹机的内核版本为 4.13.6-1-ARCH。

单核水平

时间跨度:20:17:02 - 20:45:11; 28m 09s

TestScoreUnitTimeIters.BaselineIndex
Dhrystone 2 using register variables36569067.3lps10.0 s7116700.03133.6
Double-Precision Whetstone4465.2MWIPS9.9 s755.0811.9
Execl Throughput4394.1lps29.8 s243.01021.9
File Copy 1024 bufsize 2000 maxblocks973906.3KBps30.0 s23960.02459.4
File Copy 256 bufsize 500 maxblocks291912.0KBps30.0 s21655.01763.8
File Copy 4096 bufsize 8000 maxblocks2448157.6KBps30.0 s25800.04221.0
Pipe Throughput2333162.0lps10.0 s712440.01875.5
Pipe-based Context Switching252854.1lps10.0 s74000.0632.1
Process Creation8604.9lps30.0 s2126.0682.9
Shell Scripts (1 concurrent)3997.4lpm60.0 s242.4942.8
Shell Scripts (8 concurrent)949.5lpm60.0 s26.01582.6
System Call Overhead3054338.3lps10.0 s715000.02036.2
System Benchmarks Index Score:1487.2
多核(4)水平

时间跨度:20:45:11 - 21:13:31; 28m 20s

TestScoreUnitTimeIters.BaselineIndex
Dhrystone 2 using register variables80021099.2lps10.0 s7116700.06857.0
Double-Precision Whetstone14737.3MWIPS10.4 s755.02679.5
Execl Throughput11689.3lps30.0 s243.02718.4
File Copy 1024 bufsize 2000 maxblocks1083898.7KBps30.0 s23960.02737.1
File Copy 256 bufsize 500 maxblocks302227.7KBps30.0 s21655.01826.1
File Copy 4096 bufsize 8000 maxblocks2963931.6KBps30.0 s25800.05110.2
Pipe Throughput5086343.3lps10.0 s712440.04088.7
Pipe-based Context Switching731917.1lps10.0 s74000.01829.8
Process Creation20550.0lps30.0 s2126.01631.0
Shell Scripts (1 concurrent)7870.2lpm60.0 s242.41856.2
Shell Scripts (8 concurrent)1256.6lpm60.1 s26.02094.4
System Call Overhead7130734.2lps10.0 s715000.04753.8
System Benchmarks Index Score:2850.4

妹妹形态的姐姐机的成绩

以下结果是我先将一个 Arch Linux 安装到一个 U 盘里,然后重启姐姐机并 boot 到 Arch 的 Live USB 里,再 chroot 到这个 U 盘里完成的(因为 Live USB 的空间极其有限,无法安装测评所需要的环境,所以才需要另一个介质)。也就是说,考生是物理机上的 Arch Linux。可以认为是物理机的极限水平,作为“满分”来理解。

进行评测时,内核版本为 4.13.3-1-ARCH。

单核水平

时间跨度:12:21:34 - 12:50:57; 29m 23s

TestScoreUnitTimeIters.BaselineIndex
Dhrystone 2 using register variables39184704.1lps10.0 s7116700.03357.7
Double-Precision Whetstone4287.6MWIPS11.5 s755.0779.6
Execl Throughput6933.8lps30.0 s243.01612.5
File Copy 1024 bufsize 2000 maxblocks1184220.1KBps30.0 s23960.02990.5
File Copy 256 bufsize 500 maxblocks360234.0KBps30.0 s21655.02176.6
File Copy 4096 bufsize 8000 maxblocks3026237.0KBps30.0 s25800.05217.6
Pipe Throughput2572000.8lps10.0 s712440.02067.5
Pipe-based Context Switching220387.1lps10.0 s74000.0551.0
Process Creation15510.1lps30.0 s2126.01231.0
Shell Scripts (1 concurrent)9798.3lpm60.0 s242.42310.9
Shell Scripts (8 concurrent)2362.4lpm60.0 s26.03937.3
System Call Overhead3404625.8lps10.0 s715000.02269.8
System Benchmarks Index Score:2002.2
多核(4)水平

时间跨度:12:50:57 - 13:20:16; 29m 19s

TestScoreUnitTimeIters.BaselineIndex
Dhrystone 2 using register variables101980896.9lps10.0 s7116700.08738.7
Double-Precision Whetstone16591.4MWIPS10.4 s755.03016.6
Execl Throughput16309.8lps30.0 s243.03793.0
File Copy 1024 bufsize 2000 maxblocks1234598.7KBps30.0 s23960.03117.7
File Copy 256 bufsize 500 maxblocks349217.9KBps30.0 s21655.02110.1
File Copy 4096 bufsize 8000 maxblocks3523944.0KBps30.0 s25800.06075.8
Pipe Throughput6226154.4lps10.0 s712440.05004.9
Pipe-based Context Switching857240.5lps10.0 s74000.02143.1
Process Creation33736.1lps30.0 s2126.02677.5
Shell Scripts (1 concurrent)17407.6lpm60.0 s242.44105.6
Shell Scripts (8 concurrent)2433.3lpm60.0 s26.04055.6
System Call Overhead8323415.8lps10.0 s715000.05548.9
System Benchmarks Index Score:3850.0

准备工作

先验条件断言

在继续阅读之前,我假定你已满足以下条件:

  • 有 GNU/Linux 的操作基础,懂得 shell 的基本操作及一些常用 coreutils 的用法,会使用 vi 或 nano 编辑器在终端进行简单的文本编辑

  • 在姐姐机上有安装 MSYS2 或 Cygwin。MinGW 或 git for windows 勉强也可,但不推荐。推荐使用 MSYS2,下文均假定姐姐机安装了 MSYS2

  • 姐姐机上有安装兼容 xterm 的终端模拟器。最好是 mintty,MSYS2/Cygwin/MinGW 都带了这个。ConEmu 也可,但必须要么使用 cygwin-connector (不推荐),要么通过 ConEmu 运行一个 mintty 的子 GUI (推荐)

  • 有基本的查阅文档的能力,包括在线文档、Arch Wiki、StackOverflow 和 man page

  • 拥有较好的网络环境

下面是加分选项,满足这些条件能让双子系统(仮)用得更加舒服:

  • 有 C 语言和 Go 语言的编程经验

  • 有 zsh 的使用经验

  • 有为 AUR 或 MSYS2 等仓库编写 PKGBUILD 的经验

打开 CPU 虚拟化

如果你的 CPU 支持虚拟化,请先到 BIOS 里开启。这会让性能提升不止一点点。

安装 VirtualBox

请到 VirtualBox 官网下载,选择 Windows hosts。

安装过程略。

安装完成后,可以接着安装 Oracle 的扩展包来备用。

下载 Arch Linux 镜像

请到 Arch Linux 官网寻找合适的下载方式,可以通过 BT 下载也可以走 HTTP。

记得一定要校验 SHA1 或 PGP 签名!我曾经遇到过校验不通过的情况。这关乎安全问题所以请务必重视。

在中国大陆推荐使用清华的源,下文对 Pacman 配置的时候也优先使用清华源。根据我的实测,清华源是国内源中跟进最快的,Arch 官方也清华源其排入了 Tier1 源之一。

双子之路

本章开始,我们将从胚胎开始,一点一点地培养妹妹机,让她长大成人。

神说,要有光

硬件设定, 开启 EFI

  1. 打开 VirtualBox,在管理⇒全局设定中选择默认虚拟电脑位置,如D:\VM

  2. 新建虚拟电脑。名称建议和你想给妹妹机起的 Hostname 一致。本文将妹妹机命名为 EqAccel。类型选择 Linux,版本选择 Arch Linux (64-bit)。下一步。

  3. 进入内存分配页面,建议给妹妹机分配姐姐机一半的内存。我的姐姐机内存 8G,所以给妹妹机分配了 4096M。不要吝啬,毕竟我们要配置的是一个几乎能与姐姐机媲美的机器。下一步。

  4. 进入虚拟硬盘分配页面,选择“现在创建虚拟硬盘”,创建。建议选择 VirtualBox 自家的 VDI 格式。下一步。

  5. 这一步比较关键。如果姐姐机的硬盘空间比较宽裕,建议选择固定大小,能获得更大的性能和更好的扩展性(动态分配将难以在分配后随意修改大小,也不容易移植)。不过,对于大多数人而言,建议选择动态分配,因为将来的使用情况确实难以意料。本文选择动态分配。下一步。

  6. 建议分配姐姐机四分之一的硬盘给虚拟硬盘。我的姐姐机硬盘 1T,所以给妹妹机分配了 256G。由于是动态分配,不会一下子就占满。创建。

好了,到这一步妹妹机的胚胎就有了。不要着急启动!我们现在还需要给这个胚胎加一些优良性状。

  1. 在开始下面的操作之前,先将之前下载好的 Arch Linux 镜像移动到妹妹机的目录下,如D:\VM\EqAccel下。因为 VirtualBox 在这方面有些多管闲事,如果你事后移动了镜像文件的位置的话,它可能会 complain,这里我们就事先存到那了。

  2. 点击设置。常规⇒说明。里面写一些有关这个胚胎的信息。比如Arch Linux, installed from archlinux-2017.10.01-x86_64.iso

  3. 系统⇒主板。将启动顺序中的软驱勾掉,并将顺序改为光驱⇒硬盘⇒网络⇒软驱。将指点设备改为 PS/2 鼠标,这样我们就能少设置一个设备(USB)。勾上启动 EFI,我们之后将通过 EFI 引导至 LiveCD。

  4. 系统⇒处理器。处理器数量设为和姐姐机一样的数量,运行峰值设为 100%,如果可以请勾上启用 PAE/NX,无视警告。

  5. 系统⇒硬件加速。半虚拟化接口为默认,硬件虚拟根据自身情况选择,建议全勾上。

  6. 显示⇒屏幕。显存大小选择 4MB,无视警告。不要勾选硬件加速中的任何选项。

  7. 确认 显示⇒远程桌面 和 显示⇒录像 都没有启用。

  8. 存储。如果姐姐机用的是 SSD,请在下面的 EqAccel.vdi 里勾上固态驱动器。我用的不是 SSD,不敢保证可用性,如果在后面的步骤中遇到问题请查询相关文档。

  9. 声音。取消勾选启用声音。

  10. 网络⇒网卡1。勾选启用网络连接,连接方式选择网络地址转换(NAT)(这应该是默认值)。高级,控制芯片选择 Intel PRO/1000 MT 桌面 (82540EM),在较旧的 VirtualBox 版本中这可能不是默认值。勾上接入网线。确认端口转发是空的。可选的,单击 MAC 地址右边的刷新图标,直到生成出一个看起来顺眼的 MAC 地址为止。

  11. 确认除了网卡1以外的网卡都没启用。

  12. 确认四个串口端口都没启用。

  13. USB设备。取消勾选启用 USB 控制器。(后期需要的时候再勾,对当下而言,并不需要)

  14. 确认共享文件夹是空的。(是的,我们也不需要这个。日后我们会使用 SSHFS 来互动文件系统,下文会提到)

  15. OK

单击备份,生成快照。备份名称神说,要有光,备份描述硬件设定, 开启 EFI

天地玄黄,宇宙洪荒

base, grub, efibootmgr; 设置 LVM 分区; 设置 EFI 引导; 添加 pacman 镜像

本章开始就是正式地安装 Arch Linux 了。内容上主要参考了官方 Wiki 的指导,但是和官方的指导略微不同,我去掉了一些可以在后面再完成的步骤,以保证该章节完成后生成的快照更加纯净。

由于虚拟机与物理机的差异,如果你是想在物理机上安装 Arch Linux 的话,请注意下文并不完全适用于物理机的安装。对于一些在安装物理机的情形下须要特别留意的步骤,我会做说明,如“物理机不要这么玩!”“物理机要特别注意”等。

在继续下面的步骤之前,请最好先关闭姐姐机的其他应用,尤其是硬盘读写频率很高的应用,以避免在安装妹妹的过程中在姐姐身体里产生太多的硬盘碎片。

如果下面有任何一步出了差错,强烈建议恢复到上个快照然后再重新开始这章的内容。

在 VirtualBox 下

  1. 打开设置。存储。单击 IDE 下的“没有盘片”,然后单击“分配光驱”最右边的光盘图标,选择一个虚拟光盘文件,选择之前放到妹妹机目录下的 ISO 镜像。勾上演示(Live)光盘。OK。

  2. 启动!

EFI 引导可能会用 1~2 分钟的时间,请耐心等待。

看到下面这个界面的话,就可以继续接下来的步骤了。

顺带一提,留意一下就会发现这个 shell 并不是 bash 而是 zsh。

  1. 联网,并测试网络。

    # dhcpcd
    # ping -c 2 ekyu.moe
  2. 校时

    # timedatectl set-ntp true
  3. 下面准备进行逻辑分区。物理机不要这么玩!如果物理机上已经有了另一个系统,那么就不需要再分 EFI 区了。

  4. 列出所有的硬盘

    # fdisk -l
  5. 格式化相应的硬盘。一般来说会是/dev/sda,如果是安装物理机请务必再三确认!。

    # fdisk /dev/sda
  6. 上面的命令会进入fdisk的交互命令行,下面准备处理设备/dev/sda

    g      # 创建 GPT 分区表。物理机:如果已经存在 EFI 分区就不需要了
    
    n      # 创建新分区,将作为 EFI 分区
    1
    ### 直接回车,默认 2048
    +512M  # 一般 EFI 分区的大小都是 512MB
    
    n      # 创建另一个分区,将作为我们的主要分区
    2
    ### 两次回车,把剩余的空间全部分配给它
    
    t      # 更改分区 label
    1      # 更改 1 号分区的 label
    1      # 1 表示 EFI System
    
    t
    2
    31     # 31 表示 Linux LVM
    
    p      # 打印本次操作的结果,现在应该有 /dev/sda1 和 /dev/sda2 两个分区了
    w      # 确认无误后,保存

    下图可供参考:

  7. 下面准备进行 LVM 分区。

    这里说明一下为什么要在 VM 里搞 LVM。因为 LVM 很灵活,缩小扩大之类的操作方便太多,尽管会带来一丁点的性能损失。如果是在安装物理机,也推荐使用 LVM 分区。可以参考 Arch Wiki。网上大多有关 Arch Linux 的安装教程都没有提到有关 LVM 分区的内容,这里我算是补上了。
  8. 查看可用作物理卷(PV)的设备。我们之前创建的/dev/sda1/dev/sda2应该会在列表中。

    # lvmdiskscan
  9. 创建物理卷。这里我们是打算将/dev/sda1作为 GPT 分区,/dev/sda2作为主分区,所以我们就选择对/dev/sda2进行 LVM 分区。物理机要特别注意不要选错。

    # pvcreate /dev/sda2
  10. 检查刚刚创建的物理卷

    # pvdisplay
  11. 创建卷组(VG)。vdi是卷组的名字,考虑到我们用了 vdi 格式来作为妹妹机的虚拟硬盘,这里用vdi作为卷名是为了让我们日后记住我们用了 vdi,当然你也可以起别的名字。对于物理机安装,你可以把多个不同的物理磁盘归到一个卷组里,这是 LVM 的优势之一。

    # vgcreate vdi /dev/sda2
  12. 创建逻辑卷。这一步就是在建立我们平时所理解的“分区”了。

    一般来说,我们在安装 Linux 系统时会至少分 3 个区,一个挂载在/,一个挂载在/home,一个作为swap。有些更讲究的人可能还给/var等单独分区。如果是在物理机上安装,我比较推荐至少三个分区的方案,这是为了方便以后哪天想换系统,这时只要挂载/,不挂/home,然后安装系统,就可以一定程度上保证个人的文件不会丢失。

    但是这里,对于双子系统(仮)的情况,我们只分两个分区,分别作为/和 swap,因为我们大概不会换系统。就算要换,直接新开一个虚拟机会更加方便。相比之下,未来的难以预料可能会让现在自以为谨慎的分区方案成为将来的阻碍,要知道修改分区不管怎么说都是件极其麻烦和极容易造成损失的操作。

    我们首先创建 swap 分区,大小建议设为给妹妹机分配的物理内存的两倍。之前给妹妹分配了 4G 内存,所以这里分配 8G swap。剩余的空间全部分给/-n后的内容为该逻辑卷的名称,可以自己改。

    # lvcreate -L 8G vdi -n swap
    # lvcreate -l +100%FREE vdi -n root
  13. 格式化分区。逻辑上说,我们刚刚一共创建了三个分区,一个 EFI 分区,两个 LVM 分区。现在准备将它们格式化。

    • 对于 EFI 分区,只能用 FAT32 文件系统

    • 对于 root 分区,我们采用 ext4 文件系统

    • 对于 swap 分区则使用mkswap来格式化

    # mkfs.fat -F32 /dev/sda1
    # mkfs.ext4 /dev/mapper/vdi-root
    # mkswap /dev/mapper/vdi-swap
  14. 挂载分区。这一步我们将刚刚创建并格式化好的分区临时挂载到/mnt,为接下来的正式安装做准备。

    # mount /dev/mapper/vdi-root /mnt
    # mkdir /mnt/boot
    # mount /dev/sda1 /mnt/boot
    # swapon /dev/mapper/vdi-swap
  15. 设置 pacman 的镜像。对/etc/pacman.d/mirrorlist的修改会随着下一步自动复制到新系统内。

    如果你有更科学的手段的话,我建议跳过这步,改为直接设置http_proxyhttps_proxy变量。提示一下,对于妹妹来说姐姐的 IP 地址默认是192.168.56.17。如果不确定,可以在 VirtualBox 的 全局工具⇒主机网络管理器 里查看对应网卡的 IP 地址。

    另外,如果你更熟悉 nano 编辑器的话就用 nano,下面不再重复提示了。

    # vi /etc/pacman.d/mirrorlist

    在开头加上这三行,这几个镜像我个人感觉跟进很快,第三个还是官方镜像,不过如果网络比较魔法的话应该很慢

    /etc/pacman.d/mirrorlist
    Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
    Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
    Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch
  16. 安装系统。是的,终于到这步了!

    这里我们只安装最基本的 base 组,别的东西我们以后再装。

    如果你不想让刚刚设置的 mirrorlist 被拷贝到妹妹机里,请加上参数-M
    # pacstrap /mnt base
  17. 生成分区表并检查。

    一定要检查,这很重要!
    # genfstab -U /mnt >> /mnt/etc/fstab
    # cat /mnt/etc/fstab

    下图为一个配置正确的分区表,可供参考:

  18. 切换视角到刚刚出生的妹妹(chroot 到/mnt上)。之前我们一直在使用接生婆(LiveCD)的视角,现在准备切换到妹妹身上,完成接下来的安装。

    不过,在这之前还有个步骤。由于这个刚刚安装完的系统并没有带 LVM 的守护进程,我们还要临时连一个“脐带”过去。

    “创建脐带”(挂载 LiveCD 的 /run 到临时挂载点)

    # mkdir /mnt/hostrun
    # mount --bind /run /mnt/hostrun

    “切换视角”(chroot)

    # arch-chroot /mnt

    “连接脐带”

    # mkdir /run/lvm
    # mount --bind /hostrun/lvm /run/lvm
  19. 现在我们就在妹妹的视角之上了。我们要做的第一件事是为内存盘镜像(initial ramdisk)加入 LVM 的 hook 扩展,这是因为我们的根分区建立在了 LVM 上[9]

    # vi /etc/mkinitcpio.conf

    在 block 与 filesystem 这两项中间插入 lvm2,如下图所示:

  20. 重新构建 initrd。

    # mkinitcpio -p linux
  21. 安装引导工具 grub 和 efibootmgr。

    如果是在安装物理机,且 CPU 是 intel 的,还要安装 intel-ucode;如果物理机上还有其他系统,还需要 os-prober。这些都请在这步完成。
    # pacman -S grub efibootmgr
  22. 配置 grub。

    # grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub
    # grub-mkconfig -o /boot/grub/grub.cfg
  23. 切断脐带。

    # umount /run/lvm
  24. 使 EFI 引导脚本生效。

    下面的操作仅适用于 VirtualBox 的情况。对于物理机,可能会根据主板厂商的不同而变,而如果已经可以正常引导(已经有了另一个系统且也是 EFI 引导),这一步就没有必要了。
    # mkdir /boot/EFI/BOOT
    # mv /boot/EFI/grub/grubx64.efi /boot/EFI/BOOT/BOOTX64.EFI
    # rm -rf /boot/EFI/grub
  25. 设置 root 密码。

    # passwd
  26. 切出妹妹视角。

    # exit
  27. 彻底切断脐带。

    # umount /mnt/hostrun
    # rm -rf /mnt/hostrun
  28. 卸载临时挂载的分区。

    # swapoff /dev/mapper/vdi-swap
    # umount -R /mnt
  29. 接生婆(LiveCD)可以下班了。

    # sync && shutdown now
  30. 打开设置⇒存储⇒存储介质,移除虚拟光盘,取消勾选演示(Live)光盘。OK。

单击备份,生成快照。备份名称天地玄黄,宇宙洪荒,备份描述base, grub, efibootmgr; 设置 LVM 分区; 设置 EFI 引导; 添加 pacman 镜像

阳清为天,阴浊为地

sudo, vim, openssh, 启用 networkd (dhcp), 启用 resolved, 启用 sshd, 设置 hostname, 添加 equim, 设置 wheel 用户组, ulimit 设置 nofile nproc 为 40960, stack 为 unlimited, 生成 rsa4096 和 ed25519 host key, 添加 SSH 端口映射

妹妹机已呱呱坠地,接下来我们要为她起名字,洗身子,打疫苗,带她看看这个世界。

本章将为妹妹机设定核心功能,如网络连接、SSHD 等,同时设置好 Hostname 并创建一个一般用户以避免 root 裸奔。

  1. 启动。用户名输入 root,密码在上一章的最后已设置。

  2. 设置主机名,顺带设置一下姐姐机的 host,为以后姐妹互动提供方便。

    不要着急 pacman 装东西,现在连网络都没设置。
    # echo EqAccel > /etc/hostname (1)
    # vi /etc/hosts
    1EqAccel为妹妹机的名字。

    在末尾添加下面这行。

    /etc/hosts
    192.168.56.17 EqHome EqHome (1)
    1EqHome为姐姐机的 Hostname
  3. 设置时区并设置时间漂移。

    # ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    # hwclock --systohc --utc
  4. 设置 Locale。个人主张只启用 en_US.UTF-8

    # vi /etc/locale.gen

    找到你要启用的 Locale,如 en_US.UTF-8,然后把那行前面的注释去掉,保存。

    # locale-gen
    # vi /etc/locale.conf

    写入以下内容

    /etc/locale.conf
    LANG=en_US.UTF-8
    LANGUAGE=en_US.UTF-8
  5. 配置网络,这里是最最最简单的 DHCP,完全被动,全靠姐姐。

    # ip a                                   # 找到网卡名称,如 enp0s3
    # vi /etc/systemd/network/dhcp.network   # 也可以改成别的名字,如 eqdhcp.network

    写入以下内容,假设 enp0s3 是刚刚找到的网卡的名称

    /etc/systemd/network/dhcp.network
    [Match]
    Name=enp0s3
    
    [Network]
    DHCP=ipv4
  6. 启用网络并设置开机自启动。

    # systemctl enable --now systemd-networkd
    # systemctl enable --now systemd-resolved
  7. 设置从 DHCP 获取 DNS。

    # ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
  8. 检查网络。

    # ping -c 2 ekyu.moe
  9. 开启 NTP。

    # timedatectl set-ntp true
  10. 安装 sudo vim openssh。如果不想要 vim 也可以不装,看个人方便。

    如果在上一章安装时没有设置 pacman 镜像而是设置了http_proxy的话,请在这里也临时设置一下,但不要着急写到/etc/profile.d之类的地方,也不推荐写到/etc/profile.d
    # pacman -S sudo vim openssh
  11. 设定 sudoers file。

    # EDITOR=vim visudo

    取消 %wheel ALL=(ALL) ALL 那行的注释,同时在底下加上下面这行。

    在这里加入 PATH 是比较危险的,不推荐这么做。
    /etc/sudoers
    Defaults env_keep += "http_proxy https_proxy no_proxy EDITOR VISUAL"

    下图可供参考:

  12. 添加一般用户并为其设置密码。这里我们用 equim 作为用户名。注意用户名不能使用大写或数字开头。

    # useradd -mG wheel equim
    # passwd equim
  13. 测试 sudo 是否可用。

    # su -l equim
    $ EDITOR=123123 sudo sh -c 'echo $EDITOR' (1)
    $ exit
    1如果输出也为 123123,则证明刚刚的设置有效。
  14. 酌情修改 ulimit 以减小内核对用户的限制。

    这一步要非常小心谨慎,你要很清楚你在干嘛,否则建议不要乱来。

    尤其是物理机!不要这样乱玩!

    # vim /etc/security/limits.conf

    以下是我个人的设置,仅供参考

    /etc/security/limits.conf
    * hard nproc 40960
    * soft nproc 40960
    * hard nofile 40960
    * soft nofile 40960
    * hard stack unlimited
    * soft stack unlimited
  15. 生成 4096 位的 RSA host key,以免其自动生成 2048 位的,同时顺便也把 ed25519 的 host key 生成了。

    # ssh-keygen -t rsa -b 4096 -N "" -f /etc/ssh/ssh_host_rsa_key
    # ssh-keygen -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key
  16. 配置 SSHD。

    # vim /etc/ssh/sshd_config

    Hostkey /etc/ssh/ssh_host_rsa_keyHostkey /etc/ssh/ssh_host_ed25519_key 的注释去掉。

    同时,将 Compression 设为 no,毕竟都在本地[10]

    去掉 X11Forwarding 的注释并确认其为 no。这个功能以后我们需要的时候再打开。

    酌情考虑设置 PrintLastLog 为 no[11]

  17. 设置 SSHD 开机启动。

    # systemctl enable sshd
  18. 关机。

    没有意外的话,这次注销以后我们将再也不会以 root 登录。
    # sync && shutdown now
  19. 打开设置⇒网络⇒网卡1⇒高级⇒端口转发,加入一条规则,名称为 SSH,映射子系统 22 端口到主机的 127.0.0.1:6666。注意,子系统 IP 留空(代表 0.0.0.0),而主机 IP 是 127.0.0.1,不要留空!映射到主机的端口号可根据喜好自己改。

    如下图:

单击备份,生成快照。备份名称阳清为天,阴浊为地,备份描述sudo, vim, openssh, 启用 networkd (dhcp), 启用 resolved, 启用 sshd, 设置 hostname, 添加 equim, 设置 wheel 用户组, ulimit 设置 nofile nproc 为 40960, stack 为 unlimited, 生成 rsa4096 和 ed25519 host key, 添加 SSH 端口映射

阡陌交通,鸡犬相闻

zsh, git, wget, openbsd-netcat, 设置 .vimrc, .zshrc, 设置 git 用户及 ssh 密钥,设置 github 的 gitconfig

妹妹已经学会走路了,现在我们要教会她说话,让她认好姐姐,不和陌生人说话。

在上一章完成之后,我们已经打通了姐妹之间沟通的核心桥梁——SSH 与其端口映射。从本章开始,我们所有的操作都是通过姐姐机 SSH 连接到妹妹机来完成的。

本章,我们会将妹妹机配置得更加可用。

在继续往下走之前,我们要在姐姐机做一些额外的工作来迎接妹妹:

  1. 安装 dokany 1.0.5注意版本号。我们选择下载DokanSetup_redist-1.0.5.1000.exe这个文件,下载完成后进行安装,不再赘述。

    dokany 是 win-sshfs 的核心依赖,所以要先安装。
  2. 安装 Foreveryone-cz/win-sshfs 1.6.1[12]。截至本文撰写时,1.6.1 是最新版本。尽管还不是稳定版本,但只要注意一些细节就不会玩坏(下文的注意事项会提到)。

好了,现在切换到 VirtualBox 上。

  1. 启动⇒无界面启动。我们不再需要界面,以后我们都会选择“无界面启动”。

然后,可以把 VirtualBox 关了。恩,没问题的,需要的时候再打开。

在姐姐机上,打开 win-sshfs。我们要配置一下。

  1. Drive Name,建议就按照 Hostname 填,比如 EqAccel。

  2. Host,当然是 127.0.0.1。

  3. Port,按照之前设定的填,比如 6666。

  4. Username,填我们刚刚创建的那个一般用户的用户名,比如 equim。

  5. Authentication method,选 Password。

  6. Password,填上一般用户的密码。

  7. Directory,一个半角的.

  8. Drive Letter,建议选Z:,勾上 Mount at login。

  9. Mount folder 留空。

  10. KeepAlive 填 30,别的选项不用管了。

  11. 左下角的 Virtual drive 选 OFF。

  12. 点 Save,然后 Mount。

不出意外的话,妹妹机的~目录就被挂载到姐姐机的Z:上了。当然,现在大概只有几个零星的 dotFiles。

接下来,打开姐姐机的 Shell。

  1. 为 SSH 添加妹妹机的规则。

    $ vim ~/.ssh/config

    格式如下

    ~/.ssh/config
    Host EqAccel
      HostName 127.0.0.1
      Port 6666
      User equim
      Compression no
      PreferredAuthentications password
  2. 连接到妹妹机的 shell。首次连接会问你指纹是否正确,我们填yes即可。

    $ ssh equim@EqAccel

    然后输入妹妹机一般用户的密码。

恭喜,到这步双子系统(仮)的基本安装已经完成了。在接下来的章节中,我们所做的都只是为了给将来的姐妹间的开发与互动提供更多的方便罢了。

从这里开始,下面的内容就因人而异了,我所偏好的环境也未必适用于所有人
  1. 开启 Pacman 的 Color 选项。

    $ sudo vim /etc/pacman.conf
  2. 修改 Pacman 镜像。

    $ sudo vim /etc/pacman.d/mirrorlist
  3. 更新。如果距离上个快照的建立已经过去了一段时间的话建议执行此步。

    $ sudo pacman -Syu
  4. 安装 zsh,git,wget,openbsd-netcat

    $ sudo pacman -S zsh git wget openbsd-netcat
  5. 生成一个专门用于 git 的密钥对,你也可以将已有的密钥复制过去(我们刚刚已经通过 sshfs 打通了一条路了)。

    $ ssh-keygen -t ed25519 -f $HOME/.ssh/git
    $ chmod 700 .ssh
    $ chmod 600 .ssh/*
    $ vim ~/.ssh/config

    以下配置仅供参考

    ~/.ssh/config
    # git 区
    Host github.com
      HostName github.com
      User git
      IdentityFile ~/.ssh/git
      ProxyCommand /usr/bin/nc -X5 -x EqHome:3210 %h %p
    
    # 全局设置
    Host *
      Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
      HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa
      KexAlgorithms curve25519-sha256@libssh.org,curve25519-sha256
      ServerAliveInterval 30
      ServerAliveCountMax 3
      Compression yes
  6. 配置 git

    $ git config --global user.name xxxx
    $ git config --global user.email xxxx@xxx.xxx
  7. 配置 zsh

    $ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
    $ git clone https://github.com/zsh-users/zsh-syntax-highlighting.git $ZSH_CUSTOM/plugins/zsh-syntax-highlighting
    $ git clone https://github.com/zsh-users/zsh-autosuggestions.git $ZSH_CUSTOM/plugins/zsh-autosuggestions
    请自行配置 ~/.zshrc~/.vimrc 等文件
  8. 关机

    $ sudo sync && sudo shutdown now

单击备份,生成快照。备份名称阡陌交通,鸡犬相闻,备份描述zsh, git, wget, openbsd-netcat, 设置 .vimrc, .zshrc, 设置 git 用户及 ssh 密钥,设置 github 的 gitconfig

原罪

base-devel, pacaur, nodejs, yarn, go-pie, ruby docker, httpie, unzip, pv, asciinema, tree, htop, lsof, dos2unix 设置 docker 用户组, 设置 docker 代理

妹妹已渐渐长大成人,越来越膨胀。

本章将为妹妹机设置基本的开发环境。因人而异。

我们之前的安装是如此纯净,而这一步却安装了一堆东西破坏了这种纯净,所以我称之为“原罪”。
  1. 无界面启动妹妹机。然后从姐姐机 SSH 连接到妹妹机的 Shell,用 SSHFS 挂载妹妹机文件系统。

  2. 安装 base-devel。这组软件提供了基本的编译与构建工具。

    $ sudo pacman -S --needed base-devel
  3. 安装 pacaur。这可以让我们更加方便地安装 AUR 仓库的软件。

    pacaur 现在已经停止维护了[13],在将来可能会被移出 AUR。你可以在 wiki 里找一些别的替代品,比较推荐的是 trizen
    $ git clone https://aur.archlinux.org/cower.git
    $ git clone https://aur.archlinux.org/pacaur.git
    $ cd cower
    $ makepkg -sirc --skippgpcheck
    $ cd ..
    $ cd pacaur
    $ makepkg -sirc
    $ cd ..
    $ rm -rf cower pacaur
  4. 安装你想装的工具。

    $ pacaur -S nodejs yarn go-pie ruby docker httpie unzip pv asciinema tree htop lsof dos2unix

    然后可以自行配置一下 ~/.config 目录。

    你也可以在 .zshrc 里添加 alias pacman=pacaur。
  5. 如果你安装了 go,可能需要配置一下 GOPATH。

    $ mkdir go

    然后在 .zshrc 中添加export GOPATH=$HOME/go,尽管这就是默认值。

  6. 如果你安装了 docker,可能需要设置一下用户组和代理。

    $ sudo usermod -aG docker equim
    $ sudo mkdir -p /etc/systemd/system/docker.service.d
    $ sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf

    以下内容供参考。

    /etc/systemd/system/docker.service.d/http-proxy.conf
    [Service]
    Environment="HTTP_PROXY=http://EqHome:2130" "HTTPS_PROXY=http://EqHome:2130" "NO_PROXY=registry.docker-cn.com"

    然后重新载入 systemd。

    $ sudo systemctl daemon-reload
  7. 关机。

    $ sudo sync && sudo shutdown now

单击备份,生成快照。备份名称原罪,备份描述base-devel, pacaur, nodejs, yarn, go, ruby docker, httpie, unzip, pv, asciinema, tree, htop, lsof, dos2unix 设置 docker 用户组, 设置 docker 代理

双子的百合度养成(更高的集成度)

以上即有关妹妹机安装与配置的内容。如果还想开启一些额外的功能,请查看番外一章。

我们与妹妹机的互动主要都通过本地网络进行。比如在妹妹机上开一个 Web 应用监听了妹妹机的 0.0.0.0:5000(注意不能是 127.0.0.1,至少要绑定在 VirtualBox 的 Host-Only 网卡上),我们可以在 VirtualBox 里设置一个端口映射,将姐姐机的 127.0.0.1:5000 和妹妹机的 0.0.0.0:5000 映射起来,这样我们在姐姐机的 127.0.0.1:5000 就能访问妹妹机的 5000 端口了。

本章将提供一些能在姐姐机上更好地互动妹妹机的技巧,需要一定的 C、Go 语言和 Shell 脚本的知识。

双子同居一室(集成到 ConEmu/mintty)

如果你使用的是 ConEmu + mintty,那么你可以添加一个针对妹妹机的 Task。下面的规则可供参考:

D:\path\to\your\mintty /usr/bin/ssh equim@EqAccel -new_console

如果你只是用了 mintty,可以参考 mintty wiki 里提到的方法建立一个快捷方式。

姐姐一键召唤妹妹(集成启动)

如果你不想每次开启妹妹机都要打开 VirtualBox 的话,完全可以通过在姐姐机写一个脚本来实现。

VirtualBox 提供了一些 CLI 工具,可以在不用 GUI 的情况下完成一些操作。如要从命令行启动虚拟机,参数为:

$ VBoxManage startvm EqAccel --type headless (1)
1EqAccel为虚拟机的名称,headless为无界面启动。

我自己用 Go 语言封装了这个启动脚本,同时还带了一些的声音与视觉效果。效果如下(文首图就是这个):

其实还带声音的(借用了 SAO Utils 的音效),截图就表现不出来了。

姐姐一键哄妹妹睡(集成关机)

你可以在不进入妹妹机的 Shell 的情况下从姐姐机的 Shell 关闭妹妹机。

$ ssh -t equim@EqAccel 'sudo sync && shutdown now'

在姐姐机可以设置一个 alias 来方便这个操作:

alias DISMISS="ssh -t equim@EqAccel 'sudo sync && shutdown now'"

姐姐与妹妹心灵相犀(集成端口映射)

如果你不想每次为妹妹机设定端口映射都要打开 VirtualBox 的话,也可以通过姐姐机的脚本实现。

例如,要开启 姐姐127.0.0.1:5000<->妹妹0.0.0.0:3000 的 TCP 映射并命名为 test,操作如下:

$ VBoxManage controlvm EqAccel natpf1 "test,tcp,127.0.0.1,5000,,3000"

要删除名为 test 的映射,操作如下:

$ VBoxManage controlvm EqAccel natpf1 delete test
controlvm只能在 VM 为开机状态时才能用。

那么,如果你想列出当前的端口映射列表呢?VirtualBox 自带的命令行工具没有提供这个功能,不过你可以自己去解析妹妹机的 vbox 文件,是 XML 格式。

同样,我也用 Go 语言写了一个工具来方便我在姐姐机用命令行添加/删除/查看端口映射。

你可以自己撰写这类工具。如果想要我演示的这些工具的话也可以私下找我。

从妹妹机召唤姐姐的程序

如果你是 tmux+vim 这种全终端工作流的话可以直接无视这段。

比如,在妹妹机输入subl xxx,姐姐机就会用她的 Sublime 打开妹妹机 SSHFS 下对应的 xxx 文件。

这个功能目前我自己还没有实现。这是个我近期实现的功能,思路比较简单,就是姐姐机开一个守护进程,然后妹妹机通过 RPC 远程调用。我自己是通过 gRPC 实现的,目前在妹妹机上支持这几种指令

  • start: 在姐姐机上通过 sshfs 用资源管理器打开妹妹机的某个文件夹

  • subl: 在姐姐机上通过 sshfs 用 Sublime 打开妹妹机的某个文件或文件夹

  • clipopaste: 与姐姐机共享剪贴板,可从姐姐机粘贴,也可复制到姐姐机。

如果集成已经达到了这种程度,就需要注意安全问题了(主要问题是要防止远程代码执行),如:

  • 姐姐机的守护进程仅监听 VirtualBox 的网关地址

  • 守护进程必须限制只有指定的程序能被妹妹机打开,并要对参数做严格的检查

  • 妹妹机的操作范围不能逾越到姐姐机的文件系统

  • 姐姐机要做一定程度的鉴权(可以采用 TLS 客户端证书质询等方法)

  • …​

维护

本章将着重于对妹妹机的日常维护工作。

可以先参考一下Arch Wiki

勤升级

对于 Arch Linux 这种滚动型的发行版而言,升级是常有的事。勤升级可以避免一次更新太多的软件包而导致滚挂。简言之就是多跑跑pacman -Syu

勤备份

你可以在使用妹妹机一段时间后(比如两天),或者在想折腾什么大家伙之前建立一个快照,名称为建立那天的日期。这样我们可以很方便地回到之前较为纯净的状态,这也是为了姐姐机的硬盘着想。

勤恢复

当你感觉现在妹妹机让人用得不太舒服的时候,请恢复到对应的做出改变就能让人用得更加舒服的快照,然后重新继续一些安装步骤,再重建这些快照。我可能表达的不太好,反正这有点类似 git 的 rebase。

留意姐姐机的硬盘

动态分配的虚拟硬盘对宿主机并不是很友好。请多留意一下姐姐机的硬盘碎片。另外,如果想压缩妹妹机的虚拟硬盘文件的话,可以在关闭妹妹机之后再姐姐机上操作:

$ VBoxManage modifymedium --compact D:/VM/EqAccel/Snapshots/xxxx.vdi
每个快照实际上就是一个虚拟硬盘文件,位于 Snapshots 目录外面的那个 vdi 可能非常小(因为我们一上来就备份了一个)。所以请压缩对应的快照。

一些教程可能会先让你对虚拟机的硬盘空间进行 0 填充(实质上也类似于一种硬盘碎片整理),但这个操作非常消耗时间和空间,也并不见得能帮助多少(这个操作消耗的时间足够你从头重装一遍了)。

一般情况下,妹妹机的虚拟硬盘文件是只会增大不会减小的。如果你装了一堆东西,就算是之后卸载,妹妹机的虚拟硬盘文件也是不会减小的。这也是为什么我们要勤备份的原因。

注意事项

  1. 请不要在 SSHFS 挂载的分区上操作 git 和 svn!会导致崩溃!就是说,比如你的编辑器带了个 git 插件,那么在打开妹妹机分区上的带 git 托管的文件前请务必把 git 插件停了,同样,也建议最好不要把姐姐机带 git prompt 的 Shell cd 到妹妹机分区里(也没这个必要)。git 与 svn 的问题目前所有的 SSHFS Win 实现都没有解决。

  2. 在关闭姐姐机之前,请务必先自然地关闭妹妹机!

番外

本章将提供一些额外的指南。

运行妹妹机的 GUI 应用

一般来说我们并没有这个必要。如果你执意要运行妹妹机的 GUI,或者只是想瞎折腾,那就接着看吧。

  1. 首先我们要在姐姐机上安装一个 X Server。这里推荐 Xming。注意安装的时候不要把 puTTy 装了,也不需要什么 wizard。安装完成后打开 Xming,它会保持在后台。

  2. 打开妹妹机的 Shell。安装 xorg 组,它会提供一个 X Client。

    如果你还想更小,那就只安装 xorg-xauth,不过这可是连字体都没有。
    $ sudo pacman -S --needed xorg
  3. 为 SSHD 修改一些设置。

    $ sudo vim /etc/ssh/sshd_config

    做如下修改,有什么不明白的请参考 sshd_config(5)

    /etc/ssh/sshd_config
    AllowAgentForwarding yes
    AllowTcpForwarding yes
    X11Forwarding yes
    X11DisplayOffset 10
    X11UseLocalhost no
  4. 重启 SSHD。

    $ sudo systemctl restart sshd
  5. 回到姐姐机的 Shell,为 SSH 添加一些设置。

    $ vim ~/.ssh/config

    在妹妹机的 Host 下添加这些,有什么不明白的参考 ssh_config(5)

    ~/.ssh/config
    ForwardAgent yes
    ForwardX11 yes
    ForwardX11Trusted yes
  6. 为姐姐机设置 DISPLAY。

    $ export DISPLAY=127.0.0.1:0
  7. 重新连接到妹妹机,注意这时候两边都开启了 X11 转发。

    $ ssh equim@EqAccel
  8. 安装你想用的 GUI 应用,这里以 xorg-xclock 为例。

    $ sudo pacman -S xorg-xclock
  9. 运行

    $ xclock

是不是很神奇?

当然,功能非常局限,你可能还要对 X Client 做更多的设置(字体、DPI 等)才能用得舒服。此外,X11 也没法转发声音。

为妹妹机挂载 USB 驱动器

以 U 盘为例。

  1. 如果妹妹机开着,先关机。

  2. 打开 VirtualBox,设置⇒USB 设备,勾上启动 USB 控制器,选 USB 2.0 或者 3.0,OK。

  3. 启动妹妹机。这里我们需要 VirtualBox 的界面,如果是无界面启动的可以在 VirtualBox 上点击“显示”。

  4. 将 U 盘插入姐姐机。

  5. 在 VirtualBox 界面,设备⇒USB,勾上你刚刚插入的 U 盘。注意看清楚别选成什么鼠标键盘了。如图所示:

    挂载完成后你会发现,姐姐机已经无法访问 U 盘了,这是因为 U 盘此时已经被妹妹机独占了。

  6. 打开妹妹机的 Shell,列举当前可用的驱动器,从里面找出刚刚插入的 U 盘。

    $ lsblk -f
  7. 如图所示,这里 U 盘是 /dev/sdb

  8. 挂载 U 盘。不一定要挂载到/mnt/usb,别的地方也行。这只是约定俗成的。

    $ sudo mkdir /mnt/usb
    $ sudo mount /dev/sdb1 /mnt/usb

    默认的,挂载上去的盘属于 root。如果你想挂载给当前用户用,可以设定 gid 和 uid,也可以设置 umask 等参数,具体请查询相关 manpage,不再赘述。

    给个例子:挂载给当前用户,设定文件权限为 644,文件夹权限为 744。

    $ sudo mount -o dmask=033,fmask=133,gid=$(id -g),uid=$(id -u) /dev/sdb1 /mnt/usb
  9. 这时候访问/mnt/usb就能看到 U 盘的内容了。

    $ cd /mnt/usb
    $ ll
  10. 卸载 U 盘。

    $ sudo sync && sudo umount -R /mnt/usb
  11. 把 U 盘归还给姐姐机,和第 5 步一样,不过这里是取消勾选。


1. 封面来自 pixiv
2. 关于 WSL 更多的“不正经”之处,以及它所提供的东西与我们真正的需求之间的矛盾,推荐看看 Medium 上的这篇文章
3. 其实很多人觉得 Cygwin/MSYS2 慢都是因为 shell 调用 fork(2) 时太慢而带来的“错觉”,实际上并没有慢得那么夸张
5. fd 是比较 POSIX 的叫法,在 Windows 下标准的说法是 Handle。
6. ……于是如果你在 cygwin-connector 转换的终端下又用 winpty 去运行一个原生 CLI 应用的话,就相当于是绕着 ASCII escape 跑了一圈。(cygwin-connector 好不容易才把 ASCII escape 转成原生 Console API,然后现在你又要用 winpty 把原生的 Console API 调用转成 ASCII escape,然后 cygwin-connector 再把它转回 Console API,画面感十足((
7. Linux 上有至少 30 种 signal(见 signal(7)),而 Windows 上只有 6 种(见 MSDN),而且 Windows 的 signal 还不是直接在系统层面实现的(见 SO 上的这个回答)。
8. Why Vagrant: Vagrant provides easy to configure, reproducible, and portable work environments built on top of industry-standard technology and controlled by a single consistent workflow to help maximize the productivity and flexibility of you and your team.
10. ssh(1): Compression is desirable on modem lines and other slow connections, but will only slow down things on fast networks.
11. sshd_config(5): PrintLastLog Specifies whether sshd(8) should print the date and time of the last user login when a user logs in interactively. The default is "yes".
12. 这其实是原 win-sshfs 的一个 fork,原分支已不再维护,目前较为活跃的也就这个分支了。

知识共享许可协议
本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

本文链接:https://ekyu.moe/article/futago-system-kari-setup-guide/