一个专注于IT互联网运维的技术博客

Vagrant的网络配置

2019.05.18

在 Vagrantfile 配置文件中,使用config.vm.network配置虚拟机的网络。Vagrant 支持三种网络模型:端口转发(Forwarded Ports)、私有网络(Private Network)和公有网络(Public Network),他们和多数虚拟机提供的网络模型是对应的。下面我们来详细分析 Vagrant 的网络配置。

1、基本配置

网络相关的信息使用config.vm.network命令在 Vagrantfile 文件中配置,例如:

Vagrant.configure("2") do |config|
  # ...
  config.vm.network "forwarded_port", guest: 80, host: 8080
end
  • config.vm.network命令格式:config.vm.network 网络类型,网络类型参数1,网络类型参数2,...
  • 这里的网络类型forwarded_port有2个参数:虚拟机需要转发的端口号、绑定的宿主机的端口号;
  • 可以使用多条config.vm.network命令给虚拟机配置多个网络,配置在虚拟机启动时按顺序生效。

参考 Vagrant 官方文档Vagrant - Networking

2、网络模型

端口转发 forwarded_port

端口转发将访问宿主机的某个端口的流量全部转发到虚拟机的某个端口,下面的例子将宿主机的 8080 端口转发到虚拟机的 80 端口:

Vagrant.configure("2") do |config|
  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  config.vm.network "forwarded_port", guest: 80, host: 8080
end
  • host的端口号必须大于 1024,除非使用 root 用户运行 Vagrant(不建议这么做);
  • 端口转发默认绑定所有网卡,可以通过指定 guest_ip 和 host_ip 绑定指定网卡:

    # Create a forwarded port mapping which allows access to a specific port
    # within the machine from a port on the host machine and only allow access
    # via 127.0.0.1 to disable public access
    # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
    
  • 端口转发支持 TCP 和 UDP,默认是 TCP 协议,可以protocol参数指定协议类型:

    Vagrant.configure("2") do |config|
    config.vm.network "forwarded_port", guest: 2003, host: 12003, protocol: "tcp"
    config.vm.network "forwarded_port", guest: 2003, host: 12003, protocol: "udp"
    end
    
  • 端口转发在 VirtualBox 中的创建一条名称是“$protocol$guest”的记录,这里是“tcp80”,可以使用id参数修改记录名称。

私有网络 private_network

私有网络适用于可以从宿主机访问虚拟机但 LAN 中的其他人不需要也无法访问虚拟机的情况。

使用同一虚拟网络的虚拟机之间网络互通。

Vagrant 的私有网络对应 VirtualBox 的 hostonly 网络模型。

1)DHCP

配置私有网络最简单的方法是使用 DHCP,下面的例子虚拟机将从默认的私有网络动态获取一个 IP 地址,虚拟机里使用ifconfig或者ip addr命令可以查看获取的 IP 地址:

Vagrant.configure("2") do |config|
  config.vm.network "private_network", type: "dhcp"
end

2)静态 IP

也可以使用静态 IP 指定虚拟机的私有网络 IP 地址,下面的例子给虚拟机配置了静态 IP 地址192.168.33.10

Vagrant.configure("2") do |config|
  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"
end
  • 必须确保配置的静态 IP 地址和网络中其他机器的 IP 不冲突;
  • 必须使用 IPv4 的保留地址中的私有 IP 地址:10.0.0.0 — 10.255.255.255、172.16.0.0 — 172.31.255.255、192.168.0.0 — 192.168.255.255。

3)禁用自动配置

Vagrant 默认在虚拟机启动时自动配置私有网络,可以设置auto_config: false禁止这一行为:

Vagrant.configure("2") do |config|
  config.vm.network "private_network", ip: "192.168.50.4",
    auto_config: false
end

公有网络 public_network

使用公有网络时,虚拟机暴露为 LAN 中的一台主机。对于私有网络来说,外网肯定无法访问,但是对于公有网络来说,这个不一定。

Vagrant 公有网络对应 VirtualBox 的 Bridge 网络,虚拟机在宿主机所在的 LAN 中等价于一台物理机器。

1)DHCP

最简单的配置公有网络的方法是从 LAN 中的 DHCP 服务器自动获得 IP 地址:

Vagrant.configure("2") do |config|
  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"
end

可以使用use_dhcp_assigned_default_route: true让 Vagrant 给虚拟机配置原始的默认路由:

Vagrant.configure("2") do |config|
  config.vm.network "public_network",
    use_dhcp_assigned_default_route: true
end

2)静态 IP

也可以使用静态 IP:

Vagrant.configure("2") do |config|
  config.vm.network "public_network", ip: "192.168.0.17"
end

3)指定默认网卡 如果宿主机有多块网卡,可以使用bridge参数指定使用哪块网卡:

Vagrant.configure("2") do |config|
  config.vm.network "public_network", bridge: "en1: Wi-Fi (AirPort)"
end

有些虚拟机管理器可以支持 Vagrant 配置多块网卡,然后使用第一块存在的网卡:

Vagrant.configure("2") do |config|
  config.vm.network "public_network", bridge: [
    "en1: Wi-Fi (AirPort)",
    "en6: Broadcom NetXtreme Gigabit Ethernet Controller",
  ]
end

4)禁用自动配置 和私有网络一样,可以使用auto_config: false禁止 Vagrant 自动配置公有网络:

Vagrant.configure("2") do |config|
  config.vm.network "public_network", auto_config: false
end

然后使用自定义的 SHELL 脚本手动配置公有网络:

Vagrant.configure("2") do |config|
  config.vm.network "public_network", auto_config: false

  # manual ip
  config.vm.provision "shell",
    run: "always",
    inline: "ifconfig eth1 192.168.0.17 netmask 255.255.255.0 up"

  # manual ipv6
  config.vm.provision "shell",
    run: "always",
    inline: "ifconfig eth1 inet6 add fc00::17/7"
end

5)指定默认路由

Vagrant.configure("2") do |config|
  config.vm.network "public_network", ip: "192.168.0.17"

  # default router
  config.vm.provision "shell",
    run: "always",
    inline: "route add default gw 192.168.0.1"

  # default router ipv6
  config.vm.provision "shell",
    run: "always",
    inline: "route -A inet6 add default gw fc00::1 eth1"

  # delete default gw on eth0
  config.vm.provision "shell",
    run: "always",
    inline: "eval `route -n | awk '{ if ($8 ==\"eth0\" && $2 != \"0.0.0.0\") print \"route del default gw \" $2; }'`"
end

3、自动创建的 NAT 网卡

Vagrant 启动虚拟机时,会自动在虚拟机中添加一块 VirtualBox NAT 类型的网卡,然后再创建 Vagrantfile 配置文件所描述的网络。你一定感到很迷惑,但是 Vagrant 就是这么设计的。

Vagrant 将宿主机的 TCP/2222 端口转发到 虚拟机的 TCP/22 端口,这样就可以使用vagrant ssh命令快速地连接虚拟机。同时,虚拟机使用这块自动创建的 NAT 网卡访问外部网络。

// 宿主机上的 VirtualBox NAT 网卡
[wedot@dx142 kubeadm]$ vboxmanage list natnets
NetworkName:    vboxnat0
IP:             192.168.1.1
Network:        192.168.1.0/24
IPv6 Enabled:   No
IPv6 Prefix:    fd17:625c:f037:a801::/64
DHCP Enabled:   No
Enabled:        Yes
loopback mappings (ipv4)
        127.0.0.1=2

// 宿主机上的 VBoxHeadless 监听 TCP/2222 端口,并将该端口的流量转发到虚拟机
[wedot@dx142 kubeadm]$ sudo netstat -lnptu|grep 2222
tcp        0      0 127.0.0.1:2222          0.0.0.0:*               LISTEN      42417/VBoxHeadless

// 使用 vagrant ssh 命令即可连接虚拟机
[wedot@dx142 kubeadm]$ vagrant ssh master01
Last login: Wed May 22 16:57:32 2019 from gateway
[vagrant@master01 ~]$ sudo netstat -lnptu|grep sshd
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      3062/sshd           
tcp6       0      0 :::22                   :::*                    LISTEN      3062/sshd

// 虚拟机的网络配置,其中 enp0s3 是 Vagrant 自动创建的 NAT 网卡,IP 地址:10.0.2.15/24,enp0s8 是 Vagrantfile 文件中定义的私有网络
[vagrant@master01 ~]$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:c5:46:4e brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic enp0s3
       valid_lft 76970sec preferred_lft 76970sec
    inet6 fe80::a00:27ff:fec5:464e/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:ac:d6:08 brd ff:ff:ff:ff:ff:ff
    inet 192.168.81.101/24 brd 192.168.81.255 scope global noprefixroute enp0s8
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:feac:d608/64 scope link 
       valid_lft forever preferred_lft forever

// 默认路由指向 VirtualBox NAT 网络的网关:10.0.2.2,虚拟机可以通过自动创建的网卡 enp0s3 访问外网
[vagrant@master01 ~]$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.0.2.2        0.0.0.0         UG    100    0        0 enp0s3
10.0.2.0        0.0.0.0         255.255.255.0   U     100    0        0 enp0s3
192.168.81.0    0.0.0.0         255.255.255.0   U     101    0        0 enp0s8

// DNS 指向 VirtualBox NAT 网络的域名服务器:10.0.2.3
[vagrant@master01 ~]$ cat /etc/resolv.conf 
# Generated by NetworkManager
nameserver 10.0.2.3

4、遇到的问题

Host-only Network 和 Bridged Network 网段冲突

错误详情:

[admin@ityoudao ceph-cookbook]$ vagrant up ceph-node1 ceph-node2 ceph-node3
Bringing machine 'ceph-node1' up with 'virtualbox' provider...
Bringing machine 'ceph-node2' up with 'virtualbox' provider...
Bringing machine 'ceph-node3' up with 'virtualbox' provider...
==> ceph-node1: Importing base box 'centos7-standard'...
==> ceph-node1: Matching MAC address for NAT networking...
==> ceph-node1: Setting the name of the VM: ceph-node1
==> ceph-node1: Clearing any previously set network interfaces...
The specified host network collides with a non-hostonly network!
This will cause your specified IP to be inaccessible. Please change
the IP or name of your host only network so that it no longer matches that of
a bridged or non-hostonly network.

Bridged Network Address: '192.168.1.0'
Host-only Network 'virbr0': '192.168.1.0'
[admin@ityoudao ceph-cookbook]$ cat Vagrantfile |grep -i network
                        node1.vm.network :private_network, ip: "192.168.1.101"
                        node2.vm.network :private_network, ip: "192.168.1.102"
                        node3.vm.network :private_network, ip: "192.168.1.103"
                        node4.vm.network :private_network, ip: "192.168.1.104"
                        os.vm.network :private_network, ip: "192.168.1.111"
                        os.vm.network :private_network, ip: "192.168.1.110"
                        rgw.vm.network :private_network, ip: "192.168.1.106"
                        use1.vm.network :private_network, ip: "192.168.1.107"
                        usw1.vm.network :private_network, ip: "192.168.1.108"
                        oc.vm.network :private_network, ip: "192.168.1.120"
Name:            vnet0
[admin@ityoudao ceph-cookbook]$ sudo vboxmanage list bridgedifs|grep -B3 -A8 "192\.168\.1\."
Name:            virbr0
GUID:            62726976-3072-4000-8000-5254008f8e8b
DHCP:            Disabled
IPAddress:       192.168.1.1
NetworkMask:     255.255.255.0
IPV6Address:     
IPV6NetworkMaskPrefixLength: 0
HardwareAddress: 52:54:00:8f:8e:8b
MediumType:      Ethernet
Wireless:        No
Status:          Up
VBoxNetworkName: HostInterfaceNetworking-virbr0
  • Vagrantfile文件 中有一个 private_network,网段为"192.168.1.0",会在 VirtualBox 中创建或使用"192.168.1.0"网段的 Host-only Network,而此时 VirtualBox 中存在"192.168.1.0"网段的 Bridged Network,故导致此错误。
  • 解决办法删除网桥 virbr0 或者修改 Vagrantfile 配置文件让虚拟机使用其他网段:
[admin@ityoudao ceph-cookbook]$ brctl show
bridge name bridge id   STP enabled interfaces
virbr0    8000.5254008f8e8b yes   virbr0-nic
              vnet0
              vnet1
              vnet2
              vnet3
              vnet4
virbr1    8000.5254003975d7 yes   virbr1-nic
virbr2    8000.000000000000 no    
virbr3    8000.000000000000 no
发表评论