macOS で multipass やってみようぜ (v1.0.0+mac)

# multipass ってなに？

mutipass って入れてるのに multipath が多くヒットしてしまう。。。

VM Engine として [hyperkit](https://github.com/moby/hyperkit), Hyper-V, Virtualbox, KVM を使った Ubuntu LTS (Long Term Support) 専用インスタンス (VM) を爆速で作成するツール。

* **Ubuntu LTS on tap**: cloud-init で初期化された Ubuntu のインスタンスを起動
* **Native hypervisor**: 爆速で起動するよう Hyper-V, HyperKit, Virtualbox, KVM などの Native Hypervisor を使用
* **Up to date**: Canonical から最新の [Ubuntu Cloud イメージ](http://cloud-images.ubuntu.com/)を自動取得しインスタンスを作成
* **Optimised guests**: 各ハイパーバイザー用にカスタムチューニングされた Ubuntu カーネルを提供
* **Pet, and cattle**: インスタンス名を自動生成
* **Platform integration**: ホスト側のホームディレクトリとインスタンスの間でファイルとフォルダを共有可能

本記事は、macOS 上で multipass を利用する方法をまとめてみました。
コマンドの実行結果は、すべて host 側の macOS からの実行になります。

## multipass の情報源

意外と情報が少なかった。
ひとまず、オフィシャルのページと GitHub と community forum が情報源として活用できる:

* [Multipass - Orchestrates virtual Ubuntu instances](https://multipass.run)
* [https://github.com/CanonicalLtd/multipass](https://github.com/CanonicalLtd/multipass)
* [For discussion of Multipass](https://community.ubuntu.com/c/multipass)
* [Multipass Documentation outline](https://community.ubuntu.com/t/multipass-documentation-outline/8294#command-line-reference)

WSL2 も出てきて [Multipass vs. Windows Subsystem for Linux (WSL)](https://community.ubuntu.com/t/multipass-vs-windows-subsystem-for-linux-wsl/11256) みたいな話題も増えてきている。


## multipass のインストール

以下から DMG ファイルをダウンロード。これを書いている時点でのバージョンは、`v1.0.0+mac` :

  * https://multipass.run
  * https://github.com/CanonicalLtd/multipass/releases

インストーラーも用意されているし `brew cask install multipass` でも簡単に導入可能。

v1.0.0 から、インスタンスの起動/停止/shell へのアクセスを行うためのステータスメニューが追加されている:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65800/575b7ae0-c478-e7d2-426f-3c6e468cae04.png)

* [Announcing Multipass 1.0.0 ‒ first stable release!](https://discourse.ubuntu.com/t/announcing-multipass-1-0-0-first-stable-release/13704)


## multipass for macOS で利用される hypervisor back-end

macOS Yosemite で導入された、[Hypervisor Framework](https://developer.apple.com/documentation/hypervisor) を使用した [moby/hyperkit](https://github.com/moby/hyperkit) で実現されている
Hypervisor Framework が利用できるかは、下記のコマンドで確認可能(2010 年以降に発売された Mac であれば利用可能)

  ```sh
  $ sysctl -a | grep kern.hv_support
  kern.hv_support: 1
  ```

binary は下記に格納される、ディスクイメージを扱うための [qemu-img](http://manpages.ubuntu.com/manpages/cosmic/man1/qemu-img.1.html) コマンドも含まれている。

  * `/Library/Application Support/com.canonical.multipass/bin`

```sh
$ ./hyperkit -v
hyperkit: v0.20180403-19-g9ef4eb

Homepage: https://github.com/docker/hyperkit
License: BSD

$ ./qemu-img -V
qemu-img version 2.9.0
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers
```

hypervisor back-end として、VirtualBox も利用する事が可能であり、platform により利用可能な back-end が異なる。
`multipass set local.driver` で変更可能。

| platform |   default  | Allowed values             |
|----------|------------|----------------------------| 
| macOS    | `hyperkit` | `hyperkit` or `virtualbox` |
| Windows  | `hyperv`   | `hyperv` or `virtualbox`   |
| Linux    | `qemu`     | `qemu` or `libvirt`        |

この記事では、`hyperkit` をベースにしている。

## インスタンスの管理に利用するコマンド

インスタンスの作成/起動/停止/削除などは、`multipass` シングルコマンドにサブコマンドを指定する。
用意されているサブコマンドは、下記のとおり (v1.0.0+mac):

```
$ multipass help

Available commands:
  delete    Delete instances
  exec      Run a command on an instance
  find      Display available images to create instances from
  get       Get a configuration setting
  help      Display help about a command
  info      Display information about instances
  launch    Create and start an Ubuntu instance
  list      List all available instances
  mount     Mount a local directory in the instance
  purge     Purge all deleted instances permanently
  recover   Recover deleted instances
  restart   Restart instances
  set       Set a configuration setting
  shell     Open a shell on a running instance
  start     Start instances
  stop      Stop running instances
  suspend   Suspend running instances
  transfer  Transfer files between the host and instances
  umount    Unmount a directory from an instance
  version   Show version details
```


## 選択可能なイメージ

v1.0.0+mac で利用できるイメージは、`find` コマンドで確認可能。
Ubuntu LTS をターゲットにしているので選択できるのは下記だけなのかな。 
`--show-unsupported` や `daily:` なんかも指定できると記載されているが、macOS 版では機能していない感じ:

```
$ multipass find
Image                   Aliases           Version          Description
snapcraft:core          core16            20191219         Snapcraft builder for Core 16
snapcraft:core18                          20191219         Snapcraft builder for Core 18
16.04                   xenial            20200108         Ubuntu 16.04 LTS
18.04                   bionic,lts        20200107         Ubuntu 18.04 LTS
```

## インスタンスの作成

実際にインスタンスを作成してみる。

インスタンスを作成するには、`launch` コマンドを実行。
インスタンス名を指定しない場合は、multipass コマンドが自動的にランダムなインスタンス名をアサイン(そのための辞書を持っている。。。)する。
また、インスタンス名に `primary` と名付けられたインスタンスは、各コマンド実行時にインスタンス名を省略できる特別なインスタンスとなる。
この省略可能な特別なインスタンス名は、`multipass set client.primary-name` で変更可能。
まずは、`primary` で作成して見ると良い:

```
$ multipass launch -n primary   
One quick question before we launch … Would you like to help                    
the Multipass developers, by sending anonymous usage data?
This includes your operating system, which images you use,
the number of instances, their properties and how long you use them.
We’d also like to measure Multipass’s speed.

Send usage data (yes/no/Later)? no
Launched: primary                                                               
Mounted '/Users/kazus' into 'primary:Home'                                      
```

初回は、[Ubuntu Cloud イメージ](http://cloud-images.ubuntu.com/releases/server/releases/bionic/release-20191205/ubuntu-18.04-server-cloudimg-amd64.img)をダウンロードするので、少し時間がかかります。

そして、プロンプトが返ってくるまで待つ。

オプションに何も指定せずに作成されるインスタンスの default resource は、cpus: 1, disk: 5G (sparse file), mem: 1G となっているので、調整したければ、`multipass launch` 実行時に、`--cpus`, `--disk`, `--mem` で好きなだけ割り当てるよろし。

また、`cloud-init を利用した cloud-config.yaml` でカスタマイズされたインスタンスを launch したければ、下記を参照:

* [Using cloud-init with Multipass](https://ubuntu.com/blog/using-cloud-init-with-multipass)

cloud-init で仕込まれた user-data と vendor-data は、作成されたインスタンスの `/var/lib/cloud/instances/` で参照する事が可能。

ダウンロードされた Ubuntu Cloud イメージは、下記のディレクトリに配置され cache として利用される:

* `/var/root/Library/Caches/multipassd/vault/images`

```
/var/root/Library/Caches/multipassd/vault/
├── images
│   └── bionic-20200107
│       ├── ubuntu-18.04-server-cloudimg-amd64-initrd-generic
│       ├── ubuntu-18.04-server-cloudimg-amd64-vmlinuz-generic
│       └── ubuntu-18.04-server-cloudimg-amd64.img
└── multipassd-image-records.json
```

また、作成するインスタンスに sshfs がインストールされるが、インスタンスが DNS を引けないなどが原因の場合、下記のエラーが出力される。
エラーは出力されるがインスタンスは作成できている。

```
% multipass launch --name primary
Launched: primary                                                               
mount failed: Error enabling mount support in 'primary'                         

Please install 'sshfs' manually inside the instance.

% multipass list
Name                    State             IPv4             Image
primary                 Running           192.168.64.3     Ubuntu 18.04 LTS

% multipass shell
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-72-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon Dec 23 01:21:00 JST 2019

  System load:  0.01              Processes:             103
  Usage of /:   20.8% of 4.67GB   Users logged in:       0
  Memory usage: 11%               IP address for enp0s2: 192.168.64.3
  Swap usage:   0%


0 packages can be updated.
0 updates are security updates.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


ubuntu@primary:~$ 
```

自宅で利用している McAfee などがインストールされていない環境では、問題なく。
環境依存かと思っているが、McAfee などがインストールされているとダメなような気がする...けど、原因が分からず。注意されたし。


### インスタンスの確認

何事もなくプロンプトが返って来たならば、すでにインスタンスは作成完了しているはず。

`multipass list` コマンドで、インスタンスの状態およびインスタンスとインスタンスにアサインされる IP アドレスを確認できる:

```
$ multipass list
Name                    State             IPv4             Image
primary                 Running           192.168.64.5     Ubuntu 18.04 LTS
passionate-reptile      Running           192.168.64.6     Ubuntu 18.04 LTS
```

アサインされた IP アドレスに ssh で突撃してみたくなるが、`PasswordAuthentication no` が設定されているため、認証は公開鍵のみでしか許可されていないのでログインする事はできない。

さらに、`multipass info` コマンドでインスタンスの詳細を確認できる:

```
$ multipass info --all
Name:           primary
State:          Running
IPv4:           192.168.64.2
Release:        Ubuntu 18.04.3 LTS
Image hash:     a720c34066dc (Ubuntu 18.04 LTS)
Load:           0.23 0.07 0.02
Disk usage:     1.1G out of 4.7G
Memory usage:   75.2M out of 985.7M
Mounts:         /Users/kazus => Home
                    UID map: 501:default
                    GID map: 20:default
```

macOS 側の ps コマンドで、hyperkit プロセスの引数を確認してみる:
  
```sh
$ ps -aef | grep hyper
    0  1289    95   0  9:35AM ??         0:12.68 /Library/Application Support/com.canonical.multipass/bin/hyperkit -c 1 -m 1024M -u -A -H -U 386bba5a-5dc4-3ac2-95c9-cf0b9a29b352 -s 0:0,hostbridge -s 2:0,virtio-net -s 5,virtio-rnd -s 31,lpc -l com1,autopty=/var/root/Library/Application Support/multipassd/vault/instances/primary/pty,log=/Library/Logs/Multipass/primary-hyperkit.log -s 1:0,ahci-hd,file:///var/root/Library/Application Support/multipassd/vault/instances/primary/ubuntu-18.04-server-cloudimg-amd64.img?sync=os&buffered=1,format=qcow,qcow-config=discard=true;compact_after_unmaps=262144;keep_erased=262144;runtime_asserts=false -s 1:1,ahci-cd,/var/root/Library/Application Support/multipassd/vault/instances/primary/cloud-init-config.iso -f kexec,/var/root/Library/Application Support/multipassd/vault/instances/primary/ubuntu-18.04-server-cloudimg-amd64-vmlinuz-generic,/var/root/Library/Application Support/multipassd/vault/instances/primary/ubuntu-18.04-server-cloudimg-amd64-initrd-generic,earlyprintk=serial console=ttyS0 root=/dev/sda1 rw panic=1 no_timer_check
```

さらに、インスタンスが起動されると、macOS 側には `bridge100` interface が作成される。
インスタンス毎に `enN` のような interface が作成され、bridge100 の member として追加されるみたい。
これは、macOS のインターネット共有機能 (Internet Sharing) と同等の事をやっているのだろうか... : 

```
bridge100: flags=8a63<UP,BROADCAST,SMART,RUNNING,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
	options=3<RXCSUM,TXCSUM>
	ether aa:20:66:aa:ae:64 
	inet 192.168.64.1 netmask 0xffffff00 broadcast 192.168.64.255
	inet6 fe80::1828:fe19:8800:209f%bridge100 prefixlen 64 secured scopeid 0x15 
	Configuration:
		id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
		maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
		root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
		ipfilter disabled flags 0x2
	member: en4 flags=3<LEARNING,DISCOVER>
	        ifmaxaddr 0 port 20 priority 0 path cost 0
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect
	status: active

en4: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
	options=400<CHANNEL_IO>
	ether ee:0f:c9:aa:34:0f 
	media: autoselect
	status: active
```

ネットワーク周りで問題がある場合は、下記のドキュメントを参考に: 

* [Troubleshooting networking on macOS](https://discourse.ubuntu.com/t/troubleshooting-networking-on-macos/12901)


### インスタンスへのアクセス

> v1.0.0 では、~/.ssh/config ファイル内の記述が複雑だと multipass shell が segmentation fault してしまう bug がある。https://github.com/canonical/multipass/issues/1259
> `sudo multipass shell` などで誤魔化す

初回、ssh での remote login はできないので、`multipass shell` でアクセスする。
インスタンス名は `primary` なので省略している:

```sh
$ multipass shell
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-74-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon Jan 13 09:39:12 JST 2020

  System load:  0.06              Processes:             118
  Usage of /:   24.1% of 4.67GB   Users logged in:       0
  Memory usage: 11%               IP address for enp0s2: 192.168.64.2
  Swap usage:   0%


0 packages can be updated.
0 updates are security updates.


Last login: Mon Jan 13 05:04:32 2020 from 192.168.64.1
ubuntu@primary:~$ 
```

アクセスできてしまえば、そこはもう Ubuntu の世界だった。

### インスタンスにユーザーを追加

作成されたインスタンスには、multipass shell 用に `ubuntu` ユーザーが用意されている。
`utbuntu` ユーザーは、multipass コマンドで利用されるためそのままにしておく。
新たにユーザーを用意したければ、一般的なユーザー追加コマンドを実行すれば良い: 

```
$ sudo useradd -d /home/kazus -s /bin/bash -m kazus
$ sudo gpasswd -a kazus sudo
$ sudo passwd kazus
```

### host からインスタンス内のコマンドを実行する

`multipass exec` で、ホストからインスタンスへコマンドを投入し、ログインすることなく出力を得ることも可能: 

```
$ multipass exec -v primary -- lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.3 LTS
Release:	18.04
Codename:	bionic
```

### host (macOS 側) からインスタンスへ ssh するには:

インスタンスには、`ubuntu` ユーザーしか存在しないので `multipass shell` でアクセスして、適当なユーザーを作成して公開鍵を設定するなどしても良い。
とりあえず、`ubuntu` ユーザーそのままで、ssh login したい場合は、下記のように macOS 側で公開鍵をコピーして利用する事も可能:

```
$ sudo cp /var/root/Library/Application\ Support/multipassd/ssh-keys/id_rsa ~/.ssh/multipass.id_rsa
$ sudo chown `id -un` ~/.ssh/multipass.id_rsa 
$ ssh -i ~/.ssh/multipass.id_rsa ubuntu@インスタンスのIP
```

接続が確認できたら、~/.ssh/config に接続設定を追記しておくと良い:

```
Host primary
    HostName 192.168.64.2
    User ubuntu
    IdentityFile ~/.ssh/multipass.id_rsa
```

なお、bridge interface の追加などは出来ないため、現状、ホスト外からダイレクトにアクセスする事はできない。

* [access from public  · Issue #512 · CanonicalLtd/multipass](https://github.com/CanonicalLtd/multipass/issues/512)
* [Support for bridged networking · Issue #118 · CanonicalLtd/multipass](https://github.com/CanonicalLtd/multipass/issues/118)

### host のディレクトリをインスタンス側で mount する

host 側のディレクトリをインスタンス側で mount しアクセスする事も可能。
uid とかどーなるの？と思ってたら、そのままで見えた。uid と gid の mapping もオプションで可能。 
インスタンス側では、FUSE sshfs を利用して実現している。 

v1.0.0+mac では、インスタンス作成時に、自動的に host 側の \$HOME が mount されるようになっている。

下記を実行すると、インスタンス側の /mnt が mount point となり、host 側の /Applications が mount される:

```
$ multipass mount /Applications primary:/mnt
```

`multipass info` で、mount 状況を確認することも可能:

```
$ multipass info --all
Name:           primary
State:          Running
IPv4:           192.168.64.2
Release:        Ubuntu 18.04.3 LTS
Image hash:     a720c34066dc (Ubuntu 18.04 LTS)
Load:           0.03 0.02 0.00
Disk usage:     1.2G out of 4.7G
Memory usage:   78.4M out of 985.7M
Mounts:         /Users/kazus  => Home
                    UID map: 501:default
                    GID map: 20:default
                /Applications => /mnt
                    UID map: 501:default
                    GID map: 20:default
```

unmount は、下記のように実行: 

```
$ multipass umount primary:/mnt

$ multipass info --all         
Name:           primary
State:          Running
IPv4:           192.168.64.2
Release:        Ubuntu 18.04.3 LTS
Image hash:     a720c34066dc (Ubuntu 18.04 LTS)
Load:           0.00 0.01 0.00
Disk usage:     1.2G out of 4.7G
Memory usage:   75.4M out of 985.7M
Mounts:         /Users/kazus => Home
                    UID map: 501:default
                    GID map: 20:default
```

`multipass umount primary` では、すべての mount point が unmount 対象になる。
host 側の \$HOME を mount したい場合は、`multipass mount $HOME primary:Home` でいける。

### host からインスタンスへファイルをコピーする

host からインスタンスへファイルをコピーすることが可能。
内部的には、scp を使っている。ユーザーは、`ubuntu` ユーザーでコピーされる。

下記は、primary インスタンスの /tmp にファイルがコピーされる。

```
$ multipass transfer multipassd.log primary:/tmp
```


### ディスクイメージの配置先

作成された `primary` インスタンスのディスクイメージは下記のディレクトリに配置される:

* `/var/root/Library/Application\ Support/multipassd/vault/instances/primary/ubuntu-18.04-server-cloudimg-amd64.img`

作成されたディスクイメージファイルの情報を qemu-img コマンドで確認してみる。
イメージファイルは、`file format: qcow2` で作成され、`virtual size: 5.0G` に対し `disk size: 1.2G` となっていることから、sparse file として作成されている事などがわかる:

```sh
$ /Library/Application\ Support/com.canonical.multipass/bin/qemu-img info /var/root/Library/Application\ Support/multipassd/vault/instances/primary/ubuntu-18.04-server-cloudimg-amd64.img
image: /var/root/Library/Application Support/multipassd/vault/instances/primary/ubuntu-18.04-server-cloudimg-amd64.img
file format: qcow2
virtual size: 5.0G (5368709120 bytes)
disk size: 1.4G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true
    refcount bits: 16
    corrupt: false
```

macOS の一般ユーザーは、/var/root 配下にアクセスできないので、`sudo -i` などで root 権限を得た状態でアクセスする必要がある。

### log の配置場所

log の配置場所は下記:

* multipassd のログ: /Library/Logs/Multipass/multipassd.log
* インスタンスのログ: /Library/Logs/Multipass/インスタンス名-hyperkit.log
* multipass コマンドの crash ログ: ~/Library/Logs/DiagnosticReports/multipass_*.crash

### インスタンスの起動/停止

`multipass launch` で作成されたインスタンスは、起動状態になる。
作成されたインスタンスは、start/stop で起動/停止をする。

* **停止**: `multipass stop インスタンス名`
* **起動**: `multipass start インスタンス名`
* **リスタート**: `multipass restart インスタンス名`

hyperkit を利用するインスタンスでは、`multipass suspend` は、サポートされていない。

### インスタンスの削除

インスタンスの削除は、インスタンスのリストから消す削除と、ディスクイメージまで消す purge がある。
完全に削除するには、purge まで実施する必要がある。

* `multipass delete インスタンス名` を実行した後に、`multipass purge` を実行する。
* `multipass delete インスタンス名 -p` でも同じ結果。

## Visual Studio Code での Remote - SSH 接続

VS Code Remote - SSH 拡張機能は、Ubuntu 64-bit x86 (16.04+, 18.04+) をサポートしている。
multipass で作成されるインスタンスは、Ubuntu 18.04.3 LTS なので、host からインスタンスに ssh 接続できるように設定しているのであれば特に問題なく利用可能。
multipass インスタンスの中では、docker なども利用できるので、VS Code - Remote Containers 拡張機能も利用可能。
~/.ssh/config を編集するモードも提供しているので、VS Code はお供にしておけば良いかと。 

## MicroK8s などのお供に

multipass を利用する事で、簡単に Ubuntu LTS インスタンスを作成できる事がわかりました。
次の一歩として、MicroK8s などを利用した、Kubernetes 環境を構築してみるなどがオススメされています。

[MicroK8s](https://microk8s.io) は、[コンテナ被害者をよりカジュアルに増やすためのソフトウェア](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0560)。
Ubuntuによって開発された Kubernetes のローカルディストリビューションであり、ローカルマシン上に Kubernetes シングルノードクラスタを簡単に構築できる。MicroK8s 自体は、Linux 専用に構築されている。
multipass を用いることで、Ubuntu インスタンス上に Kubernetes を構成する事が可能になるので、構築方法などが公開されている:

* [Kubernetes on Mac: how to set up](https://ubuntu.com/blog/kubernetes-on-mac-how-to-set-up)
* [https://ubuntu.com/blog/kubernetes-on-windows-how-to-set-up](https://ubuntu.com/blog/kubernetes-on-windows-how-to-set-up)


## その他

* Cisco AnyConnect で VPN 接続をすると、host とインスタンスの通信ができなくなる...
* 次は、VM Engine として VirtualBox を利用するネタを...