Vagrant の package --vagrantfile における Vagrantfile の適用優先度（と翻訳）

> Vagrant の Box 作成時に適用した Vagrantfile と、Vagrant up 時の Vagrantfile で、設定の優先度はどうなっているの？

## TL;DR（概要）

> Vagrantfiles は以下の順序でロードされます。各ステップで Vagrantfile が見つからなかった場合、Vagrant は次のステップに進み、Vagrantfile が見つかった場合は、その値をマージしていきます。<br>
> 1. 対象仮想マシンの Box に内包された Vagrantfile。
> 2. Vagrant のホームディレクトリにある Vagrantfile（デフォルトは `~/.vagrant.d`）。
> 3. プロジェクトのディレクトリにある Vagrantfile。
> 4. [Multi-machine](https://www.vagrantup.com/docs/multi-machine/) がある場合は、それらの設定。
> 5. プロバイダ[^provider][固有のオーバーライド](https://www.vagrantup.com/docs/providers/configuration.html)ある場合、それらの設定。

ほとんどの場合、Vagrant ファイルの変更はステップ 3 を指します。適用の優先度の仕組みは、`profile` `.bash_profile` `.bashrc` のような[ bash の設定が適用される優先度](https://www.google.com/search?q=site:qiita.com+profile+.bash_profile+.bashrc)がイメージとして近いかもしれません。

## TS;DR（詳細）

### `--vagrantfile` オプションの使い道がわからない

Vagrant[^vagrant] のコマンド・ツールには Vagrant の Box[^box] アーカイブを作成するための `package` というコマンドがあります。その、`package` コマンドに `--vagrantfile` というオプションがあります。

```shell-session:ヘルプの翻訳（一部）
$ vagrant --help | grep package
     package         現行の Vagrant 環境を Box にパッケージングします。

$ vagrant package --help
Usage: vagrant package [オプション] [パッケージ名|パッケージ id]

オプション:

        --base NAME                  Box にパッケージングしたい VirtualBox の仮想マシン名。
                                    （VirtualBox 限定オプション。仮想マシンの設定にある "Name"）
        --output NAME                Name of the file to output
        --include FILE,FILE..        Box のパッケージングの際に追加するファイル。コンマ区切り。
        --vagrantfile FILE           Box のパッケージングの際に同梱する Vagrantfile。　　←これ
    -h, --help                       このヘルプ
```

しかし、そもそも Vagrantfile から呼び出されるのが作成された Box ファイルであるため、このオプションの使い道がいまいちピンと来ないのです。

公式のドキュメントを読むと注釈に簡単な違いが書いてありました。

> **A common misconception** is that the `--vagrantfile` option will package a Vagrantfile that is used when vagrant init is used with this box. This is not the case. Instead, a Vagrantfile is loaded and read as part of the Vagrant load process when the box is used. For more information, read about the [Vagrantfile load order](https://www.vagrantup.com/docs/vagrantfile/#load-order).
> （「[Options の注釈](https://www.vagrantup.com/docs/cli/package.html#options) | Package | Docs」@ Vagrant 公式より）
> 
> （筆者訳）<br>**よくある誤解**は、`--vagrantfile` オプションで Box にパッケージ化された Vagrantfile は、`vagrant init` 時に使われると勘違いされることです。違います。この、パッケージに含まれた Vagrant ファイルは、Box の使用時の Vagrant のロード・プロセスの一部として読み込まれます。詳しくは、[Vagrantfile のロード順序](https://www.vagrantup.com/docs/vagrantfile/#load-order)をお読みください。

なるほど、よくある誤解だったようです。とほほ。

そこで、詳しく知りたかったので、公式の「[Load Order and Merging](https://www.vagrantup.com/docs/vagrantfile/#load-order)」を訳してみました。

▼ 以下翻訳（この記事は[原文と同じ MIT ライセンス](https://github.com/hashicorp/vagrant/blob/master/LICENSE)とします）

### Vagrantfile のロード順とマージ

Vagrant が、どのように Vagrantfiles をロードする（読み込まれる）か概念を理解することが重要です。

実際には、Vagrant は一連の Vagrantfiles をロードし、設定をマージして行きます。これにより、さまざまなレベルの特定の Vagrantfiles が以前の設定を上書きすることができます。

Vagrantfiles は以下の順序でロードされます。各ステップで Vagrant ファイルが見つからなかった場合、Vagrant は次のステップに進むことに注意してください。

1. 対象仮想マシンの Box に内包された Vagrantfile。
2. Vagrant のホームディレクトリにある Vagrantfile（デフォルトは `~/.vagrant.d`）。これにより、いくつかの設定は、システムユーザー固有のデフォルト値として設定できます。
3. プロジェクトのディレクトリにある Vagrantfile。ほとんどの場合は、この Vagrant ファイルを変更します。
4. [Multi-machine](https://www.vagrantup.com/docs/multi-machine/) がある場合は、それらの設定。
5. プロバイダ[^provider][固有のオーバーライド](https://www.vagrantup.com/docs/providers/configuration.html)ある場合、それらの設定。

各段階で設定された項目は、それ以前の値とマージされます。どのようにマージされるかは設定によって異なります。ほとんどの設定では、新しい設定が古い設定を上書きします。一方、ネットワークの定義などの場合は上書きでなく追加されていきます。デフォルトで設定は互いに優先しあう（上書きしあう）と仮定する必要があります。動作が異なる場合は、関連するドキュメントに記載されています。

各 Vagrantfile 内では、複数の Vagrant.configure ブロック（構成）を指定できます。すべての構成は、定義されている順序で単一の Vagrant ファイルにマージされます。

▲ 翻訳ここまで

つまり、Box に内包された Vagrantfile は `vagrant init` でなく `vagrant up` 時に影響がある設定ということのようです。どうやら、**提供する Box のデフォルト値を変更したい時に `--vagrantfile` オプションを活用する**のが主な目的のようです。

[Vagrant Cloud から macOS の Vagrant box をダウンロード](https://app.vagrantup.com/KEINOS/boxes/macOS.10.13.6_Japanese/) して単純に `vagrant up` すると以下のような「`Vagrant is not able to mount VirtualBox shared folders`」エラーが出る場合に、デフォルトで共有フォルダを無効にしておくなどに活用できそうです。

```
Vagrant is not able to mount VirtualBox shared folders on BSD-based
guests. BSD-based guests do not support the VirtualBox filesystem at
this time.

To change the type of the default synced folder, specify the type as
rsync or nfs:

    config.vm.synced_folder ".", "/vagrant", type: "nfs" # or "rsync"

Alternatively, if you do not need to mount the default synced folder,
you can also disable it entirely:

    config.vm.synced_folder ".", "/vagrant", disabled: true

You can read more about Vagrant's synced folder types and the various
configuration options on the Vagrant website.

This is not a bug in Vagrant.
```


<!-- 注釈 --------------------------------------------------------------------------------->

[^vagrant]: 【Vagrant とは】VirtualBOX / VMware / Docker などの仮想マシン系のアプリの挙動を、コマンドで操作するためのツールのこと。例えば、[VirtualBOX の仮想マシンとゲスト OS の入手](https://app.vagrantup.com/boxes/search?provider=virtualbox)と起動、必要なアプリのインストール、OS のスナップショット、シェルコマンドの実行、スナップを戻すといったバッチ処理的なことができる。これにより、テスト環境の構築とテストの実行や、特定環境でのビルドを自動化することができる。このように指揮をとるイメージから、オーケストレーション・ツールと呼ばれるものの１つ。[CI](https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3) などに使われる。「[Vagrant (ソフトウェア)](https://ja.wikipedia.org/wiki/Vagrant_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2))」@ Wikipedia 

[^box]: 【Box とは】Vagrant における Box は、".box" の拡張子が付いたパッケージ・ファイルのこと。作成した仮想マシンとゲスト OS（仮想マシン上で動かす OS）を異なる Vagrant 環境で動かすために必要なファイルをアーカイブして１つのファイルにしたもの。基本的に含まれる内容は「[Raw Contents](https://www.vagrantup.com/docs/virtualbox/boxes.html#raw-contents) | Boxes」@ Vagrant 公式 を参照。

[^provider]: 【プロバイダーとは】Vagrant におけるプロバイダーとは、仮想環境を提供しているアプリおよび Box が必要な仮想環境のこと。VirtualBox、VMware、Docker などを指す。