Vagrant 1.8の新機能を試す。

# **Vagrant 1.8**

- **[Vagrant 1.8](https://www.hashicorp.com/blog/vagrant-1-8.html)**
- **[CHANGELOG](https://github.com/mitchellh/vagrant/blob/master/CHANGELOG.md)**

先日 **Vagrant1.8** がリリースされました。
1.X 系としては、昨年12月の 1.7 が最新でしたので約1年ぶりのアップデートとなります。

公式ブログでも言及されていますが、やはりメインとなるのは

- **Linked Clone**
- **Snapshot**

という新機能だと思います。
今回はこの2つの新機能を調べつつ、簡単に試してみたいと思います。

なお、環境はWindows環境にて下記のようになっています。VMは2台扱います。

```
C:\vagrant> vagrant -v
Vagrant 1.8.1

C:\vagrant> VBoxManage -v
5.0.12r104815

C:\vagrant> 
Current machine states:

sandbox1                  running (virtualbox)
sandbox2                  running (virtualbox)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.
```

```:vagrantfile
Vagrant.configure(2) do |config|
  config.vm.define "sandbox1" do |node|
        node.vm.box = "centos7.1"
        node.vm.hostname = "sandbox1"
        node.vm.network :private_network, ip: "192.168.100.10"
        node.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2210
  end
  config.vm.define "sandbox2" do |node|
        node.vm.box = "centos7.1"
        node.vm.hostname = "sandbox2"
        node.vm.network :private_network, ip: "192.168.100.20"
        node.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2220
  end
end
```

# **Linked Clone**

## **概要**

公式ブログでは

> Linked cloning is a feature supported by many hypervisors that dramatically speeds up imports by **only creating a differential disk** versus copying the entire disk image of the virtual machine.
> (Linked Cloneは多くのハイパーバイザーでサポートされている、 **差分ディスクのみを作成する** ことでディスク全体のコピーを行う場合に比べてインポートの速度を劇的に改善する機能です)

というように述べられています。
Linked Clone自体はVMware, VirtualBoxなど多くのハイパーバイザーでサポートされている機能ですが、その恩恵をVagrant経由のVM操作でも受けられるようになった、ということのようです。

位置が分かりにくいですが、公式ドキュメントでは下記で言及されています。

- **[Configuration - VirtualBox](https://docs.vagrantup.com/v2/virtualbox/configuration.html)**

> LINKED CLONES
> 
> By default new machines are created by importing the base box. For large boxes this produces a large overhead in > terms of time (the import operation) and space (the new machine contains a copy of the base box's image). Using > linked clones can drastically reduce this overhead.
> 
> Linked clones are based on a master VM, which is generated by importing the base box only once the first time it > is required. For the linked clones only differencing disk images are created where the parent disk image belongs > to the master VM.

## **試してみる**

Linked Clone を使うには vagrantfile の修正が必要です。
最初に示した vagrantfile で `vagrant up` していると、

```
C:\Virtual Machines\vagrant_sandbox1_1452524761615_56212>dir
2016/01/14  01:01     1,583,874,048 centos-vm-disk1.vmdk
2016/01/14  00:41             9,804 vagrant_sandbox1_1452524761615_56212.vbox
2016/01/14  00:41            19,236 vagrant_sandbox1_1452524761615_56212.vbox-prev
               3 個のファイル       1,583,903,088 バイト

C:\Virtual Machines\vagrant_sandbox2_1452524830199_16477>dir
2016/01/14  01:01     1,583,874,048 centos-vm-disk1.vmdk
2016/01/14  00:34             9,804 vagrant_sandbox2_1452524830199_16477.vbox
2016/01/14  00:34             9,861 vagrant_sandbox2_1452524830199_16477.vbox-prev
               3 個のファイル       1,583,893,713 バイト
```

それぞれ約1.5GBずつディスク容量を使っていることがわかります。
容量差分が出ているのは .vbox 側なので、同じBoxファイルを元にしている .vmdk は同じ容量です。

そこで、 Linked Clone を使うべく vagrantfile を以下のように修正します。

```:vagrantfile
Vagrant.configure(2) do |config|
  config.vm.provider "virtualbox" do |v|
    v.linked_clone = true
  end
  config.vm.define "sandbox1" do |node|
        node.vm.box = "centos7.1"
        node.vm.hostname = "sandbox1"
        node.vm.network :private_network, ip: "192.168.100.10"
        node.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2210
  end
  config.vm.define "sandbox2" do |node|
        node.vm.box = "centos7.1"
        node.vm.hostname = "sandbox2"
        node.vm.network :private_network, ip: "192.168.100.20"
        node.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2220
  end
end
```

2-4行目に provider に関する設定を追記しました。
この状態で `vagrant destroy` してから再度 `vagrant up` してみたいと思います。

```
C:\vagrant>vagrant destroy
　(略)
==> sandbox2: Destroying VM and associated drives...
　(略)
==> sandbox1: Destroying VM and associated drives...

C:\vagrant>vagrant up
Bringing machine 'sandbox1' up with 'virtualbox' provider...
Bringing machine 'sandbox2' up with 'virtualbox' provider...
==> sandbox1: Preparing master VM for linked clones...
    sandbox1: This is a one time operation. Once the master VM is prepared,
    sandbox1: it will be used as a base for linked clones, making the creation
    sandbox1: of new VMs take milliseconds on a modern system.
==> sandbox1: Importing base box 'centos7.1'...
　(略)
==> sandbox1: Machine booted and ready!
==> sandbox2: Cloning VM...
　(略)
==> sandbox2: Machine booted and ready!
```

`vagrant up` の最初に `Preparing master VM for linked clones...` というものがあります。これがLinked Cloneで使われることになる親VMということになります。
書いてあるように、これは初回だけの処理であるため、次回以降では発生しません。

さて、再度容量を確認してみましょう。

```
C:\Virtual Machines\vagrant_sandbox1_1452701864512_18192>dir
2016/01/14  01:17             7,970 vagrant_sandbox1_1452701864512_18192.vbox
2016/01/14  01:17             7,971 vagrant_sandbox1_1452701864512_18192.vbox-prev
               2 個のファイル              15,941 バイト

C:\Virtual Machines\vagrant_sandbox2_1452701909144_22261>dir
2016/01/14  01:18             7,970 vagrant_sandbox2_1452701909144_22261.vbox
2016/01/14  01:18             7,971 vagrant_sandbox2_1452701909144_22261.vbox-prev
               2 個のファイル              15,941 バイト

C:\Virtual Machines\centos-vm_1452701834129_67107>dir
2016/01/14  01:17     1,583,611,904 centos-vm-disk1.vmdk
2016/01/14  01:18            15,361 centos-vm_1452701834129_67107.vbox
2016/01/14  01:18            15,355 centos-vm_1452701834129_67107.vbox-prev
               3 個のファイル       1,583,642,620 バイト
```

各VMに対して作られるフォルダから .vmdk ファイルがなくなり、代わりに centos-vm というフォルダが作られました。
これが親VMになっているということですね。
前後を比較すると、各VMで重複していたイメージ本体を集約することができたので約1.5GB分のディスク容量を削減することができました。

# **Snapshot**

## **概要**

VMのSnapshot機能自体は多くの方がご存知かと思いますが、Vagrant 1.8ではVagrantとして公式(※)にSnapshotの利用が可能になりました。
※ 以前よりVirtualBoxであれば **[sahara](https://github.com/jedi4ever/sahara)** プラグインや **[vbox-snapshot](https://github.com/dergachev/vagrant-vbox-snapshot/)** プラグインを使うことで、Snapshot機能の利用自体は可能でした

機能的に真新しいものではないのですが、公式に組み込まれたということで気になる機能です。

## **コマンド**

さて、Snapshot機能について公式ドキュメントを確認してみましょう。

- **[SNAPSHOT](https://docs.vagrantup.com/v2/cli/snapshot.html)**

また、単に `vagrant snapshot` コマンドを実行すると

```
C:\vagrant>vagrant snapshot
Usage: vagrant snapshot <subcommand> [<args>]

Available subcommands:
     delete
     list
     pop
     push
     restore
     save

For help on any individual subcommand run `vagrant snapshot <subcommand> -h`
```

と表示され、メインとなる `snapshot` コマンドの配下に、

- **delete**
- **list**
- **pop**
- **push**
- **restore**
- **save**

があることがわかります。
listとdeleteはそのままですが、save & restore が名前付きスナップショット、 push & pop が名前なしスナップショットの操作にあたります。
それぞれ簡単に確認していきたいと思います。

### **save**

**save** コマンドでは **"名前付き" スナップショットの取得** を行います。

```
> vagrant snapshot save ( [対象マシン] ) [スナップショット名]
```

ではやってみましょう。

```
C:\vagrant> vagrant snapshot save sandboxes1
==> sandbox1: Snapshotting the machine as 'sandboxes1'...
==> sandbox1: Snapshot saved! You can restore the snapshot at any time by
==> sandbox1: using `vagrant snapshot restore`. You can delete it using
==> sandbox1: `vagrant snapshot delete`.
==> sandbox2: Snapshotting the machine as 'sandboxes1'...
==> sandbox2: Snapshot saved! You can restore the snapshot at any time by
==> sandbox2: using `vagrant snapshot restore`. You can delete it using
==> sandbox2: `vagrant snapshot delete`.

C:\vagrant> vagrant snapshot save sandbox1 sandbox1_001
==> sandbox1: Snapshotting the machine as 'sandbox1_001'...
==> sandbox1: Snapshot saved! You can restore the snapshot at any time by
==> sandbox1: using `vagrant snapshot restore`. You can delete it using
==> sandbox1: `vagrant snapshot delete`.
```

1つ目のコマンドでは対象マシンを指定していないため、vagrantfileに記述している全VMについてのスナップショットが取得されています。
一方で、2つ目のコマンドでは対象マシンを `sandbox1` として指定しているため、 `sandbox1` についてのみスナップショットが取得されています。

### **restore**

**restore** コマンドでは save コマンドで取得した **スナップショットのリストア** を行います。

```
> vagrant snapshot restore ( [対象マシン] ) [スナップショット名]
```

さて、先ほど save したスナップショットで早速リストアしましょう。

```
C:\vagrant>vagrant snapshot restore sandboxes1
==> sandbox1: Forcing shutdown of VM...
==> sandbox1: Restoring the snapshot 'sandboxes1'...
　(略)
==> sandbox1: Machine booted and ready!
==> sandbox2: Forcing shutdown of VM...
==> sandbox2: Restoring the snapshot 'sandboxes1'...
　(略)
==> sandbox2: Machine booted and ready!

C:\vagrant>vagrant snapshot restore sandbox1 sandbox1_001
==> sandbox1: Forcing shutdown of VM...
==> sandbox1: Restoring the snapshot 'sandbox1_001'...
　(略)
==> sandbox1: Machine booted and ready!
```

save と対になっているコマンドなので使い方も同様です。
ちなみに、VM名とスナップショット名を逆にすると下記のよう片方は成功、片方は失敗となります。
vagrantfileの内容とスナップショットの中身を考えれば失敗する理由もわかるかと思います。

```
C:\vagrant>vagrant snapshot restore sandbox1_001
==> sandbox1: Forcing shutdown of VM...
==> sandbox1: Restoring the snapshot 'sandbox1_001'...
　(略)
==> sandbox1: Machine booted and ready!
==> sandbox2: Forcing shutdown of VM...
==> sandbox2: Restoring the snapshot 'sandbox1_001'...
　(略)
Stderr: VBoxManage.EXE: error: Could not find a snapshot named 'sandbox1_001'
　(略)

C:\vagrant>vagrant snapshot restore sandbox1 sandboxes1
==> sandbox1: Forcing shutdown of VM...
==> sandbox1: Restoring the snapshot 'sandboxes1'...
　(略)
==> sandbox1: Machine booted and ready!
```

### **push**

**push** コマンドでは **"名前なし" スナップショットの取得** を行います。

```
> vagrant snapshot push ( [対象マシン] )
```

push コマンドではスナップショット名の指定はできません。

```
C:\vagrant>vagrant snapshot push
==> sandbox1: Snapshotting the machine as 'push_1452696816_6988'...
==> sandbox1: Snapshot saved! You can restore the snapshot at any time by
==> sandbox1: using `vagrant snapshot restore`. You can delete it using
==> sandbox1: `vagrant snapshot delete`.
==> sandbox2: Snapshotting the machine as 'push_1452696819_9416'...
==> sandbox2: Snapshot saved! You can restore the snapshot at any time by
==> sandbox2: using `vagrant snapshot restore`. You can delete it using
==> sandbox2: `vagrant snapshot delete`.

C:\vagrant>vagrant snapshot push sandbox1
==> sandbox1: Snapshotting the machine as 'push_1452696878_1741'...
==> sandbox1: Snapshot saved! You can restore the snapshot at any time by
==> sandbox1: using `vagrant snapshot restore`. You can delete it using
==> sandbox1: `vagrant snapshot delete`.
```

基本的な考え方は save と大差ありません。
1つめのコマンドでは対象マシンを指定しないため全VMのスナップショットが、2つ目のコマンドでは指定した sandbox1 のみが push されていることがわかります。

### **pop**

**pop** コマンドでは push コマンドで取得した **スナップショットのリストア** を行います。

```
> vagrant snapshot pop ( [対象マシン] )
```

実行方法は save に対する restore 同様、 push と同様に行うことができます。
ただし、 restore とは異なり、リストアしたスナップショットは pop によって **削除される** という点に注意が必要です。
(ただ、スタックのイメージを持ってpush, popの意味をを捉えていれば特に違和感はないかと思います)

```
C:\vagrant>vagrant snapshot list sandbox1
push_1452699192_9693

C:\vagrant>vagrant snapshot list sandbox2
push_1452699195_6376

C:\vagrant>vagrant snapshot pop
==> sandbox1: Forcing shutdown of VM...
==> sandbox1: Restoring the snapshot 'push_1452699192_9693'...
==> sandbox1: Deleting the snapshot 'push_1452699192_9693'...
==> sandbox1: Snapshot deleted!
　(略)
==> sandbox1: Machine booted and ready!
==> sandbox2: Forcing shutdown of VM...
==> sandbox2: Restoring the snapshot 'push_1452699195_6376'...
==> sandbox2: Deleting the snapshot 'push_1452699195_6376'...
==> sandbox2: Snapshot deleted!
　(略)
==> sandbox2: Machine booted and ready!

F:\vagrant>vagrant snapshot list
==> sandbox1: No snapshots have been taken yet!
　(略)
==> sandbox2: No snapshots have been taken yet!
　(略)
```

### **list & delete**

既に list はしれっと使っていますが、それぞれスナップショットの一覧表示と削除を行います。

```
>vagrant snapshot list ( [ 対象マシン ] )

>vagrant snapshot delete ( [対象マシン] ) [スナップショット名]
```

実行例は下記のようになります。

```
C:\vagrant>vagrant snapshot list sandbox1
sandbox1_001

C:\vagrant>vagrant snapshot delete sandbox1 sandbox1_001
==> sandbox1: Deleting the snapshot 'sandbox1_001'...
==> sandbox1: Snapshot deleted!
```