初心者によるchef-solo,vagrant,berkshelf等で作るrails+mysqlの環境

## はじめに
僕自身は環境構築が苦手なので、これを期に環境周りの構築をまとめてみた。
間違っている点や疑問点などもあるので、よければコメントでご指摘してもらえると幸いである。

なお、開発環境はMacです。

あと`rails+mysqlの環境`と書いてますが、`railsの環境`は別記事で`capistrano3`について書く予定です。
`ruby`と`mysql`までは入るので、環境自体は完成しているはず・・・！

### 追記
[capistrano3](http://qiita.com/syou007/items/9b8a2f4d1ff099c64fc5)について書きました。


## Chefって？
このページを見てる人は僕よりもスキルが高い人ばかりだと思うので、あえて説明する必要は無いと思うけど、、、念のため書いておく。

Chefはサーバーを構築するレシピを管理して、実施するツールである。
例えば自分のPCがあって、本番のWebサーバーが3台あってそれぞれに対してRailsが動く環境を作るとすると３台のサーバーに`ssh`で入り込み`yum`とか`apt-get`とかをして構築してくことになる。

しかも、同じような案件があったら上記の作業を毎回行う必要が出てくる。
これを自分の手作業で行うと`面倒臭い`し`ミスが発生`するかもしれ無い。
だったら対象サーバーを指定したら同じ事をしてくれるツールがあるといいよね？って事で作られたのが`chef`だ。（多分）

`chef`は構築手順を`レシピ`として残しておけるので、一部を変更してサーバー構築をしたいという時にも便利だし、後述する`berkshelf`などを使えば他の人が作ったレシピを使えたりするので僕のようにサーバー構築が苦手な人でも簡単に使えるのが特長だ。

## Macに必要なものを入れる。

環境開発をする際にお世話になったサイトは[こちら](http://d.hatena.ne.jp/minamijoyo/20150131/p1)です。
ほとんどこのままですが、SQLiteではなくMySQLで構築してます。

### Vagrant
まずはこちらからVagrantをインストールする。
[https://www.vagrantup.com/downloads.html](https://www.vagrantup.com/downloads.html)

### VirtualBox
こちらも同様にインストールする。
[https://www.virtualbox.org/wiki/Downloads](https://www.virtualbox.org/wiki/Downloads)

この辺りで困る事は多分ないはず。

### Vagrantのboxを追加する。
`vagrant`は`VirtualBox`などの仮想OSを簡単に管理できるツールだ。（多分）

例えば`centOS`の仮想OSを入れたい場合は以下のように実行すれば出来上がる。

```sh
$ mkdir centos
$ cd centos
$ vagrant init opscode-centos-6.5 http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.5_chef-provisionerless.box
```

また、仮想OSをあらかじめ自分のPCにダウンロードだけしたい場合は以下のコマンドでできる。

```sh
$ vagrant box add opscode-centos-6.5 http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.5_chef-provisionerless.box
# や
$ vagrant box add centos65 https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box

# こんなフォーマット
$ vagrant box add [ボックスの名前（任意）] [取得URL]
```

※`opscode`は`chef社`の前の名前らしい。なので、僕は無難に`opscode-centos-6.5`を使ってるけど、何が違うかはわから無い・・・。

追加したboxは

```sh
$ vagrant box list
```

で見ることができる。
また、追加したボックスから作成する場合はvagrantを作成したいディレクトに移動して以下のコマンドで出来上がる。

```
$ vagrant init [上記で設定したボックスの名前]
```

`init`コマンドは`Vagrant`ファイルを作成するだけで、実際に仮想OSを作成する場合は以下のコマンドを続けて実行します。

```sh
# 初回構築 or 起動
$ vagrant up

# 終了
$ vagrant halt

# 削除（これがあるので、環境構築に失敗しても気軽にやり直せる。）
$ vagrant destroy
```

### vagrant-omnibusのインストール
これはvagrantにChef Client/Chef Soloがインストールされていなければ自動でインストールするものになります。（この辺の事は、後述の`knife-soloって？`を見てもらえると分かるかと。）

vagrantインストール後に以下のコマンドを実施します。

```sh
$ vagrant plugin install vagrant-omnibus
```

また、後で出てきますがVagrantファイル内に以下の記述を行う必要があります。

```ruby
config.omnibus.chef_version = "バージョン"
# もしくは以下のように指定することで最新のバージョンを入れる。
config.omnibus.chef_version = :latest
```

参考：
[http://www.ryuzee.com/contents/blog/6651](http://www.ryuzee.com/contents/blog/6651)

### chefとknife-soloを入れる。
今回メインで使用するchefを入れます。
その際に`knife-solo`も一緒に入れておきます。

```sh
$ gem install chef
$ gem install knife-solo
```

#### knife-soloって？
`knife-solo`がよく分からなかったのでちょっと調べた。（今までは盲目的に使ってた。）
`chef`には`Chef Server`というものがあり、これを使うと対象のサーバーは`Chef Server`へアクセスしてレシピを取得して自分のサーバーの中身を構築していくと言う事ができる。
`Chef Server`を使うと多くのサーバーで同じ設定ができる上に、対象サーバー内にレシピを持つ必要もないのだが、、、ちょっと試しに使ってみようと思う僕みたいな人には敷居が高い。（`Chef Server`も用意しなければなら無いし・・・。）

`knife-solo`は構築する対象サーバー内部にレシピを持ってきて対象サーバー内部でレシピを実行していくので`Chef Server`がなくても対象サーバーが`Chef Server`のように振舞ってくれるので僕のような人や少ないサーバー管理をしている人にはもってこいの代物だ。

って理解であってるかな・・・？

### berkshelfを入れる。
[berkshelf](http://berkshelf.com/)は`chef`のレシピを管理してくれるツールだ。
一言で言うと`rubyのbundle`みたいなものだ。

とりあえず、入れてみる。

```sh
$ gem install berkshelf
```

使うためには`Berksfile`を作る必要がある。
とりあえず適当なディレクトリに作ってみる。

```sh
$ mkdir chef-test
$ cd chef-test
$ vi Berksfile
```

使いたいレシピ（クックブック）を記述する。

```ruby
source "https://supermarket.chef.io"

cookbook 'build-essential', '~>2.1.3'
cookbook 'git', '~>4.1.0'
cookbook 'rvm', '~>0.9.2'
cookbook 'mysql', "~> 5.3.6"
```

先ほどまで`レシピ`って書いてたけど、ここに記述しているのは`クックブック`で`クックブック`の中に`レシピ`が入ってる。
一つの`クックブック`に一つしか`レシピ`が入って無い場合もあるけど、複数入っている事もある。
僕みたいな素人は中身を確認してから使ったほうが良いかも・・・。

作成した`Berksfile`の`クックブック`を自分のPCに落とす時は以下のコマンドを使う。

```sh
$ berks
```

と書いているけど、僕はこのコマンドを叩いた事が無い。
多分

```
~/.berkshelf/cookbooks/
```

にクックブックが作成されるのかな？（この辺の思想は多分`gemのbundle install`と同じだと思う。）
実行する場合は以下のように保存するディレクトリを指定する。

```sh
$ berks vendor cookbooks
```

これで実行したディレクトリ内に`cookbooks`ができてその中に`クックブック`ができる。

出来上がった`cookbooks`を見ると、以下のフォルダに`レシピ`が詰まっている。

```sh
cookbooks/***/recipes/
# ***は入れたクックブック名
```

指定した`クックブック`を実行する時に`レシピ`を指定しない場合は`default.rb`が実行される。

## 実際に実行してみる
ここまでが前段階です。
次からは実際に構築していきます。

まずは`vagrant`の設定ファイルに`chef`の`レシピ`を追加して構築する手順を書いていく。

### Vagrant+Chefで環境づくり
はまったところもありましたが、以下の手順で概ね問題なく動作しました。

#### Vagrantの設定ファイル作成。
`vagrant`の設定ファイルは後で作ってもOKです。

```sh
$ mkdir rails-test
$ cd rails-test

# 事前にBoxを追加しておく。（上記で行っている人は不要）
$ vagrant box add opscode-centos-6.5 http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.5_chef-provisionerless.box
# vagrantの設定ファイルを作成する。
$ vagrant init opscode-centos-6.5
```

#### クックブックをダウンロード
同フォルダに`Berksfile`ファイルを作成します。

```sh
$ vi Berksfile
```

内容は以下のように記載します。

```ruby
source "https://supermarket.chef.io"

cookbook 'build-essential', '~>2.1.3'
cookbook 'git', '~>4.1.0'
cookbook 'rvm', '~>0.9.2'
cookbook 'mysql', "~> 5.3.6"
```

MySQLは上記の`"~> 5.3.6"`のようにバージョンを記載しないと正しく動作しませんでした。
今回は`5.5`を入れますが、`5.6`でも入ると思います。
設定方法は後述します。

実際に`クックブック`をダウンロードします。

```sh
$ berks vendor cookbooks
```

##### rvmの疑問
`rvm`は`ruby`のバージョン管理だけど、ここで`rbenv`を指定してるサイトがほとんど見当たらなかった。
なんでだろうか？

`rbenv`はユーザー単位で設定ファイルが作成されてしまうから、`Apache`とかと相性が悪いのかな・・・？（僕は昔`rbenv`でサーバー構築をして、どはまりをして`ruby`を入れ直した経験がある・・・。）

確か`rvm`は`ruby`の実行パスを書き換えるだけのシンプルな実装だったと思うから、そっちのほうが相性が良いのかな？？

#### Vagrantの初期設定
`vagrant`は`chef`と連携できるので、`Vagrant`ファイル内に`chef`のレシピを書き込みます。

ただ、その前に幾つか設定する必要があるのでその説明を記載します。

```sh
$ vi Vagrant
```

ファイル内を以下のように記載します。

```ruby
# Vagrantの設定です。`(2)`の部分はバージョンを指定します。
# 2015年9月現在では2を設定しておけば問題ありません。
Vagrant.configure(2) do |config|
  # 使用しているboxを記載します。（Vagrantファイル作成時に自動的に作成されていると覆います。）
  config.vm.box = "opscode-centos-6.5"

  # 後述
  config.vm.network "forwarded_port", guest: 3000, host: 4000
  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024"]
  end

  # vagrant-omnibusに記載した通りで、対象のサーバーで動かすchefのバージョンです。
  config.omnibus.chef_version = :latest
end
```

##### private_network
`vagrant`を起動した後にWebサーバーを立ち上げても外部からはアクセスできません。
アクセスするために`IPアドレス`を振る必要があり、ここで指定した`IPアドレス`でアクセスできるようになります。

ただし、この`IPアドレス`は自分PCからのみ有効なので自分以外の人にアクセスさせたい場合は以下の方法をとります。

※通常はこの設定のみで十分なはず。

##### forwarded_port
こちらの設定をしておく事によって、自分のPCにアクセスがあったポート番号を`vagrant`へ飛ばします。
例えば上記の設定の場合は

```
http://localhost:4000/
```

へアクセスした場合は`vagrant`内部の`3000番ポート`へフォワードされます。
これを使えば他のPCから`vagrant`へアクセスさせることができます。

なお、`vagrant`を外に公開する方法もありますがここでは言及しません。（僕が使わないため。ってか、大抵の人は使わないと思います・・・。）

##### virtualbox
各`virtualbox`の設定を記載できます。
[こちら](http://toshihirock.blogspot.jp/2014/04/vagrantvirtualboxvmvagrantfile.html)の説明がわかりやすかと思います。

また、詳細な設定方法は[こちら](http://vboxmania.net/content/vboxmanage-modifyvm%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89)が参考になりました。

#### Vagrantへchefを設定する
続いて`chef`の`レシピ`を記載します。

```ruby
  # 上記に記載の通り。
  config.omnibus.chef_version = :latest

  # 以下を追加します。
  config.vm.provision :chef_solo do |chef|
    # 先ほどBerksfileでダウンロードしたクックブックを指定します。
    chef.cookbooks_path = "./cookbooks"
    # chef.add_recipeとの差がわからない・・・
    chef.run_list = [
    ]
    chef.add_recipe 'build-essential'
    chef.add_recipe 'git'
    chef.add_recipe 'mysql::server'
    chef.add_recipe 'mysql::client'
    chef.add_recipe 'rvm::system'

    chef.json = {
        rvm: {
            user: "vagrant",
            default_ruby: "ruby-2.2",
            rubies: ["ruby-2.2" ]
        },
        mysql: {
            service_name:"default",
            version: "5.5",
            server_root_password: 'root'
        }
    }
  do
```

##### chef.run_list
こちらは`chef`で実行したい`レシピ`を記載します。

```ruby
    chef.run_list = [
    	'build-essential',
    	'git',
    	...
    ]
```
と書けば動くはずです。（僕は使ってません。）

##### chef.add_recipe
`chef.run_list`との差がわかりませんが、`vagrant`ではこちらの記述方法が一般的のようです。

```ruby
chef.add_recipe 'git'
```

と記載した場合は`cookbooks/git/recipes/default.rb`のレシピが実行されます。

MySQLには`default`の`レシピ`がないため

```ruby
chef.add_recipe 'mysql::server'
chef.add_recipe 'mysql::client'
```

のように記載して、サーバーとクライアントのプログラムを動かしてます。
以下の`レシピ`が実行されます。

```
cookbooks/mysql/recipes/server.rb
cookbooks/mysql/recipes/client.rb
```

##### chef.json
こちらは`chef`で環境を設定する際に使用する設定内容です。
あまりわかってませんが、初めの`rvm`や`mysql`で各クックブックに対しての設定内容を書き込めます。

MySQLの`server_root_password`を書き忘れると、デフォルトの`ilikerandompasswords`とかになってしまいます。

また、ここでMySQLのバージョンを指定できます。
`version: 5.6`にすれば`5.6`が入ると思います。（未検証）

##### config.vm.provision
最後になりましたが、これは実行したいプログラムを指定します。
例えば、シェルを実行したい場合は以下のようになります。

```ruby
config.vm.provision "shell", inline: "echo hello world"
```

Hello worldが出力されます。

#### Vagrantを起動する
さて、いよいよ今まで作った設定で仮想OSを作成して起動します。

```sh
$ vagrant up
```

これでしばらく待ってれば仮想OSが立ち上がります。

```sh
$ vagrant ssh
$ ruby -v
$ mysql -u root -p
```

等を行って、設定通りに作成されているか確認してください。
これで完了です。

##### 設定ファイルを適用させる。
`vagrant`作成に設定ファイルを変更させたい場合は以下のように行います。（僕はあまりやらないけど・・・）

```sh
$ vagrant provision
```

### Vagrantもしくはサーバーへchef-soloでレシピを流し込む環境づくり
こちらも書こうと思ったのですが、量が多くなったので別途記事を書きます！

初心者なので、ご指摘などがありましたらコメントまでお願いいたします。