page_adsence

2015年4月9日木曜日

Vagrantでsuspendからresumeする際のポート問題

vagrantでマシンを起動や停止を行う際に、「vagrant up」「vagrant halt」を使っていたが、
これだと起動や停止にかかる時間が長いのでよく利用するVMに関しては「vagrant suspend」(一時停止)「vagrant resume」(復帰)を利用するようにしている。
しかしこの「vagrant suspend」「vagrant resume」を複数のVMで併用していると、ある工程で作業をすると問題が出てくる。

問題となる手順は以下の通り。
1.VM1を「vagrant up」で起動
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Connection timeout. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /vagrant => C:/cygwin64/home/XXXXXXXXX/XXXXXXXXX/XXXXXXXXX-1
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: to force provisioning. Provisioners marked to run always will still run.

2.VM1を「vagrant suspend」で一時停止
$ vagrant suspend
==> default: Saving VM state and suspending execution...

3.VM2を「vagrant up」で起動
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Connection timeout. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /vagrant => C:/cygwin64/home/XXXXXXXXX/XXXXXXXXX/XXXXXXXXX-2
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: to force provisioning. Provisioners marked to run always will still run.

4.VM2を「vagrant suspend」で一時停止
$ vagrant suspend
==> default: Saving VM state and suspending execution...

5.VM1で「vagrant resume」で起動
$ vagrant resume
==> default: Resuming suspended VM...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection refused. Retrying...
==> default: Machine booted and ready!

6.VM2で「vagrant resume」をするが起動しない。
$ vagrant resume
Vagrant cannot forward the specified ports on this VM, since they
would collide with some other application that is already listening
on these ports. The forwarded port to 2222 is already in use
on the host machine.

To fix this, modify your current projects Vagrantfile to use another
port. Example, where '1234' would be replaced by a unique host port:

  config.vm.network :forwarded_port, guest: 22, host: 1234

Sometimes, Vagrant will attempt to auto-correct this for you. In this
case, Vagrant was unable to. This is usually because the guest machine
is in a state which doesn't allow modifying port forwarding.

ここで、何が問題になって起動しないかというと、ホストマシンからVMにSSH接続する際に使用するポートの重複が問題となっている。
※VMを2台同時に立ち上げる事が問題なのではなく、立ち上げる時の工程に問題がある。

こういった問題を回避する為に、予めローカルからVMにSSH接続する際に使用するポート番号を変更しておく必要がある。
ポート番号の変更方法は、Vagrantfileに下記の様な設定を追加する事で回避出来る。

config.vm.network "forwarded_port", id: "ssh", guest: 22, host: 2223

一度全てのVMを「vagrant halt」で停止させてから、Vagrantfileを編集し、上記設定を追記した状態で「vagrant up」する。
追加する場所は下記のコメントがあるので、その下辺りに追加する。

# config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", id: "ssh", guest: 22, host: 2223 ← この部分を追記

保存した状態で再び「vagrant up」すると、
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 => 2223 (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2223
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /vagrant => C:/cygwin64/home/XXXXXXXXX/XXXXXXXXX/XXXXXXXXX-2
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: to force provisioning. Provisioners marked to run always will still run.

この様な感じで立ち上がる。
ちなみに複数台立ち上げて「vagrant resume」「vagrant suspend」しても問題ない手順は以下の通り。

1.VM1を「vagrant up」で起動
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Connection timeout. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /vagrant => C:/cygwin64/home/kusagaya-naoki/VirtualBoxMachines/jenkins-laravel
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: to force provisioning. Provisioners marked to run always will still run.

2.VM2を「vagrant up」で起動
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set forwarded ports...
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 => 2200 (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2200
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /vagrant => C:/cygwin64/home/kusagaya-naoki/VirtualBoxMachines/jenkins-laravel-2
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: to force provisioning. Provisioners marked to run always will still run.

3.VM1を「vagrant suspend」で停止
$ vagrant suspend
==> default: Saving VM state and suspending execution...

4.VM2を「vagrant suspend」で停止
$ vagrant suspend
==> default: Saving VM state and suspending execution...

5.VM1を「vagrant resume」で起動
$ vagrant resume
==> default: Resuming suspended VM...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection refused. Retrying...
==> default: Machine booted and ready!

6.VM2を「vagrant resume」で起動
$ vagrant resume
==> default: Resuming suspended VM...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2200
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection refused. Retrying...
==> default: Machine booted and ready!

赤文字にした部分も見てもらえれば一目瞭然だと思いますが、
なぜこの手順で問題ないかというと、「vagrant up」時にはSSHポート番号が重複していた場合に
vagrantが自動で別の開いているポートを使用して立ち上げる様になっている。
しかし、このポートチェックは現在起動しているVMで使用されているポート番号だけで、一時停止されているVMに使われているポート番号はチェック対象にならない。
そのため、手順によってはこういった現象が発生する。
常にこの様な手順で起動させるようにしていればこういった事態にはならないが、常にこの手順を守れるわけではないので、予めポート番号は設定しておいたほうが良さげ。