VagrantでSoftLayerに仮想サーバーをProvisioningする

仮想化環境やクラウドにサーバー環境を簡単に構築できるVagrantですが、SoftLayerでも仮想サーバーのProvisioningや操作に利用できます。その手順や設定を記載。
Vagrantのインストールやboxの準備は飛ばします。

## 前提

- Vagrantがインストールされている
- SoftLayer CLIがインストールされていて、ユーザーID & API Key が設定されている


## 準備

### vagrant-softlayerプラグインのインストール

```bash
$ vagrant plugin install vagrant-softlayer
Installing the 'vagrant-softlayer' plugin. This can take a few minutes...
Installed the plugin 'vagrant-softlayer (0.4.0)'!

$ vagrant plugin list
vagrant-aws (0.6.0)
vagrant-login (1.0.1, system)
vagrant-omnibus (1.4.1)
vagrant-share (1.1.4, system)
vagrant-softlayer (0.4.0)
```

[audiolize/vagrant-softlayer · GitHub](https://github.com/audiolize/vagrant-softlayer)


### Vagrantfileの作成

- 複数仮想サーバーの起動、Provisioningが可能(以下のファイルではコメントアウト)
- Provisioingは、インラインスクリプト、シェルスクリプト、Chefで自動構成
  - シェルスクリプト: ```script/pre-provision.sh```
  - Chef: ```cookbooks/```以下にレシピを作成

```rb:Vagrantfile_example
# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

SL_USER_NAME = "<SL_USERNAME>"
SL_API_KEY = "<SL_API_KEY>"

$script = <<SCRIPT
#gpg --quiet --with-fingerprint /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#yum install -y docker
#yum install -y net-tools
systemctl enable docker.service
systemctl start docker.service
docker version
su - root -c 'echo alias d=docker >> ~/.bashrc'
SCRIPT

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  # ssh options
  config.ssh.username = "root"
  config.ssh.private_key_path = "~/.ssh/sl_rsa"
  config.ssh.pty = true

  # install chef in the VM by vagrant omnibus plugin
  config.omnibus.chef_version = :latest

  # box
  config.vm.box = "dummy"
  config.vm.box_url = "https://github.com/audiolize/vagrant-softlayer/raw/master/dummy.box"

  # sync options
  config.vm.synced_folder ".", "/vagrant", type: "rsync"

  # Multi machine environment

  config.vm.define :server1 do |server1|
    server1.vm.provider :softlayer do | sl, override |
      sl.api_key = SL_API_KEY
      sl.username = SL_USER_NAME
      sl.datacenter = "tok02"
      sl.dedicated = false
      sl.hostname = "TK-docker-centos7-01"      
      sl.domain = "example.com"
      sl.hourly_billing = true
      sl.local_disk = true
      sl.max_memory = 1024
      sl.network_speed = 100

      # Specify Operating System and disk capacity (See "sl vs create-options" command)
      sl.operating_system = "CENTOS_7_64"
      sl.disk_capacity = { 0 => 25 }
      # sl.operating_system = nil

      # Or specify a compute or flex image guid (see "sl image list" command)
      # sl.image_guid = nil
      # sl.image_guid = "e2970bb2-95d0-4227-955c-5a19da114dd3"

      # post install script
      # sl.post_install = <URL>

      sl.ssh_key = [ "sladmin_ssh_key" ]
      sl.start_cpus = 1
      override.ssh.username = "root"
    end

=begin
  config.vm.define :server2 do |server2|
    server2.vm.provider :softlayer do | sl, override |
      sl.api_key = SL_API_KEY
      sl.username = SL_USER_NAME
      sl.datacenter = "tok02"
      sl.dedicated = false
      sl.hostname = "TK-docker-centos7-02"
      sl.domain = "example.com"
      sl.disk_capacity = { 0 => 25 }
      sl.hourly_billing = true
      sl.image_guid = nil
      sl.local_disk = true
      sl.max_memory = 1024
      sl.network_speed = 100
      sl.operating_system = "CENTOS_7_64"
      sl.ssh_key = [ "sladmin_ssh_key" ]
      sl.start_cpus = 1
      override.ssh.username = "root"
    end
  end
=end

  end

  # Run custom inline script in Vagrantfile
  if Dir.glob("#{File.dirname(__FILE__)}/.vagrant/machines/default/*/id").empty?
    config.vm.provision :shell, :inline => $script
  end

  # Enable provisioning with shell script
  config.vm.provision :shell, :path => "script/pre-provision.sh"

  # Enable provisioning with chef solo, specifying a cookbooks path, roles
  # path, and data_bags path (all relative to this Vagrantfile), and adding
  # some recipes and/or roles.
  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "cookbooks"
    chef.add_recipe "setup-user"
    chef.add_recipe "install-package"
    chef.add_recipe "install-chef"
    #chef.add_role "web"
    # You may also specify custom JSON attributes:
    #chef.json = { :mysql_password => "foo" }
  end
end
```



## 実行

### vagrant up

providerを指定しないで```vagrant up```するとエラーになる

```bash
$ vagarnt up
Bringing machine 'server1' up with 'virtualbox' provider...
==> server1: Box 'dummy' could not be found. Attempting to find and install...
    server1: Box Provider: virtualbox
    server1: Box Version: >= 0
==> server1: Adding box 'dummy' (v0) for provider: virtualbox
    server1: Downloading: https://github.com/audiolize/vagrant-softlayer/raw/master/dummy.box
The box you attempted to add doesn't match the provider you specified.

Provider expected: virtualbox
Provider of box: softlayer
```


### --provider=softlayer を指定して実行

rsyncでエラーになる

```bash
$ vagrant up --provider=softlayer
Bringing machine 'default' up with 'softlayer' provider...
==> default: HandleBoxUrl middleware is deprecated. Use HandleBox instead.
==> default: This is a bug with the provider. Please contact the creator
==> default: of the provider you use to fix this.
==> default: Creating a new SoftLayer instance...
==> default: Waiting for instance provisioning. This may take a few minutes...
==> default: SoftLayer instance successfully provisioned!
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: xxx.xxx.xxx.xxx:22
    default: SSH username: root
    default: SSH auth method: private key
Text will be echoed in the clear. Please install the HighLine or Termios libraries to suppress echoed text.
Enter passphrase for /home/takech/.ssh/sl_rsa:  
==> default: Machine booted and ready!
==> default: Rsyncing folder: /home/takech/vagrant/softlayer/ => /vagrant
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
```

Provisioningはされている

```bash
$ vagrant status
Current machine states:

server1                   running (softlayer)
```

## イメージの更新

- オリジナルのイメージCENTOS_7_64でProvigioingされるサーバーは、デフォルトでsudoコマンド実行時にttyが必要な設定になっている(/etc/sudores)。
- フォルダ共有のためにvagrantではrsyncが実行される
- rsyncの中で、sshから```sudo mkdir -p 'vagrant/'```コマンドが呼ばれているが、sshからのコマンド実行ではttyが割り当てられず、エラーになる


いろいろ試したけどProvisioing中に設定を変更するのは難しそうなので、設定ファイルを修正したイメージを作成して、そのイメージでProvisioingするようにする。

- sshでコマンドを発行するところで -t オプションを付ければよいのかも


### vagrant ssh でログイン

```bash
$ vagrant ssh
Last failed login: Sat Jan  3 07:44:33 CST 2015 from xx.xxx.xxx.x on ssh:notty
There were 21 failed login attempts since the last successful login.
Last login: Sat Jan  3 07:42:11 2015 from hxxx-xxx-xxx-xxx.xxxxx.xxxxx.jp
[root@TK-docker-centos7 ~]#
```

### /etc/sudoerを修正

ログインした先のSLの仮想サーバーの上のファイル```/etc/sudoders```を```visudo```コマンドで修正

```bash:/etc/sudoers
#
# Disable "ssh hostname sudo <cmd>", because it will show the password in clear.
#         You have to run "ssh -t hostname sudo <cmd>".
#
#Defaults    requiretty
Defaults    !requiretty
```


### Standard Imageを作成

```bash
$ sl vs list | grep docker
9713c5ce-e11b-4c29-b4d5-a16ef3a34158  TK-docker-centos7  xxx.xxx.xx.xx    10.132.2.217   tok02  NULL

$ sl vs capture 9713c5ce-e11b-4c29-b4d5-a16ef3a34158 -n docker-centos7-02
:................:............................:
:           Name : Value                      :
:................:............................:
:          vs_id : 6069184                    :
:           date : 2015-01-25                 :
:           time : 00:19:49                   :
:    transaction : Create Cloud Disk Template :
: transaction_id : 15706140                   :
:      all_disks : None                       :
:................:............................:

$ sl image list |grep docker-centos7-02
3ae8566d-85f4-4a0b-b490-fc9ca26b543a  docker-centos7-02         SYSTEM        PRIVATE  319556
```


### 一旦destroy

```bash
$ vagrant destroy
    server1: Are you sure you want to destroy the 'server1' VM? [y/N] y
==> server1: Destroying the SoftLayer instance...
==> server1: Running cleanup tasks for 'shell' provisioner...

$ vagrant status
Current machine states:

server1                   not created (virtualbox)
```

## 更新したイメージで起動

### イメージを確認

```bash
$ sl image list |grep docker-centos7-02
3ae8566d-85f4-4a0b-b490-fc9ca26b543a  docker-centos7-02         SYSTEM        PRIVATE  319556
```

### Vagrantfileの修正

起動するイメージを、さっき取得したものに変更

```rb
      # Specify Operating System and disk capacity (See "sl vs create-options" command)
      # sl.operating_system = "CENTOS_7_64"
      # sl.disk_capacity = { 0 => 25 }
      sl.operating_system = nil

      # Or specify a compute or flex image guid (see "sl image list" command)
      # CentOS-7.0-docker02 - no tty required for sudo for rsync
      sl.image_guid = "3ae8566d-85f4-4a0b-b490-fc9ca26b543a"    

```

## 再度実行

```bash
$ vagarnt up --provider=softlayer

```

普通はこれでいけるはず(以前はいけた)

ただ、現時点では以下のエラーがあり、サーバーの起動はできるがChef等でのProvisionigが失敗する模様。

- [\`ip_addr ess_record': undefined method \`[]' for nil:NilClass (NoMethodError) during vagrant up · Issue #44 · audiolize/vagrant-softlayer](https://github.com/audiolize/vagrant-softlayer/issues/44)



## 参考リンク

- [Vagrant から SoftLayer の仮想サーバを Provisioning する - Qiita](http://qiita.com/kentarok/items/f58174aa573359e369e4)
- [Vagrant から SoftLayer の仮想サーバを 1度に複数 Provisioning する - Qiita](http://qiita.com/kentarok/items/efcbee0b708a3d71aef3)