Vagrant でホストとのマウントに失敗する問題

<!-- Vagrant でホストとのマウントに失敗する問題 -->

# はじめに

VirtualBox をバージョンアップすると Vagrant で仮想マシンを起動するときにホストとのマウントに失敗してしまうことがあります。この問題の原因を調べたところ複数の問題が絡み合っていて解決するのに手間取ったので、解決方法について整理してみたいと思います。

# 原因

原因はホストマシンとのマウントは仮想マシン内に入っている VirtualBox Guest Addition というツールで実現しており、そのバージョンが古くてマウントに失敗するためです。特に VirtualBox のメジャーバージョンが 5 から 6 に上がったタイミングでこの事象に出くわす方が増えてきました。これを解決するためには仮想マシン内の Guest Addition をアップデートする必要があります。

# 試した環境

- ホストマシン macOS
- 仮想マシン bento/ubuntu-16.04
- VirtualBox 6.0.8 r130520
- Vagrant 2.2.5

# 解決策

Guest Addition をアップデートするには `vagrant-vbguest` プラグインを使って行います。その際、下記の条件を満たしていないとアップデートに失敗してしまうことがあるので注意が必要です。

- `vagrant-vbguest` のバージョンが最新であること
- gcc のバージョンが各 Linux ディストリビューションで配布されている最新のものであること
- Linux カーネルのバージョンが最新であること

これらの条件を満たしていなくても VirtualBox のバージョン次第では上手くいったりいかなかったりするため、ハマりやすいのではないかと思います。これを踏まえて、解決方法を説明していきます。

## vagrant-vbguest の導入

### プラグインを入れてない方

下記を実行してインストールします。

```shell:ホストマシンで実行
$ vagrant plugin install vagrant-vbguest
```

### プラグインを導入済みの方

下記を実行してプラグインをアップデートします。

```shell:ホストマシンで実行
$ vagrant plugin update
```

## gcc のバージョンを確認

普段使用している gcc がディストリビューション配布のものより古いものだと Guest Addition のアップデートに失敗することがあります。理由は Guest Addition のソースコードをコンパイルする際に C++ の新しい構文を使っている場合があるためです。gcc のバージョンが古い場合はディストリビューションでデフォルト利用されている gcc にしておく必要があります。

デフォルトで利用されているものより新しい gcc を使っている場合に Guest Addition のアップデートが成功するかどうかについては未確認ですが、もし失敗する場合はデフォルトの gcc を使うようにしたほうが確実かと思います。

gcc のバージョンを変えていない方は下記の手順を行わなくても大丈夫なので、次の項目に進んでください。

Ubuntu 16.04 の場合だと gcc-5 がデフォルトで使用されます。gcc がこれよりも古い（または新しい）場合は `update-alternatives` を使って gcc のバージョンを切り替えてあげます。`update-alternatives` はツールのバージョンを容易に切り替えるためのツールで Ubuntu には最初からインストールされています。

まず gcc の各バージョンを `update-alternatives` の管理下に登録します。下記は gcc-4.8 と gcc-5 を登録する例です。

```shell:仮想マシンで実行
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 4
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 5
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 4
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 5
```

登録が終わればデフォルトで使用する gcc のバージョンを選択します。

```shell:仮想マシンで実行
$ sudo update-alternatives --config gcc
alternative gcc (/usr/bin/gcc を提供) には 2 個の選択肢があります。

  選択肢    パス            優先度  状態
------------------------------------------------------------
* 0            /usr/bin/gcc-5     5         自動モード
  1            /usr/bin/gcc-4.8   4         手動モード
  2            /usr/bin/gcc-5     5         手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 2
```

同様に g++ のバージョンも切り替えてあげます。

```shell:仮想マシンで実行
$ sudo update-alternatives --config g++
alternative g++ (/usr/bin/g++ を提供) には 2 個の選択肢があります。

  選択肢    パス            優先度  状態
------------------------------------------------------------
* 0            /usr/bin/g++-5     5         自動モード
  1            /usr/bin/g++-4.8   4         手動モード
  2            /usr/bin/g++-5     5         手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 2
```

## Linux カーネルのアップデート

仮想マシン内で下記を実行します。念の為、カーネル以外のパッケージも一緒にアップデートします。

```shell:仮想マシンで実行
$ sudo apt update           # リポジトリのキャッシュを更新
$ sudo apt upgrade -y       # パッケージのアップデート
$ sudo apt dist-upgrade -y  # カーネルのアップデート
```

更新が終わったら仮想マシンを再起動します。

```shell:ホストマシンで実行
$ vagrant reload
```

## Guest Addition のインストール

ここまでできたら準備完了なので最新の Guest Addition をインストールします。

```shell:ホストマシンで実行
$ vagrant vbguest --do install --auto-reboot
```

Guest Addition のインストールと仮想マシンの再起動がかかります。再起動が終わったら仮想マシン内で `/vagrant` が正しくマウントできているかどうかを確認してください。ホストマシンのファイルが表示されれば成功です。

## gcc のバージョンを元に戻す

通常使用する gcc のバージョンをもとに戻したい場合は下記のコマンドでバージョンを選択してください。

```shell:仮想マシンで実行
$ sudo update-alternatives --config gcc
$ sudo update-alternatives --config g++
```

# さいごに

解決策が分からなくて困っていた方の助けになれば幸いです。