僕がAnsibleを学ぶためにVagrant upできるようになるまで

#はじめに
数年前から環境構築を自動で整えたいと思っていて、
ようやくVagrant + Ansible の勉強をはじめました。
本記事の範囲は

1. とりあえず仮想マシンを２台立ち上げ
1. Ansibleで操作できるようになる土台が整うまで

を目指し、
vagrant upが満足に立ち上がる様にまでの手順と
自分が躓いた箇所とその対応を記録したものです。

#勉強の元ネタ
@hidekuro 様の記事を手始めに勉強させてもらいました。
[Vagrant + Ansibleで環境構築をコード化する(1)導入](https://qiita.com/hidekuro/items/81ae801b3cc5f72f0cc5)
Vagrantfile　はココを元ネタにしております。


# 環境
母艦：Ubuntu 18.04.2 LTS
仮想マシンの制御用ソフト：libvirtd (libvirt) 4.0.0、Vagrant 2.0.2
子１：Ubuntu 18.04.2 LTS (ホスト名：controller) 
子２：Ubuntu 18.04.2 LTS (ホスト名：remote)

操作は可能な限りTerminalからコマンドで行っています。

## libvirtのインストール
[ubuntu 18.04 上でkvm仮想マシンを動作させるまでの最低限の手順](https://qiita.com/zhh/items/df076c4614f0238f9876) を参考にインストールしました。

```
$ sudo apt install libvirt-clients
$ sudo apt install qemu-utils
$ sudo apt install qemu-kvm
$ sudo apt install virtinst
$ sudo apt install libvirt-bin
```
## vagrantの環境設定

~/.vagrant 配下が大容量必要になるとのことなので
Vagrantのホームディレクトリを変更しました。

```
$ sudo mkdir -p /srv/vagrant/home
$ sudo chown -R user:user /srv/vagrant
$ echo "VAGRANT_HOME=/srv/vagrant/home" >> ~/.bashrc
$ source ~/.bashrc
```

##　出来上がったVagrantfile

```
Vagrant.configure(2) do |config|

  # remote-VM
  config.vm.define "remote" do |remote|
    remote.vm.box = "generic/ubuntu1804"
    remote.vm.hostname = "ansible-remote"
    remote.vm.network "private_network", ip: "172.16.97.102"
    remote.vm.synced_folder './remote/', '/vagrant', type: '9p', :mount_options => ['dmode=775', 'fmode=664']

    remote.vm.provider "virtualbox" do |vb|
      vb.memory = 1024
      vb.cpus = 2
    end
    
    remote.vm.provision "shell", inline: <<-SHELL
      # DNS config
      sed -i.bak -e "s/^DNS=.*$/DNS=8.8.8.8 192.168.122.1/g" /etc/systemd/resolved.conf
      systemctl restart systemd-resolved.service
    SHELL
  end

  # control-VM
  config.vm.define "control" do |control|
    control.vm.box = "generic/ubuntu1804"
    control.vm.hostname = "ansible-control"
    control.vm.network "private_network", ip: "172.16.97.101"
    control.vm.synced_folder './control/', '/vagrant', type: '9p', :mount_options => ['dmode=775', 'fmode=664']

    control.vm.provider "virtualbox" do |vb|
      vb.memory = 512
      vb.cpus = 2
    end

    control.vm.provision "shell", inline: <<-SHELL
      # DNS config
      sed -i.bak -e "s/^DNS=.*$/DNS=8.8.8.8 192.168.122.1/g" /etc/systemd/resolved.conf
      systemctl restart systemd-resolved.service

      apt update 
      # expect
      apt -y install expect
      
      # ansible 
      apt -y install software-properties-common
      apt-add-repository --yes --update ppa:ansible/ansible
      apt -y install ansible
      apt -y autoremove

    SHELL

    control.vm.provision "shell", privileged: false, inline: <<-SHELL
      # ssh
      mkdir -p ~/.ssh
      ssh-keygen -N "" -t ed25519 -f ~/.ssh/id_ed25519
      rm -f ~/.ssh/known_hosts

      # ssh-copy-id
      cp -f /vagrant/expect_sendkey.expect ~/expect_sendkey.expect
      chmod 774 ~/expect_sendkey.expect
      ~/expect_sendkey.expect vagrant@172.16.97.102
    SHELL
  end

end
```

# エラー
## その１

```
$ vagrant up
A Vagrant environment or target machine is required to run this
command. Run `vagrant init` to create a new Vagrant environment. Or,
get an ID of a target machine from `vagrant global-status` to run
this command on. A final option is to change to a directory with a
Vagrantfile and to try again.
```

カレントディレクトリにVagrantfileが無いだけでした。
カレントディレクトリを移動します。
```$ cd ~/.vagrant.d```


## その２

```bash:母艦
$ vagrant up
Bringing machine 'remote' up with 'libvirt' provider...
Bringing machine 'control' up with 'libvirt' provider...
==> remote: An error occurred. The error will be shown after all tasks complete.
==> control: An error occurred. The error will be shown after all tasks complete.
An error occurred while executing multiple actions in parallel.
Any errors that occurred are shown below.

An error occurred while executing the action on the 'remote'
machine. Please handle this error then try again:

Name `vagrant_remote` of domain about to create is already taken. Please try to run
`vagrant up` command again.

An error occurred while executing the action on the 'control'
machine. Please handle this error then try again:

Name `vagrant_control` of domain about to create is already taken. Please try to run
`vagrant up` command again.
```

VAGRANT_HOME の場所をデフォルトから別の場所へ変更したので、
思い切って```~/.vagrant```ディレクトリを削除(rm -rf)してしまいました。
ついでに１からやり直したくなったので、Vagrantfileを残して
仮想マシン等(boxes,data,gems,等...)すべて物理削除(rm -rf)してしまった後、
```vagrant up```した時に出たエラーです。

libvert側に名前が残っていたので、名前衝突によってエラーがでていました。

```bash:母艦
$ virsh list --all
 Id    Name                           State
----------------------------------------------------
 -     vagrant_control                shut off
 -     vagrant_remote                 shut off

$ virsh undefine vagrant_control
Domain vagrant_control has been undefined

$ virsh undefine vagrant_remote
Domain vagrant_remote has been undefined
```

上記のように、libvirt側も名前を消したら、解消しました。

##その３

```bash:母艦
$ vagrant up
:
:
    control: Running: inline script
    control: /tmp/vagrant-shell: line 10: unexpected EOF while looking for matching `''
    control: /tmp/vagrant-shell: line 14: syntax error: unexpected end of file
==> control: An error occurred. The error will be shown after all tasks complete.
An error occurred while executing multiple actions in parallel.
Any errors that occurred are shown below.

An error occurred while executing the action on the 'control'
machine. Please handle this error then try again:

The SSH command responded with a non-zero exit status. Vagrant
assumes that this means the command failed. The output for this command
should be in the log above. Please read the output to determine what
went wrong.
```

「`」の数が合わないとのエラー。
実際にcontrolにログインして/tmp/vagrantファイルを見てみると、、、、

```bash:control
$ cat /tmp/vagrant-shell 
:
      mkdir -p ~/.ssh
      echo -e  'y
' | ssh-keygen -N "" -f ~/.ssh/id_rsa
:
```

たしかに数が合ってない。。。。
Vagrantfileを確認してみると、、、

```bash:母艦のVagrantfile抜粋
:
    control.vm.provision "shell", inline: <<-SHELL
:
      mkdir -p ~/.ssh
      echo -e  'y\n' | ssh-keygen -N "" -f ~/.ssh/id_rsa
:
    SHELL
:
```
ぱっと見おかしいところが無さそうですが、
```echo -e 'y\n' | ssh-keygen ```の\n　が改行として解釈されてしまったようです。
エスケープ処理(\を重ねる)で対応しました。

```bash:母艦のVagrantfile抜粋
:
    control.vm.provision "shell", inline: <<-SHELL
:
      mkdir -p ~/.ssh
      echo -e  'y\\n' | ssh-keygen -N "" -f ~/.ssh/id_rsa
:
    SHELL
```

うまく行きました。


## その４
```bash:母艦
$ vagrant up
:
==> control: Installing NFS client...

==> control: An error occurred. The error will be shown after all tasks complete.
An error occurred while executing multiple actions in parallel.
Any errors that occurred are shown below.

An error occurred while executing the action on the 'control'
machine. Please handle this error then try again:

The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

apt-get -yqq update
apt-get -yqq install nfs-common portmap
exit $?

Stdout from the command:

Stderr from the command:
E: Failed to fetch http://us.archive.ubuntu.com/ubuntu/pool/main/k/keyutils/keyutils_1.5.9-9.2ubuntu2_amd64.deb  Temporary failure resolving 'us.archive.ubuntu.com'
E: Failed to fetch http://us.archive.ubuntu.com/ubuntu/pool/main/libn/libnfsidmap/libnfsidmap2_0.25-5.1_amd64.deb  Temporary failure resolving 'us.archive.ubuntu.com'
E: Failed to fetch http://security.ubuntu.com/ubuntu/pool/main/libt/libtirpc/libtirpc1_0.2.5-1.2ubuntu0.1_amd64.deb  Temporary failure resolving 'us.archive.ubuntu.com'
E: Failed to fetch http://us.archive.ubuntu.com/ubuntu/pool/main/r/rpcbind/rpcbind_0.2.3-0.6_amd64.deb  Temporary failure resolving 'us.archive.ubuntu.com'
E: Failed to fetch http://us.archive.ubuntu.com/ubuntu/pool/main/n/nfs-utils/nfs-common_1.3.4-2.1ubuntu5.1_amd64.deb  Temporary failure resolving 'us.archive.ubuntu.com'
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
```

NFSのインストール〜設定まわりで失敗したようです。


```text:母艦のVagrantfile(抜粋)
:
control.vm.synced_folder ".", "/vagrant", :mount_options => ['dmode=775', 'fmode=664']
:
```

[Vagrant provider for libvirt. #Synced_Folders](https://github.com/vagrant-libvirt/vagrant-libvirt#synced-folders)　を見てみると若干書式が違っていました。
以下の様に修正してみると、、、、

```text:母艦のVagrantfile(抜粋)
control.vm.synced_folder './', '/vagrant', type: '9p', :mount_options => ['dmode=775', 'fmode=664']
```

無事起動できました！

```bash:母艦
$ vagrant up
:
==> control: Configuring and enabling network interfaces...
==> control: mounting p9 share in guest
==> control: Running provisioner: shell...
    control: Running: inline script
:
```

#その５
日本語化
[Ubuntuの日本語環境](https://www.ubuntulinux.jp/japanese) を参考にaptのリポジトリの更新を行いました

```text:母艦のVagrantfile(抜粋)
    control.vm.provision "shell", inline: <<-SHELL
      # Japanese
      cd /tmp
      wget -nv https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg
      apt-key add /tmp/ubuntu-ja-archive-keyring.gpg

      cd /tmp
      wget -nv https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg
      apt-key add /tmp/ubuntu-jp-ppa-keyring.gpg

      mkdir -p /etc/apt/sources.list.d
      cd /etc/apt/sources.list.d
      wget -nv https://www.ubuntulinux.jp/sources.list.d/bionic.list
      mv bionic.list ubuntu-ja.list

      apt update
    SHELL
```

オプションの ```-q```　はエラーも黙らせてしまうようなので```-nv```オプションに変更してます。
あと問題の切り分けのために```wget```、```apt-key``` を分割しました。


```
==> control: Running provisioner: shell...
    control: Running: inline script
    control: wget: unable to resolve host address 'www.ubuntulinux.jp'
    control: Warning: apt-key output should not be parsed (stdout is not a terminal)
    control: gpg: can't open '/tmp/ubuntu-ja-archive-keyring.gpg': No such file or directory
```

調べてみるとwgetでファイルが取得できていませんでした。
vagrant sshでログインした後、確認するとIPアドレスではpingが通りますが、
ホスト名だと迷子になってました。どうやらDNSの名前解決に失敗しているようです。

nsswitch.conf弄ったり、```--natdnshostresolver1``` onにしたり、offにしたり、
色々やってみましたが、destroy -> up を繰り返すたびに挙動が不安定です。
で、やっと見つけましたresolve.confを修正しました。

ほんと探しまくりました（２週間くらい。。。）

```text:母艦のVagrantfile(抜粋)
    control.vm.provision "shell", inline: <<-SHELL
      # DNS config
      sed -i.bak -e "s/^DNS=.*$/DNS=8.8.8.8 192.168.122.1/g" /etc/systemd/resolved.conf
      systemctl restart systemd-resolved.service

    SHELL
```
DNSの接続先を8.8.8.8（GoogleのDNS）、母艦のvirbr0インタフェースに指定しています。

# その他、調べていく中で、たくさんの方々の記事を参考にさせて頂きました。
* [Vagrant + Ansibleで環境構築をコード化する(2)Playbookを使う](https://qiita.com/hidekuro/items/835ad3b0262ef5203e4d)
* [Vagrant + Ansibleで環境構築をコード化する(3)もっとPlaybook](https://qiita.com/hidekuro/items/628645799247f0939724)
* [Vagrant + Ansibleで環境構築をコード化する(4)さらにPlaybook　～終わり～](https://qiita.com/hidekuro/items/8cd1ebe1c52a256593ef)
* [vagrant-libvirtの使い方](https://qiita.com/manji0/items/d1ab7a0c134ed0e32b3f)
* [KVMのゲストマシンから外部へ通信できるようにする](https://www.rhoboro.com/2016/08/13/kvm-on-digitalocean-2.html)
* [Ubuntu 18.04: NFSサーバのnfs-kernel-serverをインストールする](https://www.hiroom2.com/2018/05/05/ubuntu-1804-nfs-kernel-server-ja/)
* [Vagrant provisioning using shell - how to setup storm project](https://stapp.space/vagrant-provisioning-shell/)
* [sedコマンドの備忘録](https://qiita.com/takech9203/items/b96eff5773ce9d9cc9b3)
* [Ubuntu Linux 18.04 LTSに、VagrantをインストールしてUbuntu Linux 18.04 LTSのboxを起動するまで](https://kazuhira-r.hatenablog.com/entry/2018/12/02/235925)
* [Ubuntu 16.10 その7 - ローカルDNSリゾルバーの仕組みが変わる・systemd-resolvedの採用](https://kledgeb.blogspot.com/2016/06/ubuntu-1610-7-dnssystemd-resolved.html)
* [VagrantのトラブルシュートのためにDebugログを出力する](https://qiita.com/ariarijp/items/92a291ac447af430c29c)
* [GitHubでEd25519鍵をつかう](https://jnst.hateblo.jp/entry/2014/12/15/200542)