本地虚拟机环境搭建

分享自己在家搭建 Linux 虚拟机的经验。

基础知识

在开始搭设虚拟机前,要求实验者掌握一些基础的知识。

遇到问题会 Google, 百度一下的能力也是很重要的,学会抓住关键词搜索。

概要

本文分享在家用环境搭建 Linux 虚拟机环境的过程,并且介绍几个虚拟化软件的用法。适合小白入门
Linux 内核的常用操作系统有:

新手玩家,强烈推荐 Ubuntu 桌面版,有 UI 界面,上手难度没有那么的大。 桌面版下载地址

准备过程

不管你自己的电脑是什么操作, 首先需要你下载官方镜像到自己的电脑上。
访问 https://ubuntu.com/download/desktop 下载镜像, 文件名为 ubuntu-20.04.2.0-desktop-amd64.iso

按操作系统

日常我们家用的电脑一般就是 Windows 系统或者 macOS 苹果系统。请根据自己电脑的系统,下载相迎的虚拟化软件。

Windows

Windows 系统下面,推荐虚拟化软件 VMware Workstation , 官网地址
安装的过程中,需要输入激活码, VMware Workstation 激活码网上随便搜索一下就可以用了

在安装虚拟机之前,我们先看一下 VMware 的网络设置,打开虚拟网络编辑器


这里将桥接模式的网络,桥接到自己电脑的网卡,我这里是台式机,其网卡是 Intel(R) Ethernet Connection(7) I219-V , 这里每个人的情况不同,笔记本电脑的话是 wireless 无线网卡。

同时,我们还需要注意到 VMware 创建了三种网络,他们各自的网络地址。 需要注意的是桥接模式的地址,是根据你自己的电脑所在网络的路由器设置的,一般家用路由器都是 192.168.1.0/24 如果是校园 WiFi, 那估计网络规模会大很多。在 windows 查看自己的网络地址, 打开命令提示符 CMD,运行 ipconfig

如上图所示,这里我自己的家用台式机,网络地址就是 IPv4: 192.168.1.77

name mode CIDR
VMnet0 桥接 192.168.1.0/24
VMnet1 仅主机 192.168.230.0/24
VMnet8 NAT 192.168.64.0/24 å

当 VMware Workstation 安装好了之后,我们就可以用 VMware Workstation 提供的快速安装功能,安装 Ubuntu 桌面版虚拟机。

我这里是 Ubuntu 18, 如果你下载的是最新版本 ubuntu-20.04.2.0-desktop-amd64.iso , 选择的镜像不同

这里设置好虚拟机的名称,还有登录的账号和密码



输入你自己设置的账号密码,登录 Ubuntu

这里可以安装VMware tools, 插件是为了更好使用,比如窗口的缩放,还有拖拽文件进入虚拟机等

检查一下 Ubuntu 虚拟机的 IP 地址,因为我的虚拟机是双网卡: ens33 是 NAT 网络的地址, ens38 是桥接网络的地址

到此,你已经成功安装了虚拟机,在你探索之前,可以看一看快照 部分,学会备份,随便折腾

新手可以跳过。如果你需要双网卡,可以再额外添加一张网卡,我因为第一次初始化设置的网卡是 NAT, 第二次添加的桥接网卡,双网卡的机器一般是拿来当跳板机(堡垒机用)可以看看这篇介绍 ssh 通过跳板机直连跳板机内网服务器

macOS

苹果系统下面,我尝试了 2 种虚拟化软件

Configure Additional NAT in VMware Fusion

VirtualBox 开源免费的,但桌面窗口的支持没有 VMware Fusion 做的好。VMware Fusion 可以在淘宝很便宜的买到序列码, 我踩坑了:好像淘宝的序列码不支持自建 NAT 网络(因为是非商业版本) non-commercial use only,很坑。 还不如这个公众号里面分享的三个注册码

按网络环境

虚拟机三种网络模式, 这篇文章已经讲得比较详细
在家用练习环境中,如果选择自己的网络环境。 以下是我的一些建议

  • 桥接模式 Bridged:1. 要安装对外提供的服务,自己的实体机想访问虚拟机的服务。2. 只安装一台虚拟机, 新手推荐,快速省事
  • 网络地址转换模式 NAT:1. 自己的电脑安装几个虚拟机,搭建集群。 2. 虚拟机没有对外开放的服务,不需要端口转发

桥接模式 Bridged

网络地址转换模式 NAT

这里我们用 mtr 命令测试一下连通性,并且看沿途经过的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
root@ubuntu20:~# ip -4 a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
inet 192.168.64.5/24 brd 192.168.64.255 scope global ens33

# -I / --interface 网卡
# -n 不进行域名解析,显示 IP
# -c 定义数据包数量
# -r 生成报告
# --tcp / -T 或者 --udp / -u 或者 -S / --sctp, 默认是 icmp
# --port / -P

root@ubuntu20:~# mtr -n -c 3 -r --tcp --port 80 192.168.1.108
Start: 2021-05-25T11:33:27+0000
HOST: ubuntu20 Loss% Snt Last Avg Best Wrst StDev
1.|-- 192.168.64.2 0.0% 3 0.2 0.4 0.2 0.7 0.2
2.|-- 192.168.1.108 0.0% 3 1.0 0.9 0.8 1.0 0.1

root@ubuntu20:~# mtr -n -c 3 -r 192.168.1.125
Start: 2021-05-25T11:38:34+0000
HOST: ubuntu20 Loss% Snt Last Avg Best Wrst StDev
1.|-- 192.168.64.2 0.0% 3 0.3 0.4 0.3 0.5 0.2
2.|-- 192.168.1.125 0.0% 3 107.3 66.8 4.6 107.3 54.7

必备技能

学会快照 snapshot

快照 snapshot 就是虚拟机的某一时刻的状态备份。当我们在完成一个重大改变的前后,我们都应该快照。 比如在安装一个软件之前,如果我们不确定担心安装后搞崩了环境,那么我们可以快照一下。大吉大利

ansible 关机

因为一共有 6 台虚拟机了,手动关机还有有点 laborious,所以用 ansible 批量关机方便。
如果不知道的 ansible 的小白同学,可以先看看 Ansible系列 奥哥的 Ansible 学习路径

SSH config 别名,方便记忆,快速登录。 还有跳板机的设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
feiyang@MAC ~ % cat .ssh/config 

StrictHostKeyChecking no
CheckHostIP no

Host grab
HostName 192.168.1.119
User feiyang

Host feiyang
HostName 192.168.1.120
User feiyang

Host jingye
HostName 192.168.1.121
User feiyang

Host win1
HostName 192.168.1.108
User feiyang

Host win2
HostName 192.168.64.4
User jy576
ProxyJump win1

Host win3
HostName 192.168.64.5
User feiyang
ProxyJump win1

1
2
3
4
5
6
7
8
9
10
11
12
13
# file name: hosts

[all]

[ubuntu]
feiyang
grab
jingye

[win]
win3
win2
win1 # win1 是跳板机,必须最后才关机
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# file name: shutdown.yml

---
- hosts: all
serial:
- 5
- 1 # win1 是跳板机,必须最后才关机
become: yes
gather_facts: no
tasks:
- name: shutdown
command: /sbin/shutdown -h now
ignore_errors: yes
ignore_unreachable: yes

每次如果觉得输入 ansible-playbook 命令还是很麻烦,那就用 alias ,真是懒人促进发展,哈哈哈

1
2
3
vim ~/.zshrc

alias feiyang-shutdown='ansible-playbook -i /Users/yang.fei/ansible/hosts /Users/yang.fei/ansible/shutdown.yml'

打通任督二脉

从上面的家庭网络架构图得知,我们有两个网络:

  • 192.168.1.0/24 家庭路由器网络
  • 192.168.64.0/24 WIN10 台式机上,Vmware 创建的虚拟 NAT 网络

接下来,我们要做的就是,打通两个网络。Ubuntu18.04 双网卡实现转发,相当于扮演了一个路由器的角色。先来看一眼架构图,今天的主角就是身负双武魂(斗罗大陆看多了,哈哈)双网卡的 ubuntu18-108 , 它的两个网卡 Network interface controller 上的 IP 分别是 ens33 网卡是 192.168.64.3 and ens38 网卡是 192.168.1.108 网卡名称和 IP 地址非常重要,请牢记,不要混淆了。

1
2
3
4
5
6
7
8
9
10
root@ubuntu18-108:/home/feiyang# ip -4 a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
inet 192.168.64.3/24 brd 192.168.64.255 scope global ens33
valid_lft forever preferred_lft forever
3: ens38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
inet 192.168.1.108/24 brd 192.168.1.255 scope global noprefixroute ens38
valid_lft forever preferred_lft forever

NAT Server

其实我的另外一篇 blog 有介绍 NAT server 设置,但这次实验,我们采用的是临时命令行操作,因此有一点不同。在临时命令行后,我们也补充了持久化的文档链接,亲测有效
参考了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
cat /proc/sys/net/ipv4/ip_forward
1
# 如果此处不是 1 ,那就需要手动开启
vim /etc/sysctl.conf

net.ipv4.ip_forward=1 # 添加此行,开启转发功能

sysctl -p # 执行生效

# iptable 允许转发
# 允许 ens33: 192.168.64.3/24 到 -> ens38: 192.168.1.108/24
iptables -A FORWARD -i ens33 -j ACCEPT
iptables -A FORWARD -o ens38 -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.64.0/24 -d 192.168.1.0/24 -o ens38 -j MASQUERADE

# 允许 ens38: 192.168.1.108/24 到 -> ens33: 192.168.64.3/24
iptables -A FORWARD -i ens38 -j ACCEPT
iptables -A FORWARD -o ens33 -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.64.0/24 -o ens33 -j MASQUERADE

# check nat table POSTROUTING chain
iptables -t nat -L POSTROUTING
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 anywhere
MASQUERADE all -- 172.18.0.0/16 anywhere
MASQUERADE all -- 192.168.64.0/24 192.168.1.0/24
MASQUERADE all -- 192.168.1.0/24 192.168.64.0/24

client server

其他的机器,只需要设置一下路由,添加一条路由规则即可。

mac

macbook pro 苹果电脑的 IP 是 192.168.1.125 添加一条路由, 指定双网卡机器 192.168.1.108 为 gateway

1
sudo route -n add -net 192.168.64.0/24  192.168.1.108

linux

centos IP 是 192.168.64.4 , ubuntu20 IP 是 192.168.64.5 。 它们两台都需要设置,添加一条路由, 指定双网卡机器 192.168.64.3 为 gateway

1
route add -net 192.168.1.0 netmask 255.255.255.0 gw 192.168.64.3 dev ens33

  1. (CentOS7的路由配置持久化)[https://blog.csdn.net/beeworkshop/article/details/102952759]
    1
    2
    vim /etc/sysconfig/network-scripts/route-ens33
    192.168.1.0/24 via 192.168.64.3 dev ens33
  2. add static route with netplan on Ubuntu 20.04
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    vim /etc/netplan/00-installer-config.yaml 
    # This is the network config written by 'subiquity'
    network:
    ethernets:
    ens33:
    addresses: [192.168.64.5/24]
    optional: true
    dhcp4: no
    gateway4: 192.168.64.2
    nameservers:
    addresses: [1.1.1.1,8.8.8.8]
    routes:
    - to: 192.168.1.0/24
    via: 192.168.64.3
    version: 2
    renderer: networkd

    测试

  3. mac -> ubuntu20 , ubuntu20 开 2 个 terminal, 一个启动 server, 一个 tcpdump 抓包分析,mac telnet 测试

    1
    2
    3
    4
    5
    6
    7
    # terminal1: start simple http server
    python3 -m http.server 8000

    Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

    # terminal2: tcpdump listen port 8000
    tcpdump -i any port 8000 -nnn

    然后就是 mac telnet 192.168.64.5 8000

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 方法一: 用 Telnet 测试
    telnet 192.168.64.5 8000

    Trying 192.168.64.5...
    Connected to 192.168.64.5.
    Escape character is '^]'.
    ^]
    telnet> q
    Connection closed.

    # 方法二: 用 mtr 测试
    ➜ ~ sudo mtr -n -c 3 -r --tcp --port 8000 192.168.64.5
    Password:
    Start: 2021-06-20T20:07:35+0800
    HOST: FEIYANG-MAC Loss% Snt Last Avg Best Wrst StDev
    1.|-- 192.168.1.108 0.0% 3 6.2 11.2 3.3 24.3 11.4
    2.|-- 192.168.64.5 0.0% 3 10.9 7.7 2.6 10.9 4.5

    检查 ubuntu20 tcpdump 的结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    tcpdump -i any port 8000 -nnn

    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
    10:49:42.301949 IP 192.168.64.3.55989 > 192.168.64.5.8000: Flags [S], seq 2641736153, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 283128122 ecr 0,sackOK,eol], length 0
    10:49:42.301991 IP 192.168.64.5.8000 > 192.168.64.3.55989: Flags [S.], seq 1529903079, ack 2641736154, win 65160, options [mss 1460,sackOK,TS val 3145755328 ecr 283128122,nop,wscale 7], length 0
    10:49:42.303721 IP 192.168.64.3.55989 > 192.168.64.5.8000: Flags [.], ack 1, win 2058, options [nop,nop,TS val 283128124 ecr 3145755328], length 0
    10:49:46.519038 IP 192.168.64.3.55989 > 192.168.64.5.8000: Flags [F.], seq 1, ack 1, win 2058, options [nop,nop,TS val 283132312 ecr 3145755328], length 0
    10:49:46.519205 IP 192.168.64.5.8000 > 192.168.64.3.55989: Flags [F.], seq 1, ack 2, win 510, options [nop,nop,TS val 3145759545 ecr 283132312], length 0
    10:49:46.521868 IP 192.168.64.3.55989 > 192.168.64.5.8000: Flags [.], ack 2, win 2058, options [nop,nop,TS val 283132315 ecr 3145759545], length 0

    整个过程是
    192.168.1.125 -> 192.168.1.108 -> 192.168.64.3 -> 192.168.64.5

  4. centos7 -> mac , mac 开 2 个 terminal, 一个启动 server, 一个 tcpdump 抓包分析,centos7 telnet 测试

    1
    2
    3
    4
    5
    6
    7
    # terminal1: start simple http server
    python3 -m http.server 8000

    Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

    # terminal2: tcpdump listen port 8000
    tcpdump -i any port 8000 -nnn

    然后就是 centos telnet 192.168.1.125 8000

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 方法一: 用 Telnet 测试
    telnet 192.168.1.125 8000

    Trying 192.168.1.125...
    Connected to 192.168.1.125.
    Escape character is '^]'.
    ^]

    telnet> q
    Connection closed.

    # 方法二: 用 mtr 测试
    sudo mtr -n -c 3 -r --tcp --port 8000 192.168.1.125

    Start: Sun Jun 20 08:16:37 2021
    HOST: centos7 Loss% Snt Last Avg Best Wrst StDev
    1.|-- 192.168.64.3 0.0% 3 0.4 0.4 0.4 0.5 0.0
    2.|-- 192.168.1.125 0.0% 3 1002. 902.3 201.3 1502. 656.6

    检查 mac tcpdump 的结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ➜  ~ sudo tcpdump -i any port 8000 -nnn
    Password:
    tcpdump: data link type PKTAP
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on any, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
    18:44:00.166899 IP 192.168.1.108.54120 > 192.168.1.125.8000: Flags [S], seq 3298177179, win 29200, options [mss 1460,sackOK,TS val 4138980 ecr 0,nop,wscale 7], length 0
    18:44:00.166996 IP 192.168.1.125.8000 > 192.168.1.108.54120: Flags [S.], seq 3788626158, ack 3298177180, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 282788376 ecr 4138980,sackOK,eol], length 0
    18:44:00.169945 IP 192.168.1.108.54120 > 192.168.1.125.8000: Flags [.], ack 1, win 229, options [nop,nop,TS val 4138982 ecr 282788376], length 0
    18:44:00.169966 IP 192.168.1.125.8000 > 192.168.1.108.54120: Flags [.], ack 1, win 2058, options [nop,nop,TS val 282788379 ecr 4138982], length 0
    18:44:12.790139 IP 192.168.1.108.54120 > 192.168.1.125.8000: Flags [F.], seq 1, ack 1, win 229, options [nop,nop,TS val 4151601 ecr 282788379], length 0
    18:44:12.790165 IP 192.168.1.125.8000 > 192.168.1.108.54120: Flags [.], ack 2, win 2058, options [nop,nop,TS val 282800870 ecr 4151601], length 0
    18:44:12.790246 IP 192.168.1.125.8000 > 192.168.1.108.54120: Flags [F.], seq 1, ack 2, win 2058, options [nop,nop,TS val 282800870 ecr 4151601], length 0
    18:44:12.792923 IP 192.168.1.108.54120 > 192.168.1.125.8000: Flags [.], ack 2, win 229, options [nop,nop,TS val 4151606 ecr 282800870], length 0
    ^C
    8 packets captured
    2158 packets received by filter
    0 packets dropped by kernel

    整个过程是
    192.168.64.4 -> 192.168.64.3 -> 192.168.1.108 -> 192.168.1.125

总结

这下,两个网络之间就实现了互通。让我联想到了 AWS VPC peering ,又联动上了。 如今 SSH 就不需要跳板机 ProxyJump 了, vault UI 192.168.64.3:8200 也不需要 Nginx 代理了。
我们如今只是将 Windows10 VMware 自定义的 NAT 内网和家庭网络连通了起来。 如果家里的其他电脑也创建了 NAT 内网, 那么最终我们可以在家里本地环境,模拟出多个网络,就像 AWS 多个VPC 一样,最终都连通起来。