Vagrant 1.8 + CentOS 7 + VirtualBox 5 + Ruby on Rails + Mysqlで開発環境構築

※追記 2016/2/27
Mysqlの設定を追記しました。
Rubyのバージョンを最新の2.3.0にしました。

#概要
「実践 Vagrant」の書籍を読んで勉強したので自分用のメモを含めてまとめる。
ただ書籍とは違って、バージョンは最新版を使うようにしました。  

Vagrant1.8.1
Virtualbox 5.0.14
CentOS 7.1
Rails 4.2.5.1
Ruby 2.3.0
Mysql Ver 15.1 Distrib 5.5.44-MariaDB, for Linux (x86_64) using readline 5.1
Mac OS X El capitan
の最新バージョンで開発環境を構築しました。

初心者の方にもわかりやすいようにVagrantの説明から書いてみました。
参考になれば幸いです。

#Vagrantとは？
VagrantはRubyで作られている仮想環境を構築できる超便利なソフトウェアです。
Mac、Windows、LinuxのどのOSでもコマンド一発で構築できてしまいます。
最初Vagrantは、OSを追加でインストールして動かすことができるVirtualBoxを対象にしていました。
Vagrant1.1より前はVirtualBoxが必須で、必ずセットでインストールする必要がありましたが、1.1以降は完全に切り離されました。
VMWareやAWSのEC2などのサーバー環境でも利用できるようになりました。
Vagrantはこれらの仮想環境やサーバ環境をラップして(包み込んで)、さらに便利に使えるようにするものです。
#なぜVagrantを使うのか？
Vagrantを使わなくても開発環境は作れます。
なぜVagrantを使うのでしょうか？
これを理解するにはVagrant登場前の開発環境にあった問題を知ることが重要です。 
Vagrant登場前は開発マシンに必要なすべてのソフトウェア(Apache,Mysqlなど)を直接インストールすることが良いとされていました。
WebアプリケーションがほとんどPHPとMysqlでできていた時代は良かったかもしれません。
Apacheの仮想ソフトとMysqlでのデータベースの分離が容易だったので、複数のプロジェクトも扱うことができました。
だた現在のWebアプリケーションはかなり多くの部品から成り立っています。
言語はPHPだけでなくRubyやPython。
データベースはMysql、Postgresql、Oracle、Redis。
ミドルウェアはApache、Nginx、Unicorn、thin....
などなど環境にもたくさんの選択肢があり、全体としてかなり複雑です。
これらの技術の様々な組み合わせをすべて適切に設定して、ローカルにインストールされている状態を保つことはもはや不可能といっても過言ではないでしょう。
これが初心者が開発環境の構築がつまづく理由の1つでもあると思います。

#ローカルで開発する上での問題点
１、Windowsではコンパイルや実行ができないものが多い。  
 OSによっては最初から入っていないソフトウェアがあり、場合によってはインストールが難しいものもある。

２、開発環境では動くのに実働環境では動かない可能性が多々ある。
 開発環境と実働環境が全く同じというのが一番の理想です。 
 しかし開発はMacで行って実働環境ではLinuxを使うことが多いと思います。
 実働環境に最も近くなるように開発環境を設定することはインストールすること以上に難しいでしょう。
「僕のPCでは動くんだけど」「ローカルでは動くけど実働環境で動かない」というトラブルによく遭遇することになる。

３、複数のプロジェクトを扱うことが困難
プロジェクトごとでソフトウェアの設定が全く一緒ということはほとんどない。  
依存関係がうまく扱えていない状態になり、不必要なサービスがたくさん動いている状態になる。
こうした環境はあっという間にカオスになる。

４、新しいメンバーと環境を揃えることが困難
各開発者が自分の責任で環境を構築するので、新しいメンバーの環境と差異が生まれる。
新しいメンバーの立ち上げに多くの時間がかかることになる。
全員が違うOSを使うということが難しい。
まずMacを買わなければ...という状況も多々ある。

#Vagrantが解決している問題点
Vagrantはこれらの問題に対して有効です。

１、シェルスクリプトや設定管理ソフトウェアを使って環境構築を自動化してくれるので早い。

２、各プロジェクトはそれぞれの仮想環境で実行するので、他のプロジェクトに影響がない。

３、実働環境と限りなく同じ環境で開発ができるので、実働環境では動かないといったこともほとんどなくなる。

４、仮想マシンのイメージを共有できることから、OSが違う他の人も全く同じ環境で開発ができるようになる。

５、コマンド一発で構築できることから、新しいメンバーの立ち上げにも時間を取られることがない。

#開発環境の準備
Vagrantのメリットが分かったところで実際にインストールして使ってみます。
今回は無料のVirtualBoxをセットで使用します。
Vagrant、VirtualBoxはどちらの順番でインストールしても大丈夫です。
公式ではVagrantのサポート外のOSもサポートしているVirtualBoxを先にインストールすることが推奨されているようなのでVirtualBoxからインストールします。

VirtualBoxのインストール
https://www.virtualbox.org/

ダウンロードしたらdmgをクリックして画面通りに進めばOK。
アプリケーションにVirtualBoxが追加されていればインストール完了。

Vagrantインストール
https://www.vagrantup.com/

ダウンロードしたらdmgをクリックして画面通りに進めばOK。
Vagrantは画面上からは見えないので、インストールが終わったらターミナルを開いて確認します。

```
$ vagrant -v 
1.8.1
```
ちゃんと入りました！
VirtualBoxのバージョン5以上は最新のVagrantを使わないと対応していないので注意。
ただ対応していない古いバージョンをインストールしてもターミナルに「対応してないバージョンだよ！」とエラーメッセージを出してくれるので大丈夫。
親切ですね。

#よくあるエラー
Vagrantがインストールされる時に自動的に環境変数に

```
/usr/bin/vagrant
```

が追加されるのでどのディレクトリでも使えるようになりますが、場合によっては失敗することがあります。
その場合は

```
$ which vagrant
```

と打つことによって、/usr/bin/vagrantにインストールされているか確認することができます。
何も表示されなかった場合は

```
$ export PATH=/Applications/Vagrant/bin:$PATH
```

と打って、パスを追加することで直ると思います。

正しいパスが設定されているにもかかわらず問題がある場合は以前にRubyGemでVagrantをインストールしていないか確認してください。
Vagrantは初期はRubyのライブラリとしてGemで提供されていたからです。

```
$ gem uninstall vagrant
```
で削除できます。

他のエラーであれば検索して解決するようにしてください。

#Vagrantの立ち上げ

Vagrantの専用のディレクトリを作成する。
専用のディレクトリを作った方がわかりやすくて管理しやすいでしょう。

```
$ mkdir Vagrant
$ cd Vagrant
$ mkdir centos7
$ cd centos7
```

Vagrantを起動させるためには２つのものが必要です。

１、Vagrantfile(設定とか書くもの)
２、Box(OSのイメージ的なもの)

の２つです。

```
$ vagrant init bento/centos-7.1
```

このコマンドの説明をします。
まず
```
$ vagrant init
```

でVagrantfileを作ってくれます。
Boxはinitとは別にbox addのコマンドを使って後からでも追加できます。
initの後に同時にBox名を指定するとVagrantfileにBoxの種類も追加してくれたり手間が省けますので簡単です。
Boxは種類が多くどれを使った方がいいかわからないと思います。
bento/がついたboxはChef社で提供されている信用できるBoxなので安心して使えます。
わからなかったら同じやつを使ってください。

次に同じディレクトリにVagrantfileが作られているので

```
$ vi Vagrantfile
```

でファイルを編集してネットワークの設定を変えます。

```
Vagrant.configure(2) do |config|
 # The most common configuration options are documented and commented below.
 # For a complete reference, please see the online documentation at
 # https://docs.vagrantup.com.
 # Every Vagrant development environment requires a box. You can search for
 # boxes at https://atlas.hashicorp.com/search.
 config.vm.box = "bento/centos-7.1"
 # Disable automatic box update checking. If you disable this, then
 # boxes will only be checked for updates when the user runs
 # `vagrant box outdated`. This is not recommended.
 # config.vm.box_check_update = false
 
 # Create a forwarded port mapping which allows access to a specific port
 # within the machine from a port on the host machine. In the example below,
 # accessing "localhost:8080" will access port 80 on the guest machine.
 
 //ここの#をはずして書き換える
 config.vm.network "forwarded_port", guest: 3000, host: 3000 

 # Create a private network, which allows host-only access to the machine
 # using a specific IP.
 # config.vm.network "private_network", ip: "192.168.33.10"

 # Create a public network, which generally matched to bridged network.
 # Bridged networks make the machine appear as another physical device on
 # your network.
 # config.vm.network "public_network"
```

編集が終わったら「:」と「wq」を打って保存する。
そしたら次は

```
$ vagrant up
```

このコマンド一発で仮想環境を作ってくれる。
超簡単ですね！


#Vagrant道
VagrantはどのOSでも操作が決まっています。

```
立ち上げ
$ vagrant up

仮想マシンへ入る
$ vagrant ssh

スリープ
$ vagrant suspend

停止
$ vagrant halt

仮想環境を消去
$ vagrant destroy
```

その日の開発が終わったら「停止」、そして朝来たら「立ち上げ」みたいな感じで使うことができます。
新しく作り直す際もコマンド一発で破棄して、コマンド一発で作り直せるので非常に簡単です。
このサイクルは覚えるようにしましょう。

#vagrant up時に行っていること
１０個のことを行っています。
１から順番に行います。

１、Boxのベースイメージからマシンを作成

２、ネットワークデバイスにMACアドレスを設定

３、仮想マシンの表示名を設定(デフォルトはディレクトリ名とタイムスタンプ)

４、ポートフォワーディングの設定

５、仮想マシンに必要な共有フォルダの設定(VirtualBoxが共有フォルダのメタデータを必要とするため)

６、 ネットワークインターフェースの設定のし直し

７、 後にSSHなどで使うため、フォワードされたポートのメタデータを作成

８、 マシンを起動する

９、 用意されたメタデータを元に仮想マシンのOSに合わせてネットワークを適切に設定する

１０、共有フォルダをマウントし、仮想マシンとローカルでデータを共有出来るようにする

#Vagrantの仮想環境でバージョン管理する際の注意点
vagrant up時に「./vagrant」という名前のディレクトリが作成されますが、これにはID、ロック、設定などの情報が保存されています。
これをバージョン管理に含めてコミットしないようにしましょう。
仮想マシンが迷子になったり、環境が壊れる可能性があります。

#仮想マシンの状態を把握するには
Vagrantはターミナルなどからコマンドで操作するので、今の状態がわかりづらくなることもよくあります。
その場合は以下のコマンドで知ることができます。

```
$ vagrant status

Current machine states:

default                   running (virtualbox)

The VM is running. To stop this VM, you can run `vagrant halt` to
shut it down forcefully, or you can run `vagrant suspend` to simply
suspend the virtual machine. In either case, to restart it again,
simply run `vagrant up`.
```

今は動いている状態ですね！

#共有ファイルシステム
ローカルと仮想マシンの間でファイルを同期できるようにシステムが用意されています。
これの設定を行ってローカルのエディタで編集してそのまま仮想マシンに反映されるように設定を行っていきます。
使うエディタはSublime Text3を使います。

###デフォルトの共有ディレクトリ
デフォルトではローカルのVagrantfileがあるディレクトリが仮想マシン上の/vagrantディレクトリと共有するようになっています。

試しに確認してみましょう。

```
$ vagrant ssh  
$ ls /vagrant
Vagrantfile
```
ここにあるVagrantfileは今ローカルにあるVagrantfileと全く同じものです。
仮想環境を破棄したりしても共有フォルダの中のファイルがなくなる事はありません。

デフォルトでも構いませんが、自分で設定を変えることもできます。

```
一旦ローカルへ戻って
$ exit

Vagranfileを40行目あたりを編集する
$ vi Vagrantfile
 # Share an additional folder to the guest VM. The first argument is
 # the path on the host to the actual folder. The second argument is
 # the path on the guest to mount the folder. And the optional third
 # argument is a set of non-required options.

 ここをコメントアウトして名前を変える
 config.vm.synced_folder "../centos7", "/rails_projects"
```

設定の方法はすごく簡単です。
config.vm.synced_folderに対して２つの値を渡してあげます。
１つ目は「ローカル上の共有したいフォルダ」
２つ目は「ホスト上の共有フォルダの場所」
です。

```
config.vm.synced_folder "../centos7", "/rails_projects"
```

試しに現在cetnos7のディレクトリにいるのでここを共有してみます。
相対パスで指定します。
デフォルトで「../data」とあるので「../centos7」と変更しました。
２つ目は適当に指定しました。
その名前のディレクトリが仮想マシン上に存在しなくても自動的に作ってくれます。

この設定を反映させるためには仮想マシン側で足りないものがあるのでそちらを先にインストールします。
参考記事
http://qiita.com/DQNEO/items/2375dd8002a831268cb5

```
ローカル
$ vagrant ssh

仮想マシン
$ sudo yum install kernel-devel
$ sudo yum install gcc make
$ exit

ローカル
$ vagrant plugin install vagrant-vbguest
$ vagrant vbguest

設定を反映させるコマンド
$ vagrant reload
```

これでできました。
ファイルが共有できているか確認します。

```
$ vagrant ssh
$ cd /rails_projects/
$ ls
Vagrantfile
```

うまくできたようです！
デフォルトの/vagrantもそのまま使えます。
初心者なら変に設定をいじらずデフォルトを使えばいいでしょう。
この後の説明ではデフォルトの/vagrantディレクトリを使います。

#Ruby、Rails、その他のインストール
マシンの作成はほぼ完了したので実際に開発ができるように必要なツールをインストールしていきます。

```
$ vagrant ssh
$ sudo yum update
$ sudo yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel make bzip2 autoconf automake libtool bison git

Gitが入ったか確認
$ git --version
git version 2.2.2

rbenvをいれる
$ git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bashrc
$ exec $SHELL -l
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ cd ~/.rbenv/plugins/ruby-build
$ sudo ./install.sh
以下のコマンドが使えればOK。
$ rbenv install -l

Rubyのインストール
$ rbenv install 2.3.0; rbenv rehash
$ rbenv global 2.3.0


ちゃんと入ったか確認
$ ruby -v
ruby 2.2.2
$ which gem
~/.rbenv/shims/gem
$ which ruby
~/.rbenv/shims/ruby


bundlerをいれてRailsのインストールする
$ gem install bundler --no-rdoc --no-ri
Successfully installed bundler-1.10.6
$ sudo rbenv rehash
$ gem install rails
$ rbenv rehash
$ rails -v
Rails 4.2.3
$ which rails
~/.rbenv/shims/rails

```
以上でインストールはOK！
さっそくアプリを作ってみるがその前にMysqlを入れておく。
Centos7からMariaDBに変更になっているのでそれに合わせる。

#Mysqlの設定(仮想マシン側)

```
$ sudo yum -y install mariadb-server
```
```
$ sudo vi /etc/my.cnf
[mysqld]
#この一行を追記する
character-set-server=utf8
```

```
データベース起動
$ sudo systemctl start mariadb 

自動起動設定
$ sudo systemctl enable mariadb 

rootやセキュリティの設定を一括で行う
$ sudo mysql_secure_installation

rootで入れるか試す
$ mysql -u root -p  
```
```
railsで使う準備
$ sudo yum install mysql-devel
$ gem install mysql2
```

これで準備ができたのでアプリを作成してみましょう。
例でVagrantという名前のアプリを作成し、DBはMysqlを指定する
rails server時にエラーが出るのでbundle installはスキップして後から行います。

```
共有フォルダへ移動する
$ cd /vagrant
$ rails new Vagrant --skip-bundle -d mysql
$ cd Vagrant
```
ここまで終わったら、ローカルで共有フォルダのcentos7を開くと「Vagrant」アプリがあります。
これをテキストエディタで開きます。
ローカルで編集したものはすぐに仮想マシン上に反映されます。
これでアプリを開発する準備ができました！
動くまであともう少しです！

Gemfileを編集して下記のコメントを外して保存

```ruby:Gemfile
コメントアウト
gem 'therubyracer', platforms: :ruby
```
```
$ bundle install
```

仮想マシン上にデータベースをまだ作成していないので作成する。
まずはローカルのテキストエディタでデータベース情報を編集する。

```ruby:config.database.yml
  default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  ここに「sudo mysql_secure_installation」を打った時に設定したrootのパスワードを設定する
  password: パスワードを追記
  socket: /var/lib/mysql/mysql.sock

```

続いてデータベースの作成

```
$ mysql -u root -p 
MariaDB [(none)]> CREATE DATABASE Vagrant_development;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> CREATE DATABASE Vagrant_test;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> CREATE DATABASE Vagrant_production;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> quit
```

ここまで出来たら動くはず！
rails serverを起動してみましょう！
-bのオプションでホストを指定しないといけません。

```
$ rails s -b 0.0.0.0
=> Booting WEBrick
=> Rails 4.2.5.1 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2016-02-26 18:30:18] INFO  WEBrick 1.3.1
[2016-02-26 18:30:18] INFO  ruby 2.3.0 (2015-12-25) [x86_64-linux]
[2016-02-26 18:30:18] INFO  WEBrick::HTTPServer#start: pid=6551 port=3000
```

無事起動しました！
ブラウザでlocalhost:3000にアクセスしてデフォルト画面が表示されればOK！

#最初の画面の作成
試しにちゃんと開発ができるか１つページを作ってみます。

##仮想マシン側

```
$ rails g controller Home
Running via Spring preloader in process 6515
      create  app/controllers/home_controller.rb
      invoke  erb
      create    app/views/home
      invoke  test_unit
      create    test/controllers/home_controller_test.rb
      invoke  helper
      create    app/helpers/home_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/home.coffee
      invoke    scss
      create      app/assets/stylesheets/home.scss
```

```rb:contollers/home_contoller.rb
def index
end
```

```html:vies/home/index.html
<h1>First Vagrant App</h1>
```
```rb:config/route.rb
root 'home#index'
```

ここまでできたらもう一度サーバーを起動してlocalhost:3000へアクセス
下記のような画面が表示されればOK！
<img width="771" alt="Screenshot 2016-02-27 03.54.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/55371/1571b560-19da-fecb-4629-3ecaabbe87ff.png">

#まとめ
最新バージョンで情報を調べながら行ったのでデータベースのところで少し時間がかかってしまいました。
情報は英語で調べましたので参考になった記事を貼っておきます。

How To Use MySQL with Your Ruby on Rails Application on CentOS 7
https://www.digitalocean.com/community/tutorials/how-to-use-mysql-with-your-ruby-on-rails-application-on-centos-7

Server World
http://www.server-world.info/en/note?os=CentOS_7&p=mariadb

ただ、うまく動くところまでいけてよかったです。
動きも軽快で、開発しやすそうです。
次はVagrantの高度な設定やEC2との組み合わせなどを試してみたいと思います。