在 Ubuntu 的 KVM 中安装 Windows 系统

为什么要折腾 KVM 虚拟机

最近因为公司的事情,没有太多时间进行写作,就用一篇技术类的文章来凑数吧。

事情是这样的,我们公司有一个小东西是基于嵌入式的系统开发的,不属于 Android 也不属于 iOS 平台。嗯,这意味着什么呢?这意味着开发这个小东西的语言是 C 语言,而不是 Java, Objective-C 抑或是 Swift。所以我们需要一个 Cross Compiler,也就是俗称的交叉编译环境来编译这个代码。

其实 Xcode 编译出来的 iOS App 也属于交叉编译的范畴。

然鹅,这个交叉编译环境竟然只有 Windows 平台的!其实,好像除了 GCC 之外,好用的交叉编译环境都是 Windows 下面的。估计很多玩嵌入式的同学应该都知道,现在业内用得比较多的也就是 KeilIAR 系列了。而及其不幸的是,两者都是 Windows 特供的,没有 macOS 或 Linux 版本。

为什么 Windows 会让我这么得不爽呢?因为平常为了更好的提高工作效率(其实是为了公司的逼格够高),除了不得不使用的行业应用软件必须要跑在 Windows 下的时候,我们只用 Mac 不用 Windows。所以,我们基本上没有闲置和富裕的 Windows 主机,不!是压根就没有,没有什么「基本没有」一说。

而在服务器端,更不要跟我说什么 Windows Server 云云的。作为一个 macOS 和 Ubuntu 的脑残用户,我是不可能在 Bare metal 上跑一个 Windows Server 的。服务器我们只跑 Linux,别的没兴趣。

那么问题来了,我们有一套自动化编译系统,也就是大家所熟知的 CI 体系 (Continuous integration),用的是 Atlassian 的全家桶:Bitbucket、Bamboo、JIRA 还有 Confluence 什么的,全部跑在 Linux 平台的 Docker 虚拟化容器中。

现在我们想把这个小东西也自动化编译器来,以便更好地把人力释放出来,也方便未来跟踪和管理每一次 Release 的内容。而第一个要解决的问题就是:我们没有 Windows 的服务器。

既然现在虚拟化这么流行,那么我们就利用现有的 Ubuntu 服务器虚拟化一个 Windows 好啦,走起!

啥是 KVM

KVM 的全称是:Kernel-based Virtual Machine,简单一句话概括,就是一个基于 Linux 内核的虚拟化管理系统。

从 Linux 内核 2.6.20 版本开始就已经集成了该功能。简单理解 Docker 是在应用层的虚拟化,而 KVM 是在系统层的虚拟化。

区别就是,Docker 虚拟化的内容,必须跟 Host 主机共享内核,也就意味着只能跑 Linux 类系统。

而 KVM 是整个主机虚拟,所以可以安装不同的操作系统,而不局限于 Linux 本身。等我过段时间抽风的时候,看看能不能在 Ubuntu 上虚拟化个 macOS 出来。这样就不用单独再弄个 Mac 主机来自动化编译 iOS App 了。

安装 KVM

我这里使用的是 Ubuntu 16.04 LTS 版本,考虑长期使用和稳定性,基本上只选 LTS 版本,其他版本差别也不太大,参考着做就好了。

首先是安装 KVM 相关的包文件,因为我的服务器都是命令行,没有安装 X 桌面,所以我加了 --no-install-recommends 参数。不然的话它会安装 virt-viewer 之类的包,而它们的依赖关系中又有 X11 和很多图形图像库,而这些都用不上。但是如果你开启了桌面系统,那么也可以不加该参数。

1
$ sudo apt-get install --no-install-recommends qemu-kvm qemu-utils libvirt-bin virtinst cpu-checker

让我们来验证一下是不是一切 OK

1
2
3
$ kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

很好,一切顺利,我们再来弄个桥接网络。其实这个也不是必须的,看你的使用场景。

KVM 会自己创建一个 virbr0 的桥接网络,但是这个是一个 NAT 的网络,没有办法跟局域网内的其他主机进行通信,所以还是别偷懒,自己建一个桥接网络吧。

参考配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The bridged network interface
auto br0
iface br0 inet static
address 1.2.3.4
netmask 255.255.255.0
gateway 1.2.3.1
dns-nameservers 1.2.3.1
bridge_ports enp9s0
bridge_stop off
bridge_fd 0
bridge_maxwait 0

重启网络,并验证一下桥接状态:

1
2
3
4
5
$ sudo systemctl restart networking
$ sudo brctl show
bridge name bridge id STP enabled interfaces
br0 8000.f079593874d9 no enp9s0
virbr0 8000.525400087ef2 yes virbr0-nic

OK,一切正常,可以开始创建虚拟主机了。

创建虚拟主机

KVM 只是完成了第一步,我们还需要创建虚拟主机才可以继续往下走。

在开始之前,我们要准备好几个东西:

我这里使用的是 Virtio 0.1.126-2 版本。操作系统版本是:Ubuntu 16.04.1 LTS。

一切准备就绪,使用 virt-install 命令来帮助创建虚拟机:

1
2
3
4
5
6
7
8
9
10
11
12
virt-install \
--name win10 \
--memory 2048 \
--vcpus sockets=1,cores=1,threads=2 \
--cdrom=/path/to/windows_10.iso \
--os-variant=win8.1 \
--disk /path/to/win10/win10.qcow2,bus=virtio,size=40 \
--disk /path/to/virtio/virtio-win-0.1.126_amd64.vfd,device=floppy \
--network bridge=br0,model=virtio \
--graphics vnc,password=Passw0rd,port=5910 \
--hvm \
--virt-type kvm

基本上配置信息都在上面了,虚拟信息机配置如下:

  • 2G 内存
  • 1 个 CPU,1 个核,2 个线程
  • 1 个 CDROM(Windows 安装光盘)
  • 40G 硬盘(系统盘)
  • 1 个软驱(Virtio 驱动)
  • 在 5910 端口开放一个 VNC 远程桌面

如果你的命令输入的正确,应该会得到类似的反馈信息:

1
2
3
Starting install...
Creating domain...
Domain installation still in progress. Waiting for installation to complete.

简单来说,就是虚拟机已经创建好了,但是因为没有图像界面,所以没有办法下一步了。当我们连接了 VNC 以后,就可以继续往下走了。这个提示只会出现一次,安装好系统以后,不会出现这个启动等待的情况。

安装 Windows 10

虽然我们在创建虚拟机的时候,指明了使用 5910 端口来提供 VNC 远程桌面。但是这个端口是不能直接访问的,因为它默认绑定在 127.0.0.1 上,也就是只有本地才能访问。我们需要先把远程的本地端口,映射成本地的端口。

1
ssh -L 5910:127.0.0.1:5910 server

然后在 macOS 下,⌘ + Space 呼叫出 Spotlight,然后输入:

1
vnc://127.0.0.1:5910

在弹出的窗口中输入密码:Passw0rd

然后就可以愉快的安装 Windows 系统了,如果不能识别硬盘,需要手动加载一下驱动,选择 A 盘和对应的 Windows 目录就可以了。同样的,如果网卡没有驱动,也是如法炮制。

附安装完成的屏幕截图一张:

参考