目标

  1. 在单台PC机上安装3+台虚拟机[1]
  2. 这些虚拟机间可以相互访问
  3. 宿主机[2]与虚拟机可以相互访问
  4. 虚拟机可以访问公网

本文将采用 NAT + Host-Only 双网卡的方式实现上述目标,因为采用这种组合来实现是很简单的,需要做的配置也非常少。

前置条件

本文仅在以下环境下验证通过,如果您的情况与此有差异,则全文内容仅供参考

  • windows11
  • virtual box7.0
  • ubuntu18.04

另外,需要宿主电脑至少预留40~60G空闲磁盘,用来安装VirtualBox和虚拟机。

搭建流程

主要有以下几步:

  1. 安装VirtualBox
  2. 创建虚拟机并安装Ubuntu系统
  3. 配置Ubuntu网络
     

安装VirtualBox

下载VirtualBox

VirtualBox的安装比较简单,本文使用的是当前(2023年2月)最新的7.0版本,点击这里直接下载。

安装VirtualBox

下载后,双击安装文件(如果下载的是归档或压缩文件,请先解压),如果不需要特别指定安装目录的话,一直点击〔下一步〕,直到安装结束即可。

如果需要将VirtualBox安装到指定目录,可以在安装向导界面上进行设置。
 

创建虚拟机并安装系统

下载Ubuntu

可直接点击这里下载ubuntu18.04的种子文件,下面列出ubuntu相关的资源清单

  • ubuntu18.04.iso光盘镜像文件
  • ubuntu18.04归档目录
  • ubuntu所有文件归档目录
  • ubuntu官方网站
  • ubuntu18.04 版本发布说明文档
  • ubuntu的阿里镜像

您也可以选择其它旧的发行版或最新的稳定版本。本文选择了18.04(版本代号为Bionic Beaver)这个版本,一来这是一个LTS版本, 官方宣称会支持10年,
同时它体积小,安装时默认的〔使用整个磁盘〕功能比较符合我们个人学习研究的感观,简而之,这个版本的安装过程和安装后使用都比较省事。

另外,建议下载live版本的ISO文件,相对于非Live版本而言,它的安装向导提供了更多的可配置项,特别是初始的用户名和密码。更多live-server与非live版本的差异,见ubuntu18.04 版本发布说明文档

 

创建虚拟机

将先创建一个原型虚拟机,再基于它复制其它的虚拟机。原型机的基本信息如下:

属性内容备注
名称ubuntu-a
CPU核心数2可根据自己宿主机的cpu核心数来调整,笔者的个人笔记本为6核,因此设置为2
内存大小1280M同理,请根据自己宿主机的物理内存调整,笔者的个人笔记本内存为16G
SATA磁盘20G同理,请根据自己宿主机的空闲磁盘调整,但建议至少10G

step1. 运行VirtualBox程序,打开程序主窗体界面。

step2. 指定虚拟机名称和操作系统

在主界面上点击【新建(N)】图标,调出虚拟机创建对话框,在对话框中,根据个人宿主机电脑实际情况,依次设置虚拟机名称、虚拟机文件存放目录和操作系统ISO安装文件的路径。如下图所示:

关于图中的第①步,即:Skip Unattended Installation 这一选项,请勾选该选项。VirtualBox识别出了ubuntu-18.04-live-server-amd64.iso文件,表示它内建了对该系统的支持,能够以全自动的、无人值守的方式安装该操作系统。因此,在一下步中,会多出一个主机名称、系统初始用户名称、昵称、密码设置的对话框,这些信息用于VirtualBox之后对ubuntu系统的自动安装任务。

但经过验证,VirtualBox的自动安装(即 Unattached Installation)是不行的。至少针对ubuntu-18.04这个版本,在我的电脑上没有成功。因此要勾选Skip Unattached Installation这个选项,以跳过自动安装。

依次单击菜单栏的〔控制(M)〕新建(N) ,或按下 Ctr+N 快捷键也可以调出虚拟机创建对话框。

step3. 分配物理内存和CPU

单击〔下一步〕进入物理内存和CPU的分配设置对话框。根据自己电脑的物理CPU核数和内存进行适当减配即可。如下图所示:

step4. 分配磁盘空间

单击〔下一步〕进入对话框。这个比较简单,为虚拟机指定好磁盘大小即可。

step5. 虚拟机参数确认

单击〔下一步〕,对话框将显示前4步设置的所有内容,确认无误后,单击〔完成〕即可。完成后VirtualBox主界面左侧面板中,会多出一个图标来,其名称为ubuntu-a,它就是我们刚刚新的虚拟机。另外,在磁盘上也会多出一个文件夹来(本文中这个文件夹位置为:E:\Data\VirutalMachine\ubuntu-a)

step6. 为虚拟机安装ubuntu系统

在VirtualBox的主界面,双击刚刚创建的虚拟机机图标,启动虚拟机,进入ubuntu操作系统的安装进程。根据安装向导,一步步输入自己的参数即可。除了初始的主机名称和登录账户信息外,其它的直接使用默认设置就可以了。

 

Ubuntu系统基本设置(可选)

一般来说,刚安装的系统,里边的软件包大多都过时了,因此需要更新系统的软件包

step1. 更改软件包源

先执行如下命令,备份之前的APT源配置文件。

cd /etc/apt/                               # 进入apt源配置目录sudo cp sources.list sources.list.origion  # 备份apt源配置

然后使用阿里的ubuntu软件包源,替换掉官方默认的源,即使用以下内容,覆盖source.list文件内容

deb https://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiversedeb-src https://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiversedeb https://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiversedeb-src https://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiversedeb https://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiversedeb-src https://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse# deb https://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse# deb-src https://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiversedeb https://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiversedeb-src https://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

step2. 更新系统软件包

直接执行以下命令即可。该命令的执行时长较长,请耐心等待 ?

sudo apt update && upgrade

其中的apt命令也可以换成apt-get,多数情况下,二者是等效的,详细差异见这里。

另外,关于命令update与upgrade的区别,这里有较为详细的讲解。

以上命令需要访问公网。VirtualBox7在创建虚拟机时,会默认配置一个NAT类型的网卡,只要宿主机能访问公网,通过该网卡虚拟机就能访问到公网。

 

网络设置

终于进入到最重要的网络设置了。目前为止,文章开头的4个目标,只有目标4彻底完成了,可以在虚拟机内输入ping www.bing.com验证是否可以连接公网。

但我们似乎什么也没做,这是因为VirtualBox在新建虚拟机时,默认添加了一张类型为NAT的网卡。只要宿主机能上网,目标4就已经完成了。

右击VirtualBox主界面上的ubuntu-a虚拟机图标,单击弹出菜单中的〔设置〕项,以打开虚拟机设置面板,选中〔网络〕选项卡。此时,右侧网卡列表中的〔网卡1〕就是默认的NAT网卡,如下图所示:

此时,宿主机还不能连接到虚拟机,在虚拟机中输入ifconfig -a查看其IP地址,其中的enp03就是默认的那张NAT网卡,如下所示。本示例中,其IP地址为:10.0.2.15 。 如果在宿主机中ping这个ip是会失败的。

enp0s3: flags=4163  mtu 1500        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯        inet6 fe80::a00:27ff:feb6:1744  prefixlen 64  scopeid 0x20        ether 08:00:27:b6:17:44  txqueuelen 1000  (Ethernet)        RX packets 140099  bytes 156313416 (156.3 MB)        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 45269  bytes 2765605 (2.7 MB)        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0lo: flags=73  mtu 65536        inet 127.0.0.1  netmask 255.0.0.0        inet6 ::1  prefixlen 128  scopeid 0x10        loop  txqueuelen 1000  (Local Loopback)        RX packets 132  bytes 12334 (12.3 KB)        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 132  bytes 12334 (12.3 KB)        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

接下来,我们就要完成目标2和目标3。

添加host-only网卡

依次如下操作:

  • 打开ubuntu-a虚拟机的设置面板,切换到〔网络〕选项卡,点击〔网卡2〕。
  • 勾选〔启用网络连接(E)〕属性
  • 打开〔连接方式(A)〕的下拉列表,选择「仅主机(Host-Only)网络」
  • 〔名称(N)〕属性栏,选择 VirtualBox Host-Only Ethernet Network

网络设置中,还有一组高级(advanced)属性,这些采用默认的值即可,无需特别配置

整个设置界面如下图所示:

刚刚已经为ubuntu-a虚拟机新添加了一张Host-Only类型的网卡。现在我们要启动该主机,进入系统查看一下该网卡在运行起来后,获得的ip是多少。

重启后,在虚拟机中输入ifconfig -a,将得到类似下面这样的输出(略去了回环网卡)

enp0s3: flags=4163  mtu 1500        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255        inet6 fe80::a00:27ff:feb6:1744  prefixlen 64  scopeid 0x20        ether 08:00:27:b6:17:44  txqueuelen 1000  (Ethernet)        RX packets 20  bytes 3630 (3.6 KB)        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 47  bytes 4716 (4.7 KB)        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0enp0s8: flags=4163  mtu 1500        ether 08:00:27:d6:ec:0e  txqueuelen 1000  (Ethernet)        RX packets 0  bytes 0        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 0  bytes 0        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

上面的enp0s8网卡,就是新添加的Host-Only网卡,但不幸的是,相对于enp03而言,这张网卡是没有分配到IP地址的。那也就不可用了,为什么会这样呢?与NAT网卡不同,Host-Only网卡很特殊,它还需要在操作系统中进行相关的网络设置才能发挥作用。

ubuntu 18.04 引入了netplan来管理网络,其配置文件位于/etc/netplan目录下,其中有个.yml后缀的文件,使用vim编辑该文件[3], 结果如下

network:    ethernets:        enp0s3:            addresses: []            dhcp4: true            optional: true        enp0s8:                         # 该节点(包含其子节点的内容)是新添加的            addresses:                - 192.168.56.101/24            dhcp4: false            optional: true    version: 2

其中的enp03节点是之前的内容,enp08是本次添加的内容。可以看到,我们手动将网卡2的ip地址设置为了192.168.56.101,并禁用了DHCP

  1. 也可以将Host-Only网卡的IP配置成DHCP方式动态获取。但配置为静态ip有个好处,就是虚拟机重启后,其IP地址是不会变的,而DHCP方式是有可能会改变,这不利于在多个虚拟机上部署集群软件。
  2. 这里有一篇关于netplan的快速操作中文博客,可以参考一下

netplan的配置文件编辑好后,执行以下命令验证配置是否正确

sudo netplan try

验证无误后,可以选择直接生效(回车即可),此时再执行ifconfig -a命令查看,会得到类似下面的结果(略去了回环网卡)

enp0s3: flags=4163  mtu 1500        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255        inet6 fe80::a00:27ff:feb6:1744  prefixlen 64  scopeid 0x20        ether 08:00:27:b6:17:44  txqueuelen 1000  (Ethernet)        RX packets 20  bytes 3630 (3.6 KB)        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 47  bytes 4716 (4.7 KB)        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0enp0s8: flags=4163  mtu 1500        inet 192.168.56.101  netmask 255.255.255.0  broadcast 192.168.56.255        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯        inet6 fe80::a00:27ff:fed6:ec0e  prefixlen 64  scopeid 0x20        ether 08:00:27:d6:ec:0e  txqueuelen 1000  (Ethernet)        RX packets 76  bytes 9568 (9.5 KB)        RX errors 0  dropped 0  overruns 0  frame 0        TX packets 59  bytes 11698 (11.6 KB)        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

下划线标识出来的部分,就是我们刚刚手动为Host-Only网卡分配的ip,那么宿主机是否可以ping得通这个IP呢?以下是笔者的电脑上执行ping命令的结果

C:\Users\Administrator>ping 192.168.56.101正在 Ping 192.168.56.101 具有 32 字节的数据:来自 192.168.56.101 的回复: 字节=32 时间<1ms TTL=64来自 192.168.56.101 的回复: 字节=32 时间<1ms TTL=64来自 192.168.56.101 的回复: 字节=32 时间<1ms TTL=64来自 192.168.56.101 的回复: 字节=32 时间=1ms TTL=64192.168.56.101 的 Ping 统计信息:    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),往返行程的估计时间(以毫秒为单位):    最短 = 0ms,最长 = 1ms,平均 = 0ms

可以看到,已经能ping得通了。

OK,是时候验证一下,在宿主机上是否可以通ssh方式连接(登录)虚拟机了。选择一款windows上的ssh连接工具(推荐MobaXTerm或XShell),经验证,是可以连接成功的。

  
现在,你一定有个疑问,为什么手动设置的IP是192.168.56.101,设置成192.168.139.101或者192.170.56.101行不行。答案是不行,因为VirtualBox7在宿主机上创建了一个名为VirtualBox Host-Only Network Adapter的虚拟网卡,如下图所示。这个网卡,就是我们在给虚拟机创建网卡2指定名称时选择的网卡。它默认的网段是192.168.56.0/24,并且该网卡默认开启了dhcp,dhcp的ip为192.168.56.100。因此我们可以手动给虚拟机配置的ip范围是:192.168.56.101 ~ 192.168.56.254。

那么这个默认的网段和dhcp的ip是否可以修改呢?是可以的,详见下一小节的问题一。

相关问题

问题一. host-only网卡的IP地址在哪里设置?

上面我们为host-only网卡设置的静态ip为192.168.56.101,且网段为192.168.56。正如上小节所述,这是因为在安装VirtualBox程序时,就默认在宿主机生成了一张host-only的网卡。我们在为虚拟机添加网卡时,只能选择网络类型,并不能为其单独设置ip和dhcp等。如果要为网卡设置一个不同的网段,比如:192.168.82.0/24,应该在全局的网络管理界面中去操作,因为网卡的创建也是全局的。

  1. 点击VirtualBox主界面上左侧面板上的,工具 栏上右侧的菜单列表图标,此后会出现一个下拉菜单,点击其中的网络菜单项,这将使用主界面的右侧面板内容切换到全局的网络设置。如下图所示

  2. 全局网络设置界面,默认显示的是Host-Only类型的网卡信息

    • 选中列表中的一个网卡(默认只有VirtualBox Host-Only Network Adapter)
    • 点击「适配器(Adapter)」TAB选项卡下的〔手动配置网卡〕,就可以设置ip和网段了
    • 勾选「DHCP服务器)」TAB选项卡下的〔启用服务器〕,就可以配置DHCP相关参数了

问题二. VirtualBox各种网络模式的都有什么用?

VirtualBox有多种网络模式,非运维人员对这些模拟出来的各种网络功能是搞不清楚的。我们一般也只想在本机建立一个文章开头所描述的那个经典场景。如果你想深入地了解它们,下面是一些可参考的博文

  • VirtualBox网络配置官方手册
  • VirtualBox网络配置超全详解-中文
  • 这是上面那边博文的原始英文版本

  
问题三. 添加Host-Only网卡时,下拉列表为空怎么办?

这种情况如果出现,基本上是安装VirtualBox时出现了错误。可以尝试在全局的网络管理界面中,点击创建图标新建一张Host-Only类型的网卡,如下图所示

如果创建失败,则表明安装的VirtualBox有问题,建议卸载重新安装,如果还不行,尝试安装其它的版本。
 

复制虚拟机

目前为止,我们仅创建了一台虚拟机,因此,目标1和目标2还未完成。完成这两个目标,最笨的办法,就是把创建虚拟机和设置网络的步骤,再重复做两遍。但这效率太低,我们可以借助VirtualBox提供的虚拟机复制功能,快速完成另外两台虚拟机的创建和设置。

step1. 复制虚拟机本体

以创建第二台虚拟机为例,按如下步骤操作:

  1. 鼠标右击ubuntu-a虚拟机图标,在右键菜单中,选择〔复制〕,如下列图组中的第①项所示

  2. 在弹出的虚拟机复制对话框中,依次设置相应属性(如下),示意图为下列图组中的第②项所示。设置完成后,点击〔下一步〕按钮

    • 名称栏(Name),设置一个新的虚拟机名,如:ubuntu-b
    • 路径栏(Path),与之前的虚拟机保持一致即可
    • 网卡地址策略栏(MAC Address Policy),请务必选择「为所有网卡重新生成 MAC 地址」
    • 其它选项栏(Other Options),该栏内的所有条目都不要勾选
  3. 在副本类型设置对话框中,选中「完全复制」,如下列图组中的第③项所示。然后点击〔完成〕按钮

  4. 虚拟机复制操作的所有属性设置就已经完成了,接下来VirtualBox开始正式执行复制,这会花费一些时间,如下列图组中的第④项所示。在复制完成后,在主界面的虚拟机列表栏会多出一个虚拟机图标,如图组中的第⑤项所示


  

  
step2. 修改ip和主机名

新复制出来的主机,其主机名、登录账户、ip地址都与第一台虚拟机一样,这在做集群时是不行的,因此,至少需要将IP和主机名改掉。

  1. 启动刚刚复制出来的虚拟机

  2. 执行以下命令修改主机名

       sudo hostnamectl set-hostname ubuntu-b   # ubuntu-b是本示例中,要设置的新主机名

    修改主机名还有其它一些方法,参见这里

  3. 执行命令sudo vim /etc/netplan/50-cloud-init.yaml打开网络配置文件[3:1]

  4. 修改文件中的enp0s8网卡(也就是Hony-Only类型的那张网卡)的ip,如下所示

    network:    ethernets:        enp0s3:            addresses: []            dhcp4: true            optional: true        enp0s8:             addresses:                - 192.168.56.102/24      # ip由复制前的101改成102            dhcp4: false            optional: true    version: 2
  5. 验证虚拟机间的互访问性
    执行sudo reboot重启虚拟机,并将第一台虚拟机也启动起来。此时一共有两台虚拟机,并且都启动起来了,为方便描述,用ubuntu-a、ubuntu-b来分别代表第一台和第二台虚拟机。它们的ip分别是192.168.56.101和192.168.56.102

    • 选择一款SSH连接工具分别登录ubuntu-a和ubuntu-b,验证是否可以在宿主以上以SSH方式连接到虚拟机
    • 在ubuntu-a上,执行命令ping 192.168.5.102, 验证ubuntu-a是否可以访问ubuntu-b
    • 在ubuntu-b上,执行命令ping 192.168.5.101, 验证ubuntu-b是否可以访问ubuntu-a

至此,目标2和目标3已完成?

step3. 创建第3台虚拟机

整篇文章,只差最后一个小目标了,那就是需要创建至少3台虚拟机,即目标1。幸运的是,现在不用再从头开始一步步创建它了,请参考上一小节(即复制虚拟机)部分操作即可。

小结

本文实现了一个在个人电脑上,安装虚拟机进行学习研究的经典场景,即:在宿主机上安装多台虚拟机,并且这些虚拟间可以互通,宿主机也能SSH登录到这些虚拟机。主要难点在网络设置上,简单来说就是NAT网卡负责连接公网,Host-Only网卡负责虚拟机之间以及虚拟机与宿主机之间的连接,当然这两种类型的网卡还有其它功能,但对于我们提到的这个最常见的应用场景,可以用这样的方式来看待这两种类型的网卡。

这里最容易失败的是第2步网络设置。由于NAT网卡设置上去后,什么也不用做,就可以连接公网了,会自然地觉得Host-Only网卡也是这样的。但事实是如果只是为虚拟机添加Host-Only网卡,宿主机并不能访问虚拟机,因为这张网上还没有分配到IP,需要登录到操作系统,修改其网络配置,为该网卡设置静态IP或开启dhcp。

另外,在创建多个虚拟机时,我们利用了VirtualBox的虚拟机复制功能,简化了后续虚拟机的创建。需要注意的是,复制时要为新虚拟机的所有网卡创建全新的MAC地址。


  1. 在虚拟化术语中,虚拟机被称作Guest,而不是Virtual Machine。宿主机被称作Host,即主人与客人的关系。 ↩︎

  2. 宿主机(Host)即安装VirtualBox程序的操作系统所在的主机,一般来说就是一台物理电脑 ↩︎

  3. netplan的配置文件是YAML格式的,但该配置文件的名称在不同主机上是不一样的 ↩︎ ↩︎