Intel Mac で Vagrant を使っていたのに Apple Silicon Mac (M1 Macなど) に移動する人にはGCEという選択肢があります

## 前文

Apple が Intel チップセットの Mac (Intel Mac) を新規で出さなくなって早数年、皆様無事に Apple Silicon (arm64) に脱出していますでしょうか？

「もうMacじゃなくて Windows/Linux にしたよ！」 という方もいらっしゃると思いますが、大半の方がいろんな事情でMacから離れられないことと思います。

私自身も築4年(2019)の Intel Mac を使っていますが、マジックキーボードの塗装はところどころ剥げ、`英数` のキートップが外れ、 `m` のキーがチャタリングを起こし [^1] 、バッテリーは `修理サービス推奨` といった無慈悲な警告を出しており、これ以上の使用にやや限界を感じております。

[^1]: チャタリングは高速なキー入力をキャンセルする [Unshaky](https://github.com/aahung/Unshaky) というアプリで凌いでいます。

そこで、そろそろM1/M2 Macあたりに腰を落ち着かせようかと思っているのですが……

### Apple Silicon に (今のところ)ちゃんと動く VirtualBox/Vagrant はおろか、amd64が満足に動かせる仮想化環境がない件

Apple Silicon Macに移動する際に一番ネックになるのが[VirtualBox](https://www.virtualbox.org/)や[Vagrant](https://www.vagrantup.com/)などの開発用の仮想環境をどうするか？という問題です。

私の場合ですと、特定案件のサーバ構築（[Ansible](https://www.ansible.com/)検証）のためにVagrantでamd64なサーバ一式立ち上げしていたり、一部ソフトウェアの動作検証のためにやや古いOSを動かさなければならなかったりするのですが、Apple Siliconでは現状、直接的にはamd64を動かすのは不可能な上、ARM版のOSであってもVirtualBoxのサポートは正式に始まっていません。


## GCE (Google Compute Engine) で仮想環境を動かそう！

そこで役に立つのが [**GCE**](https://cloud.google.com/compute?hl=ja) です。なぜGCEかというと、 **Nested Virtualization(VM内でVM立ち上げ)をサポートしている** からです。

AWSのEC2など通常のVMではすでにVM自体が仮想環境のために、その中でVMを立ち上げることはできませんが、 **GCEはVMの中にVMを立ち上げることができます。**

https://cloud.google.com/compute/docs/instances/nested-virtualization/overview?hl=ja

全てのインスタンスでNested Virtualizationをサポートしているわけではなく、 **[Linux上のGPU無しのIntelプロセッサ(Haswell以降)](https://cloud.google.com/compute/docs/instances/nested-virtualization/overview?hl=ja)のみでNested Virtualizationに対応しています。**

この機能を使うには、VM作成時にCLIからオプション(`--enable-nested-virtualization`)を追加して、 **VMのCPUのIntel VT-xフラグをオンにした状態で起動する必要** があります。（画面には項目が今のところないので、CLIを使うのがオススメ）

```bash
$ gcloud compute instances create VM_NAME \
  --zone=ZONE \
  --enable-nested-virtualization \
  --min-cpu-platform="Intel Haswell"
```

https://cloud.google.com/compute/docs/instances/nested-virtualization/enabling?hl=ja

作成済のVMであっても、CLI経由でVMの構成のXMLを書き換えて更新することにより、Intel VT-xフラグをオンにすることができます。（こちらはやや面倒）

フラグがオンになっている場合は下記コマンドで `vmx` の文字列が引っかかるはずです。

```bash
$ lscpu | grep vmx
Flags:
fpu ... vmx ... arch_capabilities
```

## GCEのVM上にVirtualBoxなど必要なツールを入れて動かそう

ここでは例として、以下のコマンドで Ubuntu 22.04 LTS (Jammy) を動かしています。

```bash
# デフォルトだとNested Virtualizationが遅くてしょうがないので、ある程度強いマシンを立てておく
# VM起動でディスクスペースが要り用なため、ディスクも大きめにしておく
$ gcloud compute instances create ksaitou-nested-vm-test \
  --enable-nested-virtualization \
  --zone=asia-northeast1-a \
  --custom-cpu=4 \
  --custom-memory=16GB \
  --boot-disk-size=300GB \
  --min-cpu-platform="Intel Haswell" \
  --image-project=ubuntu-os-cloud \
  --image-family=ubuntu-2204-lts
```

### VirtualBox/Vagrant のインストールと実行

下記コマンドで VirtualBox/Vagrant がインストール可能です。（詳しくは[公式のインストール手順](https://www.virtualbox.org/manual/ch02.html)を参照してください。）

```bash
## Virtualboxインストール
cat <<EOF > /etc/apt/sources.list.d/virtualbox.list
deb [arch=amd64 signed-by=/usr/share/keyrings/oracle-virtualbox-2016.gpg] https://download.virtualbox.org/virtualbox/debian jammy contrib
EOF

$ wget -O- https://www.virtualbox.org/download/oracle_vbox_2016.asc | sudo gpg --dearmor --yes --output /usr/share/keyrings/oracle-virtualbox-2016.gpg

$ apt update
$ apt -y install \
    virtualbox \
    virtualbox-guest-additions-iso \
    virtualbox-guest-utils-hwe \
    virtualbox-guest-x11-hwe

$ systemctl status virtualbox
● virtualbox.service - LSB: VirtualBox Linux kernel module
     Loaded: loaded (/etc/init.d/virtualbox; generated)
     Active: active (exited) since Wed 2023-08-02 05:48:03 UTC; 5s ago
       Docs: man:systemd-sysv-generator(8)
    Process: 17443 ExecStart=/etc/init.d/virtualbox start (code=exited, status=0/SUCCESS)
        CPU: 46ms

## Vagrantインストール
$ apt install -y vagrant
```

LinuxでVirtualBoxを扱う際もMacと同じく、VMにアサイン許可するIPアドレス帯をファイルで指定しておく必要があります。下記の例では `192.168.0.0/16` をVMにアサインすることを許可しています。

```bash
$ mkdir /etc/vbox/
$ cat <<EOF > /etc/vbox/networks.conf
* 192.168.0.0/16
EOF

$ systemctl restart virtualbox
```

ためしに Vagrant でいくつかVMをたててみましょう。

```ruby:Vagrantfile
Vagrant.configure("2") do |config|
    config.vm.define "test-vm-1" do |server|
      server.vm.box = "generic/ubuntu2004"
      server.vm.network "private_network", ip: "192.168.120.10"
      server.vm.provider "virtualbox" do |vb|
        vb.memory = "512"
      end
    end
end
```

きちんと立ち上がりますね！

```bash
$ vagrant up
Bringing machine 'test-vm-1' up with 'virtualbox' provider...
==> test-vm-1: Importing base box 'generic/ubuntu2004'...
...
==> test-vm-1: Checking for guest additions in VM...
==> test-vm-1: Configuring and enabling network interfaces...

$ vagrant ssh
vagrant@ubuntu2004:~$ 
```

### デスクトップ環境(VNC)のインストール

CLIで操作するOSのみインストールするのであれば上記で十分ですが、画面が欲しい時もあります。デスクトップも入れちゃいましょう。

```bash
$ apt install -y xfce4 tightvncserver
```

デスクトップ環境を入れればVirtualBoxをそのままGUIアプリとして触ることも可能です。

```bash
# (サーバ上/一般ユーザで実行) デスクトップ起動
$ vncserver :1

New 'X' desktop is ksaitou-nested-vm-test:1

Starting applications specified in /home/ksaitou/.vnc/xstartup
Log file is /home/ksaitou/.vnc/ksaitou-nested-vm-test:1.log

# 停止するには vncserver -kill :1 を実行すればOK
```

```bash
# (自マシン) localhost:5901 に向けてポートフォワーディング
$ gcloud compute ssh --zone "asia-northeast1-a" "ksaitou-nested-vm-test" -- -L 5901:localhost:5901
```

VNCソフト(VNC Viewerなど)から `localhost:5901` 宛に繋げば下記のようにデスクトップにつなぐことができます。VirtualBoxもデスクトップアプリとして利用可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1577592/cb849e34-54ae-a97a-7c88-718c6857d337.png)


## まとめ

以上のようにして、GCEでVirtualBoxやVagrantの起動ができます。Apple Silicon MacなどでVMを立ち上げて開発する際の助けになるでしょう。

ただ、**ちょっと起動etcが重いのが難点** です。なので、**やや強いVM性能で起動することをオススメします**。

開発機であれば常に起動する必要があるわけではないので、必要のない時にシャットダウンする仕組みにしておけばいいでしょう。その場合は休眠時はストレージのみの支払いになります。