VagrantfileのみでCentOSの起動とruby2.1のインストールをやってみる


# こんなことをやってみたい
- CentOSに最新のrubyをインストールしたい。
- vagrantを利用したい
- ruby入りのboxを使うのではなく、素のCentOSを使って手順を自分で試したい
- OS起動後に自分でsshでログインしてからrubyのセットアップをするのではなく、自動でインストールが進んで欲しい
- ひとまずrubyが入ったら、自分のイメージとしてboxを作りたい。
- rubyのリモートでバッグをしたい。（ゆくゆく）

※プロビジョニングにはChefを使えそうではあるけれど、Chefはそもそも対象ノードにrubyを入れるのが前提です。


## Chefを使わずに簡単にプロビジョニング
Vagrantを使ってVMを起動したあとは、Chef (Chef-solo)を使ってプロビジョニングができます。
でも、そこまでしなくても、設定ファイルなどは調整せず、単純にyumでパッケージをインストールするくらいなら、shellを使って実施ができます。

### 注意点
Vagrantで **config.vm.provision :shell** をつかうとshellが実行できるのですが、基本はvagrantアカウントでsudoを使って操作になります。
でも、Vagrantの元になっているBoxによっては **sudoした際のPATHが決まっていて、/usr/local/bin にインストールされたものが使えなかったりする**ので、ご注意を。

以下は、CentOSの場合のvisudoでの確認。

```
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin
```
## CentOS6.5に、Vagrantのプロビジョニング段階でrubyをインストールしてみる

### rubyをインストールする手順を用意する

参考にしたのは、実は、[index.docker.io](index.docker.io) にあったCentOS6.5 + ruby2.1入りのイメージです。

- https://index.docker.io/u/tmtk75/ruby-2.1.0p0/

『Vagrantをすっ飛ばして、Dockerですか？』とお叱りを受けそうですが、Dockerのイメージは、docker history とすると、そのイメージが **どんなコミットの積み重ねで生成されたか**が分かります。
また、docker.io の対象のイメージのページには、そのイメージを作るもとになったのDockerfileも掲載されています。

ということで、インストールの手順が大変参考になります。
Vagrantのboxは、参考にしたDockerのイメージと同じく、CentOS。ただし、CentOS6.5を利用しました。

- https://github.com/2creatives/vagrant-centos/releases/tag/v6.5.1

### 参考にしたVagrantfileは、こんな感じ

```source:ruby
# -*- 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|
  # 利用するboxと、host名を設定
  config.vm.box = "cent65"
  config.vm.hostname = "test" 

　# Virtualboxのネットワークで、固定IPを割り当て
  config.vm.network :private_network, ip: "192.168.33.11"

　# boxは基本はメモリが512MBなので、2GBにしておく
  config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--memory", "2048"]
    vb.customize ["modifyvm", :id, "--cpus", "1"]  
  end

  # ここから、Chefを使わない簡単プロビジョニング
  config.vm.provision :shell, :inline => <<-EOT
      yum install -y gcc
      yum install -y zlib-devel openssl-devel
      cd /usr/local; curl -OL http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.0.tar.gz
      cd /usr/local; tar xfz ruby-2.1.0.tar.gz
      cd /usr/local/ruby-2.1.0; ./configure --prefix=/usr/local; make; make install
      # 実はここ、絶対パスでなく gem install … だったら失敗しました。
      /usr/local/bin/gem install bundler --no-ri --no-rdoc
  EOT
end
```

## Server specでチェック

vagrant upでイメージの起動からプロビジョニングまで済んだら、ちゃんとVagrantfileの通りになっているか、server specで確認してみます。
単純に、ホスト名やOS, rubyが指定のパスにインストールできたか、というチェックです。

### specファイルの例

```source:ruby
require 'spec_helper'

# OS チェック
describe file('/etc/redhat-release') do
  it { should contain 'CentOS' }
end

# ホスト名チェック
describe file('/etc/sysconfig/network') do
  it { should contain 'test' }
end

# SELinux 無効の確認
describe selinux do
  it { should be_disabled }
end

# ruby 
describe file('/usr/local/bin/ruby') do
  it { should be_executable }
end

describe command('/usr/local/bin/ruby -v') do
  it { should return_stdout /^ruby 2\.1\.0/ }
end

```
### rake specで確認

実行してみます。うまくテストが通った模様。

```
% rake spec
/Users/xxx/.rbenv/versions/2.0.0-p247/bin/ruby -S rspec spec/default/default_spec.rb
....

Finished in 2.11 seconds
5 examples, 0 failures

```

## うまくいったのでSnapshotを取っておこう！

Vagrantでは、saharaというシンプルなSnapshotを取るプラグイン以外にも、snapshotというプラグインがあります。こちらの方が、コマンドラインから名前付きスナップショットが取得できるので、便利。

```source:bash
% vagrant snapshot take ruby2.1-installed
Taking snapshot ruby2.1-installed
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

% vagrant snapshot list
Listing snapshots for 'default':
   Name: ruby2.1-installed (UUID: 9e25d049-0445-46db-9b05-3432d819d3c1) *

```

以上、VagrantでベースのCentOSを起動後、chefではなくconfig.vm.provision :shellを使ってruby2.1を入れる手順を検証してみました。
リモートデバッグに関しては、ruby2.1向けはまだ上手くできませんでしたが、上手く出来たら次回に書こうと思います。

# 追記：出来上がったCentOSにChefを入れておく

http://www.vagrantbox.es で、そもそもChef-soloインストール済みのBoxが提供されていますが、今回は自前でChef-soloを入れます。
また、rubyをインストールするプロビジョンの段階で、Chef-soloのインストールステップを追加することもできますが、ここでは、Vagrantのホスト側から、knife solo prepareで追加することにします。

なお **config.vm.provision は、実行されるタイミングに制限**があります。

 - 初回のvagrant init
 - vagrant provision を明示した際
 - vagrant reload --provision を明示した場合
 - 参考：http://docs.vagrantup.com/v2/provisioning/basic_usage.html

最初にvagrant upでOS起動とプロビジョニングを実施し、その後にconfig.vm.provisionに追加操作をさせたい場合は **上記のいずれかで明示的に指定しないと反映されません**。
(あ、このコマンドもyumで入れとけば良かった、と後から気がついた時とか）

## SSHのキーを登録する

では、Chef-soloを入れる作業に移ります。

- 前提：
 - Vagrantを管理する側にも、Chef-soloが入っていて、Chefのリポジトリもそこで管理している。

出来上がったCentOSのホスト名は、config.vm.hostname = "test" と設定したので、ssh test でログインできるように、vagrant ssh-config にオプションを付けて、鍵を登録します。
（※ --host を指定しないと、Host default という名前になって登録されます）

```source:bash
% vagrant ssh-config --host test >> ~/.ssh/config
``` 

## knife solo prepare で、ホスト側からChef-soloをインストールする

knife solo prepare ".ssh/configで登録したホスト" で、ホスト側からのChef-soloのインストールができますので、ruby2.1でも問題ないか確認します。 

```
% knife solo prepare test
Bootstrapping Chef...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 14101  100 14101    0     0   2244      0  0:00:06  0:00:06 --:--:-- 20555
Downloading Chef 11.8.0 for el...
downloading https://www.opscode.com/chef/metadata?v=11.8.0&prerelease=false&p=el&pv=6&m=x86_64
  to file /tmp/install.sh.12727/metadata.txt
trying curl...
url	https://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chef-11.8.0-1.el6.x86_64.rpm
md5	8f72d94dffd75c3f79dc0fcd457e7f11
sha256	1a1e3df541240dcf5da1d128b1a4341224db5a2e1dee83b3f0f5d41e0aadb2a3
downloaded metadata file looks valid...
downloading https://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chef-11.8.0-1.el6.x86_64.rpm
  to file /tmp/install.sh.12727/chef-11.8.0.x86_64.rpm
trying curl...
Checksum compare with sha256sum succeeded.
Installing Chef 11.8.0
installing with rpm...
warning: /tmp/install.sh.12727/chef-11.8.0.x86_64.rpm: Header V4 DSA/SHA1 Signature, key ID 83ef826a: NOKEY
Preparing...                ########################################### [100%]
   1:chef                   ########################################### [100%]
Thank you for installing Chef!
Generating node config 'nodes/test.json'...

```
入ったようです。

## Server specで再度チェック

Host test にChefが入ったか、これもserver specで確認してみます。上記のspecファイルに追加してチェック。

```
# Chef-soloが入ったかチェック
# knife solo prepareであとから入れた場合のテスト
describe file('/usr/bin/chef-solo') do
  it { should be_executable }
end
```