Vagrant入門から実践まで

2019/12/31 更新：記事作成から3年以上が経過しており、リンク先が変わっていたり、なくなっていたりしているため、そのような不適切となったリンクを削除しました。

# Vagrant（ベイグラント）を使うメリットとは？

* 仮想環境をすぐに使える（環境構築の自動化）
* 作成した仮想マシンの環境をファイルとして配布できる（開発環境を共有する）
* プラグインによる機能拡張や、仮想環境のコマンド操作

詳しくはこの辺を見たら良さそうです。
http://dev.classmethod.jp/server-side/virtual-box-vagrant/
http://...（2019/12/31 リンク先が変わっていた為、リンクを削除しました）

では、早速使いましょう。

# VirtualBoxをインストールする
https://www.virtualbox.org/wiki/Downloads
リンク`VirtualBox 4.3.12 for Windows hosts`からダウンロード

![vbox_download.png](https://qiita-image-store.s3.amazonaws.com/0/37334/1b22274d-8ab8-1457-cfc4-c4da73f12dcb.png)

# Vagrantをインストールする

以下のURLにアクセスし、最新版のVagrantを入手＆インストールする。

http://www.vagrantup.com/


![vagrant_top.png](https://qiita-image-store.s3.amazonaws.com/0/37334/f02561bc-c7ab-95ac-02ab-bbef7f5f7407.png)

![download_vagrant.png](https://qiita-image-store.s3.amazonaws.com/0/37334/644554c1-5797-d139-55d6-37cea4feaa0c.png)

# インストールするOSを選択する

以下のようなサイトを使って、インストールしたいOS（というより、boxファイル）を選択する
http://www.vagrantbox.es/
※参考：PuPHPetというサービスもある。 https://puphpet.com/

今回は`CentOS 6.5 x86_64`を選択してみました。

![centos_vagrant.png](https://qiita-image-store.s3.amazonaws.com/0/37334/5a733db1-e47a-84ae-fa27-bf8758128925.png)

これからカレントフォルダにファイルが作成されるため、`cd`コマンドで適当なフォルダ（プロジェクトルートフォルダなど）に移動してから以下のコマンドを実行する

```
$ vagrant box add centos https://github.com/2creatives/vagrant-centos/releases/download/v6.5.1/centos65-x86_64-20131205.box
```

進捗状況が出ています……待つこと数分……

```text
Downloading or copying the box...
Progress: 67% (Rate: 230k/s, Estimated time remaining: 0:08:16))
```

そして…

```text
Successfully added box 'centos' with provider 'virtualbox'!
```

成功。やっと終わった！


次のコマンドを実行して必要なファイル`Vagrantfile`を生成する

```
$ vagrant init centos
```

実行結果

```
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
```

訳してみた↓

```
このディレクトリに`Vagrantfile`ファイルが設置されました。
`vagrant up`コマンドで最初の仮想環境を作成することができます。
Vagrantfile`ファイルのコメントをドキュメントと同様に読んでください。
詳しい使い方は`vagrantup.com`を参照してください。
```

いやぁ、全く芸がないですね！
とりあえず`Vagrantfile`ファイルが生成され、起動の準備が整いました。

ちなみにVagrantfileなしで新規にboxを追加する際は

```
$ vagrant box add {box-name} {box-url}
$ vagrant init {box-name}
```

の代わりに次のコマンドを使ってもOK。

```
$ vagrant init [box-name] [box-url]
```

# インスタンスを起動する vagrant up

コマンド `vagrant up`を実行

実行結果

```
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'centos'...
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for machine to boot. This may take a few minutes...
[default] Machine booted and ready!
[default] Mounting shared folders...
[default] -- /vagrant
```

# 接続する vagrant ssh

コマンド`vagrant ssh`を実行

実行結果

```
`ssh` executable not found in any directories in the %PATH% variable. Is an
SSH client installed? Try installing Cygwin, MinGW or Git, all of which
contain an SSH client. Or use the PuTTY SSH client with the following
authentication information shown below:

Host: 127.0.0.1
Port: 2222
Username: vagrant
Private key: C:/Users/UserName/.vagrant.d/insecure_private_key
```

Windowsなので、そのままでは繋がらないようです。
SSHクライアントにパスが通してあれば繋がるようなことが書いてありますが、それは後のお楽しみとして。

Windows用SSHクライアントのPuTTyを使って、上の接続先に接続する。

今回は日本語で使うため **PuTTY ごった煮版** を使用してみました。（2019/12/31 リンク先が無くなっている為、リンクを削除しました。おそらく、今後は通常の英語版を使うのが良いでしょう。）

実は、秘密鍵は指定しなくてもいいようです。
ログインはvagrant、パスワードもvagrantで接続。

```
[vagrant@vagrant-centos65 ~]$
```

接続成功！

※`vagrant ssh`コマンドをWindows上で使えるようにするには、[Git for Windows](http://msysgit.github.io/)をインストールすればOK。sshを使うため、`C:\Program Files (x86)\Git\bin`に間違いなくパスが通っているようにして下さい。

# パッケージ化して配布する vagrant package

ここからが本番ですね！
設定した環境をパッケージ化し、チームメンバーへ配布してみます。

コマンド`vagrant package`を実行
※保存するファイル名を指定したい場合は`vagrant package --output my_centos.box`のようにファイル名を付けて実行
※--output では拡張子を省略しても勝手に付けてくれません。.boxを付けるのが無難そうです。

```text
[default] Attempting graceful shutdown of VM...
[default] Clearing any previously set forwarded ports...
[default] Creating temporary directory for export...
[default] Exporting VM...
[default] Compressing package to: c:/path/to/package.box
```

あえて起動中に実行してみましたが、自動的にシャットダウンされるようです。

`package.box`ファイルが生成されました！

![vagrant_package.png](https://qiita-image-store.s3.amazonaws.com/0/37334/b0849668-b306-e05c-a904-851650d17115.png)

後はこの`package.box`ファイルを配布し、同じような手順でインストールします。
(ファイル名は内容のわかるものに変えた方がいいでしょう)

このboxファイルを受け取った人はコマンド`vagrant box add centos package.box`などでboxを追加してもらう。他にもやり方はある。

# Vagrantコマンドの一覧

## ドキュメント
* 日本語ドキュメント - コマンドライン （2019/12/31 リンク先が変わっていた為、リンクを削除しました）
* [英語 Command-Line Interface - Vagrant Documentation](https://docs.vagrantup.com/v2/cli/index.html)

## 準備などに使うコマンド

```test
# 先ほど紹介した{url}のboxファイルを{title}として追加
$ vagrant box add {title} {url}

# 他にもこんなコマンドがある
$ vagrant box list
$ vagrant box remove
$ vagrant box repackage

# boxをパッケージ化（boxファイルとして保存）
$ vagrant package
# いくつかオプションがあるようなので、ヘルプは要チェックかもしれません
$ vagrant package -h
```

## よく使いそうなコマンド

```test
# vagrant box add {title}で追加したbox用のVagrantfileファイルをカレントディレクトリに生成
$ vagrant ini {title}

# カレントディレクトリのVagrantfileを読み込んで、仮想マシンを起動
$ vagrant up

# 仮想マシンを停止（シャットダウン）
$ vagrant halt

# vagrant haltしてからvagrant up　※Vagrantfileを読み直すので、再起動とは少し違う
$ vagrant reload

# 仮想マシンを保留状態にする　※シャットダウンせずに状態を保存して電源を切る
$ vagrant suspend

# vagrant suspendで保留状態にした仮想マシンを起動する
$ vagrant resume

# 行ったすべての変更を削除する　※仮想マシンを丸ごと削除するので、再度vagrant upを行った場合はベースとなったboxから新たに仮想マシンを作り直します。
$ vagrant destroy
```

# Vagrantfileの設定
* [日本語ドキュメント](http://lab.raqda.com/vagrant/vagrantfile/index.html)
* [英語ドキュメント](https://docs.vagrantup.com/v2/vagrantfile/index.html)

※プロビジョニングは同じく設定ですが、次の項目に書きました。少しスクロールしてみてやって下さい。

## 共有ディレクトリの設定
ホストOSの`./src`ディレクトリを共有ディレクトリに設定する。

```rb
config.vm.synced_folder "./src", "/srv/website"
```

複数設定する場合はこんな感じ

```rb
config.vm.synced_folder "./", "/var/www"
config.vm.synced_folder "./", "/bar"
```

詳細な情報
http://docs.vagrantup.com/v2/synced-folders/index.html

* デフォルトでVagrantファイルのある場所がゲストOSの`/vagrant`として共有されている。
* 所有者とグループを指定する例：`config.vm.synced_folder "./src", "/srv/website", owner: "root", group: "root"`
* mount_optionでその他のアクセス権限などの設定を記載する

例：

```rb
# Vagrant v1.1以上の書式
config.vm.synced_folder "./src", "/srv/website",
  owner: "vagrant",
  group: "www-data",
  mount_options: ["dmode=775,fmode=664"]
```

## rsyncでファイルを同期する設定

Vagrant 1.5から、rsyncを使ったファイルの同期を行う事が出来ます。

VagrantをWebアプリケーション開発などで使う場合は、上で説明した共有ディレクトリを使うよりも、rsyncでファイルを同期させる方がメリットが多いと思われます。

```rb
config.vm.synced_folder "./src", "/srv/website", type: "rsync", rsync__exclude: [".git/", ".idea/"]
```

Windows上での実行にはrsync.exeを入手する必要があります。

もう少し詳しい情報は[Vagrant - rsyncでファイルを同期する(Windows)](http://qiita.com/daichi87gi/items/6b33349eedce28db430a)に記載しました。

[リファレンスはこちら(英語)](http://docs.vagrantup.com/v2/synced-folders/rsync.html)

## BoxのURLを設定する
入手したBOXのURLを覚えておきたい、と思うならここにURLを書いてアンコメントすればよさそう。

```rb
# config.vm.box_url = "http://domain.com/path/to/above.box"
```

そうすると、このVagrantfileに対してvagrant upしたときにconfig.vm.boxに該当するboxがない場合、自動的にurlからboxが追加される。
この時、追加されるboxの名前はconfig.vm.boxの設定値が使われる。

Vagrantfileを配布するときにも使えそう。

## メモリを増やす

デフォルトのままではメモリが少なすぎて、プログラムの実行が遅くなったりする場合があります。

Vagrantfileの内容を`provider`で検索すると、設定例がコメントアウトされている箇所を見つけられるかもしれません。
見つけた設定例を参考にして以下のように設定したところ、メインメモリが1024MBに設定されました。

```rb
  config.vm.provider "virtualbox" do |vb|
    # Use VBoxManage to customize the VM. For example to change memory:
    vb.customize ["modifyvm", :id, "--memory", "1024"]
  end
```

![vbox_memory.png](https://qiita-image-store.s3.amazonaws.com/0/37334/4319d1d6-ced0-3d41-f1e2-87d027020e85.png)

ドキュメント
http://docs.vagrantup.com/v2/virtualbox/configuration.html

## Private Network

アクセスするIPを指定できる。

```rb
  # 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"
```

ドキュメント
https://docs.vagrantup.com/v2/networking/private_network.html

## hostnameの設定

```rb
  config.vm.hostname = 'example.localhost'
```

# プロビジョニングの設定
初期設定を行うため、初回起動時にコマンドやシェルスクリプトを実行してみます。
参考：[英語　Provisioning](https://docs.vagrantup.com/v2/getting-started/provisioning.html)

## 簡単なスクリプトを実行してみる
まず、スクリプト`bootstrap.sh`を作成し、Vagrantfileと同じディレクトリに配置します。

```sh:bootstrap.sh
#!/bin/sh

echo 'Hello, Qiita!'
```

初回起動時に作成した`bootstrap.sh`を実行するため、`Vagrantfile`に次の1行を追加します。（`config.vm.box`の次の行あたりでいいでしょう）

```rb
  config.vm.provision :shell, :path => "bootstrap.sh"
```

ついでにコマンドの実行も試してみます。次の1行を追加します。

```rb
  config.vm.provision :shell, :inline => "echo 'Hello, Vagrant!'"
```

`Vagrantfile`全体として、次のような感じになればOK。

```rb:Vagrantfile
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "centos"
  config.vm.provision :shell, :path => "bootstrap.sh"
  config.vm.provision :shell, :inline => "echo 'Hello, Vagrant!'"
end
```

では初回起動を試します。
ここまでの流れで既に仮想マシンを作ってしまっているため、通常の再起動(`vagrant reload`や`vagrant halt`&`vagrant up`)では実行されません。

`vagrant destroy`で全ての変更を削除し、`vagrant up`でベースとなったboxから仮想マシンを作り直します。

※もしくは`vagrant provision`コマンドでプロビジョニングを実行することもできます。

```sh
vagrant destroy
vagrant up
```

次のように表示されたらOK。

```text
[default] Running provisioner: shell...
[default] Running: C:/Users/UserName/AppData/Local/Temp/vagrant-shell20140502-4880-182jwes
Hello, Qiita!
[default] Running provisioner: shell...
[default] Running: inline script
Hello, Vagrant!
```

## 初期設定スクリプトを作ってみました

このCentOSのiptablesの設定、PHP5.5とApacheのインストールをするため、次のような初期化スクリプトを作ってみました。
こんな感じでどうでしょう。

```sh:bootstrap.sh
#!/bin/sh

# Set logfile name
LOGFILE=setuplog.txt

date 2>&1 | tee -a ${LOGFILE}

# Set iptables
cat << EOT >> /etc/sysconfig/iptables
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
COMMIT
EOT

# Install Php5.5 and Apache
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm 2>&1 | tee -a ${LOGFILE}
yum -y install --enablerepo=remi-php55 php php-mbstring 2>&1 | tee -a ${LOGFILE}
echo '<?php phpinfo();' > /var/www/html/info.php

# service
/etc/rc.d/init.d/iptables restart 2>&1 | tee -a ${LOGFILE}
service httpd start 2>&1 | tee -a ${LOGFILE}

# chkconfig
chkconfig iptables on
chkconfig httpd on

date  2>&1 | tee -a ${LOGFILE}
```

# プラグインのインストール

## プラグイン [vagrant-vbox-snapshot](https://github.com/dergachev/vagrant-vbox-snapshot) でスナップショットの作成

コマンドから手軽にスナップショットを撮る機能をインストールしてみます。
※追記：個人的には後述のプラグインSaharaの方がおすすめなので、是非そちらもご覧下さい。

### インストール

次のコマンドを実行

```sh
$ vagrant plugin install vagrant-vbox-snapshot
```

```
Installing the 'vagrant-vbox-snapshot' plugin. This can take a few minutes...
Installed the plugin 'vagrant-vbox-snapshot (0.0.4)'!
```

これはVirtualBoxのUIから操作できることと同じみたい。

### コマンド一覧

```sh
# [vm-name]は書かなくてOK

# 名前を指定してスナップショットを取得
$ vagrant snapshot take [vm-name] <SNAPSHOT_NAME>

# スナップショット一覧を表示
$ vagrant snapshot list [vm-name]

# 最後に取得したスナップショットで復元
$ vagrant snapshot back [vm-name]

# 指定した名前のスナップショットを削除
$ vagrant snapshot delete [vm-name] <SNAPSHOT_NAME>

# 指定した名前のスナップショットで復元
$ vagrant snapshot go [vm-name] <SNAPSHOT_NAME>
```

### 実際に試してみる

#### 準備

`vagrant up` `vagrant ssh`で仮想マシンに接続する。

#### ディレクトリを作ってスナップショットを作成

```sh
# ゲストOSで実行
$ mkdir first_dir

# ホストOSで実行
$ vagrant snapshot take first_dir_maked
```

※ゲストOS : 仮想マシンの事

#### 2つ目のディレクトリを作ってスナップショットを作成

```sh
# ゲストOSで実行
$ mkdir second_dir

# ホストOSで実行
$ vagrant snapshot take second_dir_maked
```

#### 1つ目のスナップショットで復元する

```sh
# ホストOSで実行
$ vagrant halt
$ vagrant snapshot go first_dir_maked

# ゲストOSで実行
$ ls　  # first_dirのみ存在し、second_dirがない状態に戻る
```

## 便利プラグイン　Sahara

Saharaを使うと、rollback、commitの形式で元に戻したりできるようです。
参考ページ：http://dev.classmethod.jp/tool/vagrant-sahar/

実はSaharaの方が使いやすいように思えます。

どちらもやっていることは同じようなものですが…スナップショットの名前を指定しなくていい分、Saharaの方が作業が早くできるかもしれませんね。

# 終わりに

本当はもっと詳しい設定のやり方についても書いていきたいと思いますが、また今後書き足すことにしたいと思います。
最後まで読んで頂きありがとうございました。