デフォルト設定を最大限に活かし VirtualBox 用の Vagrant box を Packer で作る

最初に結論を書きます。**めちゃくちゃに手を抜きまくっても意外と大丈夫です。**
https://github.com/hytdsh/minimalpacker

# 動機
Vagrant を使うのに他所から box をダウンロードするのがダルいというか遅いのが我慢できませんでした。
他所からダウンロードした box に何が入ってるのかよくわからなくて落ち着かないのもフラストレーションでした。

いまいち中身のはっきりしない box をホイホイと使うのはダメなのでは？
かといって Vagrant を捨てた挙句に「画面遷移ごとに手入力してインストールした仮想マシン」に回帰するのも as Code の観点からどうなの？
⇒ **box を手元で自動的に作成できれば良いのでは**

ダウンロードした box だと VirtualBox の更新に追随しないのがツラい・・・Guest Additions を入れなおすのが面倒くさい・・・
⇒ **box を手元で自動的に作成できれば VirtualBox の更新に追随するのも楽なのでは**

box が秘伝のタレ化する予感がある
⇒ **box を手元で自動的に作成できれば気軽にリセットできて秘伝のタレ化を回避できるのでは**

https://github.com/chef/bento とか、もちろん便利なんだとは思います。
ですが、汎用のレシピとかは対象が多すぎて、どのファイルが必要でそのファイルが不要か、見分けるだけで疲れてしまうのも否めません。

⇒⇒⇒ **簡潔な Packer の構成が欲しい！！！**

# わりと頑張ったところ

#### とにかく記述を軽くした
どこまでデフォルト設定を活かせるか、定石の書き方からかなり削ったつもりです。
限界を詰めたわけではないので、まだ削れる余地はあるかもしれませんが、まあまあ軽量になったのではないかと思います。

#### Base Box としての最低限の機能
限界まで手を抜きつつも Vagrant が提示する [Base Box としての要件](https://www.vagrantup.com/docs/boxes/base.html) は満たしています。

- vagrant/vagrant なユーザーアカウントに SSH でログインできる
- root/vagrant になっている
- vagrant ユーザーがパスワード無しで sudo できる
- Guest Additions がインストールされている
  - 副作用として `vagrant up` で仮想マシン内の `/vagrant` ディレクトリがデフォルトで共有される

#### preseed だけで `hostname` を指定できる
Packer 系の記事で preseed ファイルを HTTP で渡しつつ、その渡した preseed ファイルの中では
 `netcfg/get_hostname` でホスト名を指定している、という内容をよく見ますが、そのままだと(append 行で指定するなどしないと)たぶん実際に出来上がるマシンのホスト名は "debian" とか "ubuntu" とかの、デフォルト名になってしまうのではないでしょうか。
少なくとも自分の手元で試した限りでは `netcfg/get_hostname` や `netcfg/hostname` のみの指定ではホスト名の反映ができませんでした。
これは preseed を HTTP で渡すと[確定で発生する仕様](https://www.debian.org/releases/stable/amd64/apbs04.html)であるようです。

同文書に記載のある `kill-all-dhcp; netcfg` を採用して preseed 内でホスト名を指定できるようにしています。
手元の環境では `netcfg/hostname` による指定を併用する必要がありました。


# 微妙にいけてないところ

#### `"boot_command"` がダサい
率直に言って `<wait>` とか使いたくないです。
Packer が失敗する時は、たいてい `"boot_command"` の送出がチャタリングしてブートできていないケースです。
本稿の手順の中で最も脆弱なポイントで可能な限り回避したい箇所です。

ホストが Linux とか macOS とかなら `netboot.tar.gz` を VirtualBox の TFTP 配下に展開してちょっと `pxelinux.cfg/default` をいじってから Packer に渡す JSON の中で `"vboxmanage"` と `"vboxmanage_post"` に `--nattftpfile` や `--boot` などを指定してブートデバイスを変更してやれば `"boot_command"` の使用を回避(空文字列の指定)できるのではないかと思います(未確認)。

Windows ホストの VirtualBox では主にシンボリックリンク周りが思うように取り回せず、ひとまず諦めました。
`netboot.tar.gz` から必要なファイルを拾って TFTP 配下に置けばうまく行くかもしれません。


#### `config.ssh.password` の指定が必要
初回の `vagrant up` の時だけ `config.ssh.password = "vagrant"` の指定が必要です。
これは Packer の工程で [insecure keypair](https://github.com/hashicorp/vagrant/tree/master/keys) を導入していないためです。
`vagrant up` の際の手間と鍵ペアの導入の手間を考えて、今回は鍵ペア導入の手間を回避しました。

# 成果物
**https://github.com/hytdsh/minimalpacker**
対象は VirtualBox のみです。

Packer に渡す JSON は40行。
Debian インストーラーに渡す preseed は50行(コメントを除く)。
Guest Addition の追加に使うシェルスクリプトは10行。
総計100行ほどと、あらかじめ用意しておいた ISO ファイル(50MBくらい)を使って `packer build` を叩いてから20分(Core i5 M520, 8GB)程度でファイルサイズ約1GBの box が作成できます。
作成中はネットワーク帯域をそれなりに使います。

# おまけ

#### ファイルの改行コードは気にしなくて良い
例えば `chef/bento` ではしっかり `.gitattributes` で改行コードを明示的に扱っていたりしています。
それはやっぱり普段の作業では改行コードに気を付けるほうが良いのはわかっていますが、本件に関しては改行コードは各サービスがよろしく扱ってくれるようで、全く気にしなくて良いです。
preseed ファイルとかも CR-LF で大丈夫です。
これは preseed ファイルを渡すのに使う HTTP がうまいことやってくれているんだと思われます。たぶん。
(同じ理由で kickstart ファイルも HTTP で渡す限りは改行コードを気にしなくて良いように思いますが、確認はしていません。)
他のファイルの改行コードも Packer や Vagrant がうまいこと扱ってくれるようです。

#### 共有フォルダの設定は明示しなくて良い
Guest Additions のインストールに成功していれば Vagrant はデフォルトで仮想マシン内の `/vagrant` を `synced_folder` として共有してくれます。

# 今後の展望
Windows Subsystem for Linux が daemon を普通に扱えるようになったら、本稿の内容は不要になるかもしれません。