CLOVER🍀

That was when it all began.

Vagrantの仮想マシンに、プライベートIPアドレスを設定する(複数個まで)

これは、なにをしたくて書いたもの?

Vagrantで時々プライベートIPアドレスを固定しているのですが、複数設定した時の挙動を見てみようかなと思いまして。

Vagrantのネットワーク設定

Vagrantのネットワーク設定には、Private NetworkとPublic Networkがあります。

Private Networks - Networking - Vagrant by HashiCorp

Public Networks - Networking - Vagrant by HashiCorp

Public Networkの方は、いわゆるブリッジですね。自分は、今のところ使う予定がないので、今回はPrivate Networkのみを見ていきます。

Private Networkは、ホスト側と通信できるネットワークを構成するものです。いわゆるNATでの構成ですね。

環境

今回の環境は、こちらです。Ubuntu Linux 18.04 LTSで、Vagrantは2.2.7です。

$ uname -srvmpio
Linux 4.18.0-25-generic #26~18.04.1-Ubuntu SMP Thu Jun 27 07:28:31 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux


$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.4 LTS
Release:    18.04
Codename:   bionic


$ vagrant -v
Vagrant 2.2.7

VagrantのProviderとしては、libvirtを使用します。

$ vagrant plugin list
vagrant-libvirt (0.0.45, global)
  - Version Constraint: > 0

使用するBoxとしては、ホスト側と同じくUbuntu Linux 18.04 LTSを使用します。

Vagrant box generic/ubuntu1804 - Vagrant Cloud

こちらの環境で、プライベートIPアドレスを設定しないところから始めて、少しずつ設定を変えながら挙動を見てみましょう。

プライベートIPアドレス未設定の場合

まずは、なにも設定を変えずデフォルトのままで起動してみましょう。

「vagrant init」。

$ vagrant init generic/ubuntu1804

仮想マシンを起動して、SSH接続します。

$ vagrant up
$ vagrant ssh

起動した仮想マシンのネットワークインターフェースおよび、IPアドレスを確認してみましょう。

$ ip a
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:31:1c:53 brd ff:ff:ff:ff:ff:ff
    inet 192.168.121.3/24 brd 192.168.121.255 scope global dynamic eth0
       valid_lft 3579sec preferred_lft 3579sec
    inet6 fe80::5054:ff:fe31:1c53/64 scope link 
       valid_lft forever preferred_lft forever

ループバック以外に、eth0があります。これは、ホスト側からもアクセス可能なIPアドレスです。

ルーティングを確認。

$ ip route
default via 192.168.121.1 dev eth0 proto dhcp src 192.168.121.3 metric 100 
192.168.121.0/24 dev eth0 proto kernel scope link src 192.168.121.3 
192.168.121.1 dev eth0 proto dhcp scope link src 192.168.121.3 metric 100

とりあえず、情報を見てみたので、仮想マシンを破棄します。

$ vagrant destroy -f

固定のプライベートIPアドレスを設定する

次は、仮想マシンにプライベートIP

Vagrantファイルの以下のようにコメントアウトされている部分を解除して、

  # 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"

固定のプライベートIPアドレスを設定します。

  config.vm.network "private_network", ip: "192.168.33.10"

Vagrantのドキュメントとしては、こちらですね。

Private Networks / Static IP

仮想マシンを起動して、SSH接続。

$ vagrant up
$ vagrant ssh

ネットワークインターフェースを確認してみます。

$ ip a
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:10:b8:0f brd ff:ff:ff:ff:ff:ff
    inet 192.168.121.192/24 brd 192.168.121.255 scope global dynamic eth0
       valid_lft 3595sec preferred_lft 3595sec
    inet6 fe80::5054:ff:fe10:b80f/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:cd:58:c5 brd ff:ff:ff:ff:ff:ff
    inet 192.168.33.10/24 brd 192.168.33.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fecd:58c5/64 scope link 
       valid_lft forever preferred_lft forever

eth1が増えましたね。こちらに、指定したプライベートIPアドレスが反映されています。eth0も存在していますが、こちらはDHCPですね。

ルーティングを確認。

$ ip route
default via 192.168.121.1 dev eth0 proto dhcp src 192.168.121.192 metric 100 
192.168.33.0/24 dev eth1 proto kernel scope link src 192.168.33.10 
192.168.121.0/24 dev eth0 proto kernel scope link src 192.168.121.192 
192.168.121.1 dev eth0 proto dhcp scope link src 192.168.121.192 metric 100 

確認したので、仮想マシンを破棄。

$ vagrant destroy -f

今回はIPアドレスのみ指定しましたが、ネットマスクを指定することもできます。

たとえば、こんな感じで。

  config.vm.network "private_network", ip: "10.0.0.10", netmask: "16"

仮想マシンを起動してSSH接続し、ネットワークインターフェースの確認をしてみます。

$ ip a
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:cc:f4:c2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.121.3/24 brd 192.168.121.255 scope global dynamic eth0
       valid_lft 3578sec preferred_lft 3578sec
    inet6 fe80::5054:ff:fecc:f4c2/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:4e:5e:b3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.10/16 brd 10.0.255.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe4e:5eb3/64 scope link 
       valid_lft forever preferred_lft forever

ネットマスクが、指定した16になっていますね。デフォルトのネットマスクは、24ということですね。
※IPv6はまた別。

ルーティング。

$ ip route
default via 192.168.121.1 dev eth0 proto dhcp src 192.168.121.3 metric 100 
10.0.0.0/16 dev eth1 proto kernel scope link src 10.0.0.10 
192.168.121.0/24 dev eth0 proto kernel scope link src 192.168.121.3 
192.168.121.1 dev eth0 proto dhcp scope link src 192.168.121.3 metric 100 

ちなみに、DHCPでも割り当てることができます。こちらで割り当てられているIPアドレスに、「vagrant ssh」で接続していることに
なっているようですね。

Private Networks / DHCP

eth0に残っていたのは、デフォルトで作られるネットワークインターフェースだと思うので、Private Networkの設定を行うと、
実質「ネットワークインターフェースを追加する」ということになりそうな感じですね。

仮想マシン間の通信を行う

最後に、仮想マシンを2つ用意して、以下のような通信を行ってみましょう。

仮想マシン1で動作するApacheは、仮想マシン2で動作するApacheへのリバースプロキシとして動作させます。

仮想マシン1には2つのプライベートIPアドレス(192.168.33.10、10.0.0.10)を与え、ホスト側からは仮想マシン1の192.168.33.10に
対してHTTPリクエストを投げ、仮想マシン2へはソースIPが10.0.0.10となっていることが確認できればOKです。

同じサブネットの方のIPアドレスを使ってくれますよね、と。

仮想マシン1の作成。

$ vagrant init generic/ubuntu1804

プライベートIPアドレスは、以下のように設定します。

  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.network "private_network", ip: "10.0.0.10"

仮想マシン1を起動して、SSH接続。

$ vagrant up
$ vagrant ssh

ネットワークインターフェースを見てみます。eth1、eth2が追加されていますね。

$ ip a
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:b4:15:04 brd ff:ff:ff:ff:ff:ff
    inet 192.168.121.202/24 brd 192.168.121.255 scope global dynamic eth0
       valid_lft 3308sec preferred_lft 3308sec
    inet6 fe80::5054:ff:feb4:1504/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:64:ce:38 brd ff:ff:ff:ff:ff:ff
    inet 192.168.33.10/24 brd 192.168.33.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe64:ce38/64 scope link 
       valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:e2:ba:6c brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.10/24 brd 10.0.0.255 scope global eth2
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fee2:ba6c/64 scope link 
       valid_lft forever preferred_lft forever

ルーティングも見てみます。eth1の分も増えていますね。

$ ip route
default via 192.168.121.1 dev eth0 proto dhcp src 192.168.121.202 metric 100 
10.0.0.0/24 dev eth2 proto kernel scope link src 10.0.0.10 
192.168.33.0/24 dev eth1 proto kernel scope link src 192.168.33.10 
192.168.121.0/24 dev eth0 proto kernel scope link src 192.168.121.202 
192.168.121.1 dev eth0 proto dhcp scope link src 192.168.121.202 metric 100

次に、仮想マシン2の作成。

$ vagrant init generic/ubuntu1804

仮想マシン2には、プライベートIPアドレスをひとつ設定します。

  config.vm.network "private_network", ip: "10.0.0.11"

仮想マシン2を起動して、SSH接続。

$ vagrant up
$ vagrant ssh

ネットワークインターフェースの確認。

$ ip a
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:0a:0c:ac brd ff:ff:ff:ff:ff:ff
    inet 192.168.121.87/24 brd 192.168.121.255 scope global dynamic eth0
       valid_lft 3349sec preferred_lft 3349sec
    inet6 fe80::5054:ff:fe0a:cac/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:3f:ad:e3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.11/24 brd 10.0.0.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe3f:ade3/64 scope link 
       valid_lft forever preferred_lft forever

ルーティングの確認。

$ ip route
default via 192.168.121.1 dev eth0 proto dhcp src 192.168.121.87 metric 100 
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.11 
192.168.121.0/24 dev eth0 proto kernel scope link src 192.168.121.87 
192.168.121.1 dev eth0 proto dhcp scope link src 192.168.121.87 metric 100

仮想マシンの準備ができたので、Apacheをインストールしましょう。仮想マシン1、仮想マシン2のいずれにも、Apacheをインストールします。

$ sudo apt install apache2

仮想マシン1側のみ、リバースプロキシとして構築するので、mod_proxyおよびmod_proxy_httpを有効にします。

$ sudo a2enmod proxy proxy_http

仮想マシン2へのリバースプロキシとして設定。
/etc/apache2/sites-enabled/000-default.conf

<VirtualHost *:80>      
  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/html

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined

  ProxyPass / http://10.0.0.11
  ProxyPassReverse / http://10.0.0.11
</VirtualHost>

Apacheを再起動します。

$ sudo systemctl restart apache2

また、仮想マシン2の方は、アクセス確認のためにindex.htmlを変更します(HTMLになってないですけど)。
/var/www/html/index.html

Hello Apache!!

ここで、ホスト側から仮想マシン1に対してHTTPリクエストを投げます。

$ curl -i 192.168.33.10
HTTP/1.1 200 OK
Date: Sat, 11 Apr 2020 13:14:34 GMT
Server: Apache/2.4.29 (Ubuntu)
Last-Modified: Sat, 11 Apr 2020 13:13:03 GMT
ETag: "f-5a3039c1f6fed"
Accept-Ranges: bytes
Content-Length: 15
Content-Type: text/html

Hello Apache!!

まず、仮想マシン2まで到達していることが確認できました。

この時の、仮想マシン1のApacheのアクセスログを確認。

192.168.33.1 - - [11/Apr/2020:13:14:34 +0000] "GET / HTTP/1.1" 200 241 "-" "curl/7.58.0"

次に、仮想マシン2のApacheのアクセスログを確認します。ソースIPが、仮想マシン1の「10.0.0.10」となっています。

10.0.0.10 - - [11/Apr/2020:13:14:34 +0000] "GET / HTTP/1.1" 200 297 "-" "curl/7.58.0"

想定通りの挙動ですね。

tcpdumpでも、パケットを見ておきました。

$ sudo tcpdump -i any tcp port 80 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes


13:14:34.437266 IP 192.168.33.1.36380 > 192.168.33.10.80: Flags [S], seq 4126635863, win 29200, options [mss 1460,sackOK,TS val 1069883733 ecr 0,nop,wscale 7], length 0
13:14:34.437347 IP 192.168.33.10.80 > 192.168.33.1.36380: Flags [S.], seq 3231866269, ack 4126635864, win 65160, options [mss 1460,sackOK,TS val 3515437649 ecr 1069883733,nop,wscale 7], length 0
13:14:34.437425 IP 192.168.33.1.36380 > 192.168.33.10.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 1069883733 ecr 3515437649], length 0
13:14:34.437448 IP 192.168.33.1.36380 > 192.168.33.10.80: Flags [P.], seq 1:78, ack 1, win 229, options [nop,nop,TS val 1069883733 ecr 3515437649], length 77: HTTP: GET / HTTP/1.1
13:14:34.437478 IP 192.168.33.10.80 > 192.168.33.1.36380: Flags [.], ack 78, win 509, options [nop,nop,TS val 3515437649 ecr 1069883733], length 0
13:14:34.437759 IP 10.0.0.10.39794 > 10.0.0.11.80: Flags [F.], seq 3809542179, ack 1644144670, win 501, options [nop,nop,TS val 3564697986 ecr 3477033970], length 0
13:14:34.437815 IP 10.0.0.10.39796 > 10.0.0.11.80: Flags [S], seq 1591844355, win 64240, options [mss 1460,sackOK,TS val 3564697986 ecr 0,nop,wscale 7], length 0
13:14:34.438097 IP 10.0.0.11.80 > 10.0.0.10.39794: Flags [.], ack 1, win 508, options [nop,nop,TS val 3477042455 ecr 3564697986], length 0
13:14:34.438117 IP 10.0.0.11.80 > 10.0.0.10.39796: Flags [S.], seq 3826655060, ack 1591844356, win 65160, options [mss 1460,sackOK,TS val 3477042456 ecr 3564697986,nop,wscale 7], length 0
13:14:34.438129 IP 10.0.0.10.39796 > 10.0.0.11.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 3564697986 ecr 3477042456], length 0
13:14:34.438182 IP 10.0.0.10.39796 > 10.0.0.11.80: Flags [P.], seq 1:193, ack 1, win 502, options [nop,nop,TS val 3564697986 ecr 3477042456], length 192: HTTP: GET / HTTP/1.1
13:14:34.438291 IP 10.0.0.11.80 > 10.0.0.10.39796: Flags [.], ack 193, win 508, options [nop,nop,TS val 3477042456 ecr 3564697986], length 0
13:14:34.439187 IP 10.0.0.11.80 > 10.0.0.10.39796: Flags [P.], seq 1:298, ack 193, win 508, options [nop,nop,TS val 3477042457 ecr 3564697986], length 297: HTTP: HTTP/1.1 200 OK
13:14:34.439201 IP 10.0.0.10.39796 > 10.0.0.11.80: Flags [.], ack 298, win 501, options [nop,nop,TS val 3564697987 ecr 3477042457], length 0
13:14:34.439327 IP 192.168.33.10.80 > 192.168.33.1.36380: Flags [P.], seq 1:242, ack 78, win 509, options [nop,nop,TS val 3515437651 ecr 1069883733], length 241: HTTP: HTTP/1.1 200 OK
13:14:34.439381 IP 192.168.33.1.36380 > 192.168.33.10.80: Flags [.], ack 242, win 237, options [nop,nop,TS val 1069883735 ecr 3515437651], length 0
13:14:34.439469 IP 192.168.33.1.36380 > 192.168.33.10.80: Flags [F.], seq 78, ack 242, win 237, options [nop,nop,TS val 1069883735 ecr 3515437651], length 0
13:14:34.439543 IP 192.168.33.10.80 > 192.168.33.1.36380: Flags [F.], seq 242, ack 79, win 509, options [nop,nop,TS val 3515437652 ecr 1069883735], length 0
13:14:34.439650 IP 192.168.33.1.36380 > 192.168.33.10.80: Flags [.], ack 243, win 237, options [nop,nop,TS val 1069883736 ecr 3515437652], length 0

なんとなく、確認しておくと安心かな、というPrivate Networkの設定回りでした、と。