Vagrantfileチートシート&コマンド集

# 概要
`Vagrantfile`(version=2)の記述方法とvagrantコマンドに関する自分用のまとめ

# Vagrantfileとは
- プロジェクトに必要なマシン種別、構成、およびプロビジョニングに関する定義を記述するファイル
- 文法は`Ruby`に従うものの、シンプルな変数割当のみのため`Ruby`を知っている必要はない
- `vagrant`コマンドを実行した際、実行時ディレクトリを起点として親ディレクトリに`Vagrantfile`がないかを順にチェックしていく

(以上、公式簡易訳)

# ホストとゲスト

- ホストマシン:`vagrant`コマンドを実行する側のマシンのこと
- ゲストマシン:`vagrant`コマンドによって、作成された仮想マシンのこと

# ファイルの記述
## バージョン `configure`

- どの`Vagrantfile`でも記述

```ruby:Vagrantfile
Vagrant.configure("2") do |config|
 # 各種定義
end
```

## マシン構成 `vm`

赤字がよく設定するだろうもの

### <font color=orangered>box</font>

- 型：`string`
- ベース環境パッケージを指定
- [Vagrant Cloud](https://app.vagrantup.com/boxes/search)に登録されているものから選択

```ruby:example
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"         # centos
 #config.vm.box = "ubuntu/trusty64"  # ubuntu  
end
```

### <font color=orangered>hostname</font>
ゲストマシンのホスト名を設定

- 型：`string`
- 文字、数字、ハイフン、ドットのみ指定可能
- ゲストの`/etc/hosts`ファイルに書き込まれる

```ruby:example
Vagrant.configure(2) do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.hostname = "machine-A"  # machine-Aというホスト名を設定
end
```

### box_version
`box`として利用するパッケージの指定

- 型：`string`、デフォルト：`>=0`
- 不等号(`>=`)を用いることができる

### post_up_message
`vagrant up`完了時に表示するメッセージ

- 型：`string`
- 利用者に、開発環境コンポーネントへのアクセス方法を通知するなどの用途で使用

### graceful_halt_timeout
`vagrant halt`が実行されてからゲストマシンを正常終了させるまでの待機秒数

- 型：`integer`、デフォルト：`60`

### <font color=orangered>synced_folder</font>
[フォルダ共有](#フォルダ共有-vmsynced_folder)　を参照

### <font color=orangered>network</font>
[ネットワーク設定](#ネットワーク設定-vmnetwork)　を参照

### <font color=orangered>provider</font>
[プロバイダ](#プロバイダ-vmprovider)　を参照

### <font color=orangered>provision</font>
[プロビジョニング](#プロビジョニング-vmprovision)　を参照

## プロバイダ `vm.provider`
仮想マシンを作成するソフトウェアの設定

- `VMWare`、`Docker`、`Hyper-V`などを指定可能である。本記事ではデフォルトの設定である**`VirtualBox`に焦点を絞って**記述
- 各種設定は`vm.provider`ブロック内に記述

```ruby
config.vm.provider "{PROVIDER_NAME}" do |v|
  ### このブロックに設定を記述
end
```

### 基本設定
VMの名称、CPU数、メモリーの設定は、それぞれ`name`、`cpus`、`memory`にて可能

```ruby
config.vm.provider "virtualbox" do |v|
  v.name = "virtualMachineA"
  v.cpus = 1
  v.memory = 512   # 単位はMB
end
```

また、ゲストマシンはデフォルトでヘッドレスモードでの起動となるため、GUIモードで起動したい場合は`gui`を設定する必要がある

```ruby
config.vm.provider "virtualbox" do |v|
  vbox.gui = true
end
```

### 詳細設定
より細かい設定は、`VBoxManage`というユーティリティを介することで設定が可能
基本構文は以下

```ruby
config.vm.provider "virtualbox" do |v|
  v.customize ["{COMMAND}", :id, "{KEY}", "{VALUE}"]
end
```

設定可能なオプションは[こちら](https://www.virtualbox.org/manual/ch08.html#vboxmanage-cmd-overview)を参照
一例として、ホスト-ゲスト間のクリップボード共有を双方向にONにしたい場合の設定は以下となる

```ruby
config.vm.provider "virtualbox" do |v|
  v.customize ["modifyvm", :id, "--clipboard-mode", "bidirectional"]
end
```

## プロビジョニング `vm.provision`
ソフトウェア関連のインストールを行う場合に設定

- `Ansible`、`Chef`などのツールが利用可能
- シェルスクリプトでの記述も可能
- ホストからゲストへのファイル(ディレクトリ)のアップロードを行うことができる
- 初回実行の`vagrant up`または`--provision`オプションが指定された場合に実行される
- オプション形式、ブロック形式のいずれかで記述することができる(下記)

```ruby
# オプション形式
config.vm.provision "{PROVISIONER_NAME}", OPTIONS...

# ブロック形式
config.vm.provision "provisioner" "{PROVISIONER_NAME}" do |p|
  # オプション設定
end
```

### シェルスクリプト形式 (`provisioner name`="shell")
大きく以下の２種類の方法に分かれる

- シェルスクリプトファイルを別で用意し、`path`にて、このファイルを参照する

```ruby
config.vm.provision "shell", path: "script.sh"
```

- `Vagrantfile`内にスクリプトを埋め込み、`inline`にて実行する


```ruby
# Vagrantfileの冒頭にスクリプトを記述
$install_package = <<-'SCRIPT'
sudo apt-get update
sudo apt-get -y upgrade                                                                                                                                            
SCRIPT

Vagrant.configure("2") do |config|
  ## 中略
  # inlineオプションで冒頭のスクリプトを指定
  config.vm.provision "shell", inline: $install_package
end
```

### Ansibleの利用 (`provisioner name`="ansible" or "ansible_local")
大きく２種類に分かれる

- `ansible`: ホストマシンにて`ansible-playbook`を実行し、ゲストマシンをセットアップする
  - ホストマシンに`ansible`を実行するためのパッケージインストールが必要
- `ansible_local`: ゲストマシンにて`ansible-playbook`を直接実行
  - ホストマシンには`ansible`を実行するためのパッケージインストール不要
  - ゲストマシンで実行するため、ゲストマシンにパッケージインストールが必要
  - 必要なパッケージは`Vagrant`がよしなにインストールしてくれるよう

詳細は`Ansible`を理解してから追記 


## フォルダ共有 `vm.synced_folder`
ホストマシンとゲストマシン間でフォルダを共有したい場合に設定

- 第１引数：ホスト側の共有ディレクトリ
  - 絶対パス、相対パスのいずれも使用可能、相対パスのルートはプロジェクトのルート
- 第２引数：ゲストマシン側の共有先ディレクトリ
  - 絶対パスで記載する必要あり

```ruby
config.vm.synced_folder "src/", "/usr/service/web"
```

### オプション
#### type
同期方法の指定

- 型：`string`、デフォルト:`nfs`
- `nfs`、`rsync`、`smb`が選択可能
- 特別な理由がない限り、`nfs`(デフォルトなので指定なし)で問題ない
- `nfs`の場合、`nfs_export`、`nfs_version`、`nfs_udp`の３オプションが使用可能

```ruby
config.vm.synced_folder ".", "/vagrant",
  type: "nfs",
  nfs_version: 4,   # 指定しない場合のデフォルトは3
  nfs_udp: false    # デフォルトはtrue、ただし、versionが４の場合はfalseにする必要あり
```

#### mount_options
マウントするときのオプション一覧、下表または[ここ](https://www.virtualbox.org/svn/vbox/trunk/src/VBox/Additions/linux/sharedfolders/mount.vboxsf.c)を参照

|オプション|概要|例|
|:---|:---|:---|
|rw|読み書き可能な状態でマウント|rw
|<font color=orangered>ro</font>|読み取り専用の状態でマウント|ro
|<font color=orangered>dmode</font>|ディレクトリ権限を設定|dmode=700
|<font color=orangered>fmode</font>|ファイル権限を設定|fmode=755
|gid|所有者グループをIDで指定<br>groupオプションよりこちらが優先される|gid=1234
|uid|所有者ユーザーをIDで指定<br>ownerオプションよりこちらが優先される|uid=1234

```ruby
config.vm.synced_folder ".", "/vagrant",
  owner: "vagrant",
  group: "vagrant",
  mount_options: ["dmode=700", "fmode=700"]
```

#### group
同期したフォルダの所有者グループを設定
- 型：`string`、デフォルト:SSHユーザー

#### owner
同期したフォルダの所有者を設定
- 型：`string`、デフォルト:SSHユーザー

#### create
`true`の場合、第1引数で指定したホスト側のパスが存在しない場合に作成

- 型：`boolean`、デフォルト:`false`
- 基本的にはホスト側にディレクトリを予め作成しておき、本オプションは`false`とすべき

## ネットワーク設定 `vm.network`
ゲストマシンのネットワーク接続設定

- 指定できる種別は3つで、`forwarded_port`、`private_network`、`public_network`(`public_network`は使う意図がないため、本記事では省略)
- 複数設定したい場合は、`vm.network`自体を複数記載する必要がある

```ruby
config.vm.network :forwarded_port, guest: 5000, host: 5000
config.vm.network :private_network, ip: "172.16.200.101"
```

### ポートフォワード
ホストマシン、ゲストマシンのポート番号をそれぞれ指定して、ポートフォワーディングする場合に設定
以下のオプションが指定可能

|オプション|概要|例|
|:---|:---|:---|
|<font color=orangered>guest</font>|ゲスト側のポート番号、指定必須|guest: 8080
|<font color=orangered>host</font>|ゲストポートへアクセスするためのホスト側のポート番号、指定必須|host: 80
|id|ポートフォワーディングの設定名称|id: "forwarding"
|protocol|使用するプロトコル<br>`tcp`または`udp`が指定可能、デフォルトは`tcp`|protocol: "tcp"

```ruby
# ゲストの5000番<-ホストの8080番ポート のアクセス設定、設定の名称=http
config.vm.network :forwarded_port, guest: 5000, host: 8080, id: "http"
```

### プライベートネットワーク
公開されていないネットワーク内の設定
`DHCP`、固定IPアドレス指定、`IPv6`のいずれかが使用可能

```ruby
# DHCP方式
config.vm.network "private_network", type: "dhcp"
# 固定IPアドレス方式
config.vm.network "private_network", ip: "192.168.50.4"
# IPv6方式(一例)
config.vm.network "private_network",
  ip: "fde4:8dba:82e1::c4",
  netmask: "96"
```


## 1ファイルで複数マシンの定義 (`vm.define`)

- `vm.define`句でブロックを新たに作成し、このブロック内にそれぞれの定義を記述

```ruby
Vagrant.configure("2") do |config|
  # １台目のマシン
  config.vm.define "web-machine" do |web|
    web.vm.box = "apache"
    web.vm.hostname = "web-server"
  end

  # ２台目のマシン
  config.vm.define "db-machine" do |db|
    db.vm.box = "mysql"
  end

  # ・・・以下同様の記述で台数を増やすことができる
end
```

## コマンド集

### `vagrant up`
  - ゲストマシンを立ち上げる
  - 初回実行時には`provision`も行われる
  - プロビジョニングも行いつつ立ち上げる際は`--provision`または`--provision-with {TARGET}`のオプションを利用

### `vagrant provision`
- プロビジョニングを実行
- ゲストマシンが立ち上がっている状態でも実行は可能

### `vagrant reload`
- 単純な再起動、またはVagrantfileの修正を反映させたい時に使用
- `box`そのものを変更したい場合は`destroy`->`up`とする必要があるよう

### `vagrant halt`
  - ゲストマシンの終了

### `vagrant destroy`
  - ゲストマシンを破棄
  - 次回の`up`時はマシン構築から行うことになる

### `vagrant ssh {TARGET}`
- {TARGET}へsshで接続を行う
- Vagrantfileでssh設定を行っていなくても使用できる(よしなに設定してくれる、プライベートネットワークであれば問題ない)

### `vagrant status`
  - ゲストマシンの現在状況を表示

```bash
Current machine states:

↓defineで設定した名前　　　　　↓現状     ↓provider
node1                     poweroff (virtualbox)
master                    poweroff (virtualbox)
```

### `vagrant validate`
- Vagrantfileの記述が正しいかをチェック
- CIあたりで使うのがよさそう

# Reference
- [Vagrant Docs](https://www.vagrantup.com/docs/vagrantfile/)