macOSでもWSLみたいなLinux環境を手に入れる

# macOSでもLinuxの仮想環境が欲しい時はある

Dockerを利用するなど、macOSであってもLinux環境が欲しい時はあります。

Microsoft365や、Adobe CCなど、macOSかWindowsでしか使えないプロプライエタリなソフトウェアを使う、開発もほとんどの場合macOSネイティブで問題ない、でもDockerも使う、などのように主たる作業はmacOSでやりながらLinuxもちょっと使わないといけないということは多々あります。

VirtualBoxなどを利用することによって、仮想環境にLinuxをインストールし利用することはできますが、WindowsにおけるWSL (Windows Subsystem for Linux) のようにネットワークやファイルシステムが統合されたように見える環境を構築するのは面倒です。

そこで、"macOS subsystem for Linux" のような世界を目指して開発されているのが [Lima](https://github.com/lima-vm/lima) です。

Limaを利用することで、WSLのような便利なLinux環境を利用することができ、またDocker Desktop for MacのようなDocker環境も構築することができます。

Limaを利用して、Linux環境を用意し、dockerをDocker Desktop for Macのように動かすところまでやってみます。

この記事の手順は Intel Mac および ARM Mac (M1 Mac) の両方で動作します。

# 大まかな手順

* Homebrew のインストール
* Lima のインストール
* LimaによるゲストVMの作成と起動
* macOSへ `docker` コマンドをインストール
* Dockerによるコンテナの起動と動作確認

# 実際の手順

## Homebrewのインストール

limaのインストールには [Homebrew](https://brew.sh/) を利用します。公式ページの手順に従って `brew` コマンドをインストールしてください。
すでに `brew` コマンドが利用できる場合にはこの手順は不要です。

```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

## Lima のインストール

```bash
brew install lima
```

## LimaによるゲストVMの作成と起動

Limaでは `limactl start` コマンドによりゲストVMの作成や起動ができます。

インストール作業に関してはWSLにおける `wsl --install` コマンドに相当します。

ゲストVMの作成時にはYAMLファイルによる定義を利用することができ、幾つかのサンプルが [Limaのリポジトリ/examples](https://github.com/lima-vm/lima/tree/master/examples) にあります。

今回は examples/docker.yaml を参考に、docker-composeとqemu-user-staticもインストールされるように [作ったYAML](https://github.com/chibiegg/lima-config/blob/master/docker.yaml) を利用します。

このYAMLファイルでは、UbuntuのベースイメージをダウンロードしゲストVMを作成し、Docker関連のセットアップがなされるような指示を書いています。

ゲストVMの作成時に使ったYAMLファイルのファイル名がそのままゲストVMの名前として利用されるため、一番よく使うゲストVMはdefaultという名前にしておきましょう。

```bash
curl -o default.yaml https://raw.githubusercontent.com/chibiegg/lima-config/master/docker.yaml
limactl start default.yaml
```

標準ではホストとおなじアーキテクチャ (M1の場合にはaarch64) のVMが出来上がります。
ほとんどの場合問題ないですが、x86_64 (amd64) のDockerイメージをビルドするときに問題が起きる場合もあります。
そういう場合には default.yaml の最後の行を `arch: default` から `arch: x86_64` に書き換えてからVMの作成をしてください。

筆者の環境では一部の `GOOS=linux GOARCH=amd64 go build` で segmentation fault が起きることがありました。


```bash:x86_64にする場合
curl -o default.yaml https://raw.githubusercontent.com/chibiegg/lima-config/master/docker.yaml
sed -i -e 's/arch: default/arch: x86_64/g' default.yaml
limactl start default.yaml
```

(参考 : [Lima で Intel on ARM やる](https://zenn.dev/sasasin/articles/46540925aecc4e) )


ただし、この方法で起動したVMは全体的に動作がかなり緩慢になります。使い分けをするほうが良さそうです。


すでに作成されているゲストVMの二回目以降の起動は `limactl start` のみでOKです。


Limaで起動しているゲストVMの中でコマンドを実行するには `lima` コマンドを利用します。

`lima` と引数なしで実行した場合にはゲストVMのシェルに入ることができます。

先程の設定ファイルによってdockerはすでにインストールされているため、以下のようなコマンドでdockerを利用することができます。

```bash
lima docker ps
```

## macOSへ `docker` コマンドをインストール

`lima` コマンド経由でdockerを利用できることは確認しましたが、macOSでビルド用のシェルスクリプトを実行する場合には、 `command not found: docker` となってしまいます。

そこで、macOSには `docker` コマンド (クライアント) のみをインストールし、ゲストVMのdockerを操作できるようにします。

```bash
brew install docker
sudo pip3 install docker-compose # docker-compose を利用する場合 (検証不足のため、うまくいかないかもしれない)

echo 'export DOCKER_HOST=ssh://limadocker:60006' >> ~/.zprofile

cat << EOS >> ~/.ssh/config
Host limadocker
  HostName localhost
  NoHostAuthenticationForLocalhost yes
  Port 60006
EOS

$SHELL -l
```
## Dockerによるコンテナの起動と動作確認

先程、dockerコマンドをインストールし、接続先をゲストVMにしましたので、dockerコマンドで操作が可能です。

```bash
docker run -it -p 8080:80 nginx:latest
```

WSLやDocker Desktopと同様に、ゲストVMへのアクセスは localhost で可能です。
http://localhost:8080 で起動したnginxにアクセスすることができます。

qemu-user-staticもゲストVMにインストールしているため、 `--platform linux/amd64` オプションも利用することができます。

```bash
docker build --platform linux/amd64 -t someimage .
```

`docker-compose` も `pip3` でインストールできていれば動くはずです。

# Docker Desktop for Macとの違い

Limaの制約により、1から1023番ポートまでの特権ポートは利用できません。

# その他の操作

### ゲストVMのシャットダウン

```bash
limactl stop
```

### ゲストVMの削除

```bash
limactl delete default
```

### default以外のゲストVMの利用

```bash
lima start instancename.yaml
LIMA_INSTANCE=instancename lima
lima stop instancename
lima delete instancename
```