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に使われているポート番号はチェック対象にならない。
そのため、手順によってはこういった現象が発生する。
常にこの様な手順で起動させるようにしていればこういった事態にはならないが、常にこの手順を守れるわけではないので、予めポート番号は設定しておいたほうが良さげ。

スッキリわかるJava 第2版を買ってみた。

会社のメンバーと何か作ろうという話になったので、とりあえずJavaの勉強から初めて見る。
どんな本がいいかなと色々探したけど、評価的にはこれが一番良さそうだったので買ってみた。


Kindle版買うかどうか悩みましたが、結局紙の本を買った。
でも電車の中で読んだりするにはKindle版の方が良かったかなと。

これからどんどん読み進めて行こうと思う。

2015年4月7日火曜日

AnsibleでJenkinsのインストールからJenkinsのプラグインインストールまで。

ローカルのVMにjenkinsをインストールして使おうと思ったのですが、調べてみたらyumでインストールしている記事ばかりだったので、 warファイルをダウンロードしてきて、それを起動するシェルスクリプトを作り、サービスとして登録し、起動させるという方法でやってみた。
最終的な成果物としては下記の様なplaybookとなった。
playbookで書かれているjenkins.shも書いておく。

files/jenkins.shの中身
#!/bin/sh
# chkconfig: 2345 70 30
# description: jenkins
# processname: jenkins

java -jar /usr/lib/jenkins/jenkins.war &

ここからAnsibleのプレイブック
---
- hosts: "target_host"
  sudo: yes
  remote_user: vagrant
  tasks:
    - name: JavaのOpenJDKをインストール
      yum: name=java-1.8.0-openjdk state=latest

    - name: JavaのOpenJDK develをインストール
      yum: name=java-1.8.0-openjdk-devel state=latest

    - name: Jenkinsのwarファイルの設置用ディレクトリを作成
      file: dest=/usr/lib/jenkins state=directory

    - name: jenkins.warファイルをサイトからダウンロード
      get_url: url=http://mirrors.jenkins-ci.org/war/latest/jenkins.war
               dest=/usr/lib/jenkins

    - name: ホストPCに置いておいたjenkins.shをリモートPCへコピー
      template: src=files/jenkins.sh
                dest=/etc/init.d/jenkins
                mode=0777

    - name: chkconfigにjenkinsを登録
      action: command chkconfig --add jenkins

    - name: jenkinsの起動レベルを変更
      action: command chkconfig --level 2345 jenkins on

    - name: jenkinsを起動
      service: name=jenkins state=started enabled=yes
      sudo: no

    - name: jenkinsのcliツールをダウンロード
      get_url: url=http://localhost:8080/jnlpJars/jenkins-cli.jar
               dest=/tmp

    - name: プラグインをインストール [build-pipeline-plugin]
      action: command java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 install-plugin build-pipeline-plugin

    - name: プラグインをインストール [timestamper]
      action: command java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 install-plugin timestamper

    - name: プラグインをインストール [git]
      action: command java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 install-plugin git

    - name: プラグインをインストール [jobConfigHistory]
      action: command java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 install-plugin jobConfigHistory

    - name: プラグインをインストール [cron_column]
      action: command java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 install-plugin cron_column

    - name: プラグインをインストール [next-executions]
      action: command java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 install-plugin next-executions

    - name: プラグインをインストール [ssh]
      action: command java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 install-plugin ssh

    - name: jenkins restart
      action: command java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 safe-restart


jenkinsのプラグインをコマンドラインからインストールする場合に、
java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 install-plugin XXXXXX
と記載する必要があるのですが、このXXXXXの部分はPluginIDを入れる必要がある。
PluginIDの調べ方はJenkinsのプラグインの一覧があるページから入れたいプラグインをクリックすると、上のほうにある表の左上に「Plugin ID」の項目があるので、そこに書かれているIDを入れる。

Vagrant upをした時のエラー

vagrantを使ってVM作ろうと思ったのですが、Vagrantfileの中身を色々と間違えていた事に気がついたので、1から作リ直そうとした時に出たエラー。

行った作業としては以下の通り。

$ vagrant init box-name

$ vi Vagrantfile

$ vagrant up

ここで間違いに気がついたので、VirtualBoxでマシンを停止。(ここでVirtualBoxで止めるのではなく、vagrant haltしてれば起きなかったかもしれない)

$ vagrant destroy

$ vim Vagrantfile
Vagrantfileの中身を修正(但しvb.nameは同じ)

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'centos6.4-30gb'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: jenkins-laravel
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["modifyvm", "a36f7bef-e56e-4686-91a4-a649a92f3a17", "--name", "jenkins-laravel"]

Stderr: VBoxManage.exe: error: Could not rename the directory 'C:\Users\username\VirtualBox VMs\vagrant-centos64_1_1427941735336_99768' to 'C:\Users\username\VirtualBox VMs\jenkins-laravel' to save the settings file (VERR_ALREADY_EXISTS)
VBoxManage.exe: error: Details: code E_FAIL (0x80004005), component SessionMachine, interface IMachine, callee IUnknown
VBoxManage.exe: error: Context: "SaveSettings()" at line 2716 of file VBoxManageModifyVM.cpp

こんな感じのエラーが出た。
色々と試行錯誤してみたけど、原因はvagrant destroyした時に
C:\Users\username\VirtualBox VMs\jenkins-laravel
のフォルダが消えていなかったため、重複していてリネームできなかった事が原因だった。