M1 MacのMultipassで動作するArm版Linux上でx86バイナリの動作環境を用意する

# はじめに

MacがIntel CPUからArm CPUに移行して久しいが、Intel CPU(x86_64/amd64)の動作環境がないと話が進められないものも多い。そこで、M1 Macでx86_64バイナリを動作可能なLinux環境を用意したい場合がたまによくある。
今回はArm CPUを採用したMac(M1 Mac)上でx86_64バイナリの実行環境を構築する。

# 所見

Arm環境でx86_64バイナリをサクッと動作確認したい場合には今回の方法が有効だが、x86_64の開発環境を用意したい場合はColimaなどを用いてx86_64版Linuxコンテナを動作させるほうが良いだろう。

https://qiita.com/rairaii/items/c59531998e21d44678a4


# Arm版Linux環境の用意

Arm CPUを採用したMac(M1 Mac)上でx86_64の開発環境を構築する方法は大きくわけて２つ存在する。

- x86_64版Linuxを動作させる
- Arm版Linux上でx86_64バイナリの実行をサポートする

今回はmultipassを使ってArm版Linux上でx86_64バイナリの実行をサポートする。

## Multipassとは

MultipassはUbuntuを開発しているCanonical Ltd.によって開発された軽量な仮想マシン管理ツールだ。主にLinux、macOS、Windows上でUbuntu仮想マシンを簡単に立ち上げ、管理するために使用される。Multipassは開発者がローカル環境でUbuntuのインスタンスを迅速に作成し、テストや実験を行うことを容易にすることを実現する。

M1 MacのMultipassはarm版のUbuntuの実行をサポートする。x86_64版のUbuntuを動作させることはできない。

## Multipassのインストール

[multipass公式サイト](https://multipass.run/install)からmultipassのパッケージをダウンロードしてインストールする

https://multipass.run/install



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/e214d4d8-a969-105f-7296-1a726634e40c.png)




![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/8bbd623c-66fd-13c6-8b18-6260ae92deee.png)

# MultipassでArm版Ubuntu22.04を起動する

Mac版Multipassの[公式チュートリアル](https://multipass.run/docs/mac-tutorial)を確認しながらUbuntu22.04を起動する

https://multipass.run/docs/mac-tutorial

## 実行可能なUbuntuのイメージ
Multipassで実行可能なUbuntuのイメージを確認する

```terminal
$ multipass find
Image                       Aliases           Version          Description
20.04                       focal             20240306         Ubuntu 20.04 LTS
22.04                       jammy,lts         20240308         Ubuntu 22.04 LTS
23.10                       mantic            20240307         Ubuntu 23.10

Blueprint                   Aliases           Version          Description
anbox-cloud-appliance                         latest           Anbox Cloud Appliance
charm-dev                                     latest           A development and testing environment for charmers
docker                                        0.4              A Docker environment with Portainer and related tools
jellyfin                                      latest           Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media.
minikube                                      latest           minikube is local Kubernetes
ros-noetic                                    0.1              A development and testing environment for ROS Noetic.
ros2-humble                                   0.1              A development and testing environment for ROS 2 Humble.
```

## Ubuntuの起動
デフォルトで作成されるインスタンスはディスクサイズやメモリサイズが小さいため明示的に指定して作成する。

```terminal
$ multipass launch 22.04  --cpus 6 --disk 20G --memory 8G
Launched: growing-shelduck
```

起動したUbuntuの状態を確認する。State:Runningと表示されUbuntu22.04が動作していることが確認できる。名前を明示的に指定しなかったため growing-shelduck という名前がMultipassによって自動で付けられた。

```terminal
$ mutipass ls
Name                    State             IPv4             Image
growing-shelduck        Running           192.168.106.3    Ubuntu 22.04 LTS
```

起動した growing-shelduck の情報を取得することでIPアドレスが192.168.106.3であることが確認できる。

```terminal
$ multipass info growing-shelduck
Name:           growing-shelduck
State:          Running
Snapshots:      0
IPv4:           192.168.106.3
Release:        Ubuntu 22.04.4 LTS
Image hash:     f19e2cf2d2e5 (Ubuntu 22.04 LTS)
CPU(s):         6
Load:           0.23 0.17 0.07
Disk usage:     1.6GiB out of 19.3GiB
Memory usage:   170.2MiB out of 7.7GiB
Mounts:         --
```

起動したUbuntuのシェルを起動する

```terminal
$ multipass shell growing-shelduck
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-97-generic aarch64)

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

  System information as of Sat Mar  9 08:50:12 JST 2024

  System load:             0.0
  Usage of /:              8.1% of 19.21GB
  Memory usage:            2%
  Swap usage:              0%
  Processes:               129
  Users logged in:         0
  IPv4 address for enp0s1: 192.168.106.3
  IPv6 address for enp0s1: fdbb:e645:f4df:3ab:5054:ff:feb2:8257


Expanded Security Maintenance for Applications is not enabled.

10 updates can be applied immediately.
9 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
```

# Ubuntu Desktop環境をインストール

[公式のGUI設定方法](https://multipass.run/docs/set-up-a-graphical-interface#heading--using-rdp)を参考にしつつデスクトップ環境を用意する。

```terminal
$ sudo apt update
$ sudo apt install -y ubuntu-desktop
```

デフォルトのubuntuユーザにパスワードを設定する。パスワード設定を忘れるとデスクトップ環境にログインできない。
```terminal
$ sudo passwd ubuntu
```

# リモートデスクトップでUbuntu上のアプリを実行する

xrdpをインストールする

```terminal
$ sudo apt install -y xrdp
```

MacであればMicrosoft Remote Desktopアプリでxrdpに接続する。接続するIPアドレスはmultipass infoコマンドで確認できる。今回の場合であれば192.168.106.3となる。

```
$ multipass info growing-shelduck
Name:           growing-shelduck
State:          Running
Snapshots:      0
IPv4:           192.168.106.3
Release:        Ubuntu 22.04.4 LTS
Image hash:     f19e2cf2d2e5 (Ubuntu 22.04 LTS)
CPU(s):         6
Load:           0.01 0.18 0.19
Disk usage:     5.4GiB out of 19.3GiB
Memory usage:   870.3MiB out of 7.7GiB
Mounts:         --
```

先ほど multipass info コマンドで調べたIPアドレス192.168.106.3を指定してRemote Desktopアプリでxrdpに接続する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/cd96df5f-f08c-3a8e-a3eb-78655c5f479a.png)

Chromiumをインストール
```terminal
$ sudo apt-get install chromium-browser
```

Chromiumを実行する

```terminal
$ chromium
```

[Speedometer3](https://browserbench.org/Speedometer3.0/)でウェブブラウザのパフォーマンスチェックを行う。なぜかMac上でネイティブ実行されるChromeブラウザよりもスコアが高い。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/add45fb3-af6c-6039-f611-fa570d45e14f.png)



ホストのMac上のChromeでSpeedometer3.0を実行した場合のスコア

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/e47f11bf-bc1f-fb92-6aac-63d0a1ae2ee5.png)



ホストのMac上のFirefoxでSpeedometer3.0を実行した場合のスコア

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/bb3ae5ac-b795-d342-92e7-0aafa0459b62.png)



# Rosettaを使ってx86版Chromeを動作させる

Multipassで動作しているArm版UbuntuにRosettaをインストールしてx86_64バイナリのアプリが実行可能な環境を整える。

## RosettaをUbuntuにインストール

[RosettaをMultipassで動作しているarm版のUbuntu22.04にインストールする](https://github.com/mrexodia/rosetta-multipass?tab=readme-ov-file)

### LinuxにRosettaを配置する
Linux用のrosettaの実行ファイルをUbuntu側にコピーして`/bin`に配置する。multipassコマンドで直接root権限が必要なディレクトリにコピーできないため、デフォルトユーザーのホームディレクトリにコピーしてから配置する。

```terminal:Mac
$ multipass transfer /Library/Apple/usr/libexec/oah/RosettaLinux/rosetta growing-shelduck:.
```

Ubuntu側で`/bin`にrosettaを配置する

```terminal:Ubuntu
$ sudo cp rosetta /bin/
$ ls -la /bin/rosetta
-rwxr-xr-x 1 root root 1595312 Mar 11 18:17 /bin/rosetta
```

rosettaの実行に必要なライブラリ等を用意する

```terminal:Ubuntu
$ sudo apt install libfuse2
$ sudo apt install python3-pip
$ sudo python3 -m pip install fusepy
$ git clone https://github.com/mrexodia/rosetta-multipass.git
```

rosettaを実行する環境を構築する (バックグラウンドで起動)

```terminal:Ubuntu
$ sudo python3 rosetta-multipass/mount-rosetta.py /bin/rosetta &
```

x86_64(amd64)バイナリの実行にrosettaを登録する

```terminal:
$ sudo apt install binfmt-support
$ sudo update-binfmts --install rosetta /bin/rosetta \
    --magic "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00" \
    --mask "\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff" \
    --credentials yes --preserve no --fix-binary no
```

x86_64形式のテスト用バイナリを実行する。
テスト用ファイルの内容をfileコマンで確認しx86_64形式の実行ファイルであることを確かめる。

```terminal:
$ file ./rosetta-multipass/tests/main-static
./rosetta-multipass/tests/main-static: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
```

x86_64形式のコマンドを実行する。
Rosettaを通したx86_64形式のコマンドの実行が確認できた。

```
$ /rosetta-multipass/tests/main-static
ERROR:RosettaFS:Unsupported ioctl(0x80806123) -> Probably the virtualization check changed
Hello from Rosetta!
```


### x86_64(amd64)のパッケージをサポートする

x86_64のパッケージのダウンロード先を登録する。

```terminal
$ sudo vi /etc/apt/sources.list
```

```config:/etc/apt/sources.list
...
#amd64
deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy main restricted
deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted
deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy universe
deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy-updates universe
deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy multiverse
deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy-updates multiverse
deb [arch=amd64] http://security.ubuntu.com/ubuntu jammy-security main restricted
deb [arch=amd64] http://security.ubuntu.com/ubuntu jammy-security universe
deb [arch=amd64] http://security.ubuntu.com/ubuntu jammy-security multiverse

```

x86_64アーキテクチャのサポートを追加する

```terminal
$ sudo dpkg --add-architecture amd64
$ sudo apt-get update
```

x86_64バイナリの`hello`コマンドをインストールして実行してみる
`Hello, world!`が表示されたら成功だ

```terminal
$ sudo apt-get install hello:amd64
$ which hello
/usr/bin/hello
$ file `which hello`
/usr/bin/hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ad4cc44d3974b5bca3bebbc40d2e03e320e9839a, for GNU/Linux 3.2.0, stripped
$ hello
Hello, world!
```

# x86版Chromeブラウザを動かす

x86版Chromeのパッケージを公式サイトからダウンロードしインストールし実行する

## x86版Chromeブラウザのインストール

Googleの公式サイトからUbuntu向けのx86形式のchromeのdebパッケージをダウンロードする。

```terminal: Chromeのパッケージのダウンロード
$ wget -r https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
```

```terminal: x86_64版Chromeをインストール
$ sudo apt -y install ~/Downloads/google-chrome-stable_current_amd64.deb
```


## x86版Chromeブラウザの動作確認

x86_64版Chromeを実行する

```terminal: 
$ google-chrome
```

`ps`コマンドで確認するとChromeブラウザがrosetta経由で動作していることが確認できる。

```terminal
$ ps aux | grep chrome
ubuntu      3459  5.6  4.9 35508596 398812 pts/0 Sl+  20:29   0:11 /bin/rosetta /opt/google/chrome/chrome
ubuntu      3466  0.0  0.0 34767756 4796 ?       Sl   20:29   0:00 /bin/rosetta /opt/google/chrome/chrome_crashpad_handler --monitor-self --monitor-self-annotation=ptype=crashpad-handler --database=/home/ubuntu/.config/google-chrome/Crash Reports --url=https://clients2.google.com/cr/report --annotation=channel= --annotation=lsb-release=Ubuntu 22.04.4 LTS --annotation=plat=Linux --annotation=prod=Chrome_Linux --annotation=ver=122.0.6261.111 --initial-client-fd=6 --shared-client-connection
ubuntu      3468  0.0  0.0 34759448 3992 ?       Sl   20:29   0:00 /bin/rosetta /opt/google/chrome/chrome_crashpad_handler --no-periodic-tasks --monitor-self-annotation=ptype=crashpad-handler --database=/home/ubuntu/.config/google-chrome/Crash Reports --url=https://clients2.google.com/cr/report --annotation=channel= --annotation=lsb-release=Ubuntu 22.04.4 LTS --annotation=plat=Linux --annotation=prod=Chrome_Linux --annotation=ver=122.0.6261.111 --initial-client-fd=5 --shared-client-connection
ubuntu      3474  0.0  0.8 35111860 66272 pts/0  S+   20:29   0:00 /bin/rosetta /opt/google/chrome/chrome --type=zygote --no-zygote-sandbox --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
ubuntu      3475  0.0  0.8 35111864 66516 pts/0  S+   20:29   0:00 /bin/rosetta /opt/google/chrome/chrome --type=zygote --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
ubuntu      3477  0.0  0.3 35111880 25228 pts/0  S+   20:29   0:00 /bin/rosetta /opt/google/chrome/chrome --type=zygote --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
ubuntu      3500  1.4  1.7 35123332 144036 pts/0 Sl+  20:29   0:02 /bin/rosetta /opt/google/chrome/chrome --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable --shared-files=v8_context_snapshot_data:100 --field-trial-handle=0,i,13569457430638291008,6707936131920262342,262144 --variations-seed-version=20240310-180200.292000
ubuntu      3509  0.1  0.7 35155376 63608 pts/0  Sl+  20:29   0:00 /bin/rosetta /opt/google/chrome/chrome --type=zygote --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
ubuntu      3585  3.8  2.2 35432860 180588 pts/0 Sl+  20:29   0:07 /bin/rosetta /opt/google/chrome/chrome --type=zygote --no-zygote-sandbox --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
ubuntu      3605  1.9  3.8 1187493552 309548 pts/0 Sl+ 20:29   0:03 /bin/rosetta /opt/google/chrome/chrome --type=zygote --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
ubuntu      3647 33.8  7.3 1187728328 595596 pts/0 Sl+ 20:29   1:03 /bin/rosetta /opt/google/chrome/chrome --type=zygote --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
ubuntu      3662  0.1  1.0 1187391160 83848 pts/0 Sl+ 20:29   0:00 /bin/rosetta /opt/google/chrome/chrome --type=zygote --crashpad-handler-pid=3466 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
ubuntu      3736  0.0  0.0   6416  1852 pts/1    S+   20:32   0:00 grep --color=auto chrome
```


[Speedometer3](https://browserbench.org/Speedometer3.0/)でウェブブラウザのパフォーマンスチェックを行う。arm版Chromiumの半分以下だがそこそこのパフォーマンスがでる。残念ながらx86版Chromeアプリを実行する環境は安定しておらず、YouTubeなどのWebサイトを閲覧する場合はレンダリングエンジンがフリーズしてしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/788397e8-57ed-7241-336e-3de75b6220ea.png)