はちびる日記

Vagrantで複数の仮想マシンを起動する

社内向けの勉強会の環境としてEC2インスタンスを複数作成する機会があったので、Vagrantを使ってやってみました。

環境

  • ワーク端末 : Mac OSX 10.9
  • Vagrant : 1.6.1
  • vagrant-aws : 0.4.1

1台のEC2インスタンスを起動する場合のVagrantfile

比較のために、1台のEC2インスタンス(Amazon Linux)を起動する場合のVagrantfileを記載します。
アクセスキーとシークレットアクセスキーは環境変数に設定してします。

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = 'dummy'

  config.vm.provider :aws do |aws, override|
    aws.access_key_id = ENV['AWS_ACCESS_KEY_ID']
    aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
    aws.region = 'ap-northeast-1'
    aws.instance_type = 't1.micro'
    # Amazon Linux AMI 2014.03.1(x64)
    aws.ami = 'ami-c9562fc8'
    aws.security_groups = ['Web Server']
    aws.keypair_name = 'test1'
    aws.tags = {
      'Name' => 'test1'
    }

    override.ssh.username = 'ec2-user'
    override.ssh.private_key_path = '~/.ssh/test1.pem'
  end
end

2台のEC2インスタンスを起動する場合のVagrantfile

config.vm.defineメソッドを使います。引数には仮想マシン名と、その仮想マシンの設定のためのブロックを渡します。 仮想マシン設定のためのブロックは、上で書いた1台の仮想マシンを設定する場合のものと同一です。

複数のEC2インスタンスを起動する場合は、このconfig.vm.defineを台数分書くのが基本です。

boxは全インスタンスで共通のものを使うので、config.vm.defineの外側でconfig.vm.box = 'dummy'を定義します。 (こうすることでconfig.vm.boxの設定が各config.vm.defineに継承されます。)

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = 'dummy'

  config.vm.define :test1 do |test1|
    test1.vm.provider :aws do |aws, override|
      aws.access_key_id = ENV['AWS_ACCESS_KEY_ID']
      aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
      aws.region = 'ap-northeast-1'
      aws.instance_type = 't1.micro'
      # Amazon Linux AMI 2014.03.1(x64)
      aws.ami = 'ami-c9562fc8'
      aws.security_groups = ['Web Server']
      aws.keypair_name = 'test1'
      aws.tags = {
        'Name' => 'test1'
      }

      override.ssh.username = 'ec2-user'
      override.ssh.private_key_path = '~/.ssh/test1.pem'
    end
  end

  config.vm.define :test2 do |test2|
    test2.vm.provider :aws do |aws, override|
      aws.access_key_id = ENV['AWS_ACCESS_KEY_ID']
      aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
      aws.region = 'ap-northeast-1'
      aws.instance_type = 't1.micro'
      # Amazon Linux AMI 2014.03.1(x64)
      aws.ami = 'ami-c9562fc8'
      aws.security_groups = ['Web Server']
      aws.keypair_name = 'test2'
      aws.tags = {
        'Name' => 'test2'
      }

      override.ssh.username = 'ec2-user'
      override.ssh.private_key_path = '~/.ssh/test2.pem'
    end
  end
end

Vagrantfileの冗長性を排除

今回は全く同じ構成のEC2インスタンスを複数台起動したかったので、シーケンス番号部分を変数化しconfig.vm.defineを繰り返し定義する形としました。

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = 'dummy'

  #5台のEC2インスタンスを起動
  (1..5).each do |num|
    config.vm.define "test#{num}" do |node|
      node.vm.provider :aws do |aws, override|
        aws.access_key_id = ENV['AWS_ACCESS_KEY_ID']
        aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
        aws.region = 'ap-northeast-1'
        aws.instance_type = 't1.micro'
        # Amazon Linux AMI 2014.03.1(x64)
        aws.ami = 'ami-bb84c4ba'
        aws.security_groups = ['Web Server']
        aws.keypair_name = "test#{num}"
        aws.tags = {
          'Name' => "test#{num}"
        }

        override.ssh.username = 'ec2-user'
        override.ssh.private_key_path = "~/.ssh/test#{num}.pem"
      end
    end
  end
end

仮想マシンの制御

vagrantコマンドにマシン名を渡せばOKです。例えばtest1にsshで接続する場合は以下のようにコマンドを実行します。

$ vagrant ssh test1

仮想マシンの停止(halt)や削除(destroy)は、複数のマシンに対して実行できます。(仮想マシン名を指定しなかった場合は、全仮想マシンに対して処理が実行されます。)

$ vagrant halt test1 test2

【補足】Synced Foldersのエラー対応

Vagrantはvagrant up時にリモートの仮想マシン上でmkdir -p '/vagrant'コマンドを実行してSynced Foldersを 作成しますが、EC2のAmazon Linuxではsudoの実行にtty経由でのssh接続が必須となっているため、このsshでのリモートコマンド実行がエラーとなります。 (EC2インスタンスの起動自体は成功します。)

# エラー内容
The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

mkdir -p '/vagrant'

Stdout from the command:



Stderr from the command:

sudo: sorry, you must have a tty to run sudo

対応として、一旦sshでEC2インスタンスにログインし、/etc/sudoersの設定を変更しtty無しでのsudoの発行を許可します。

$ vagrant ssh test1
$ sudo visudo
# 以下をコメントアウトし全ユーザについてtty無しでのsudoの発行を許可する
Defaults    requiretty

# または以下のように設定しec2-userのみtty無しでのsudoの発行を許可する
Defaults:ec2-user    !requiretty

VagnrantからAmazon Linuxを頻繁に利用する場合は、この設定を行ったインスタンスからAMIを作成しておくと便利です。

参考サイト/書籍

comments powered by Disqus

© Yutaka Yawata 2014-2015. All right reserved.