normcore.dev

M1MacとLima環境でコンテナがARMでもIntel両方混在するdocker compose環境構築ログ

この方法が一番良いかどうかは環境次第だと思うけど残していく。

ざっくり

M1 Mac をホストとしてLimaのVMを立ち上げ、コンテナはARMでもIntelでもごちゃまぜで動かせる環境を構築してみる。
この記事用にdocker-compose.ymlをこしらえる元気がないので、環境構築まで。(すません

構成

  • Mac: M1 Pro
  • Lima: aarch64
    • dcoker compose系のコマンドに未実装なものもり、初期で入っているnerdctlは使用せずVM内にインストールする
  • Docker Container: IntelでもARMでも混在する環境

※VM上でARMを動かすにもQEMUでエミュレーションすることになるので、Dockerコンテナは可能な限りARMに寄せる。(LimaのFast mode)

Limaのイストール

lima-vm/lima: Linux virtual machines, on macOS (aka "Linux-on-Mac", "macOS subsystem for Linux", "containerd for Mac", unofficially) https://github.com/lima-vm/lima

$ brew install lima
$ which limactl
/opt/homebrew/bin/limactl
$ limactl --version
limactl version 0.7.4

Limaの設定ファイル作成

任意の場所にLimaの設定ファイルを新規作成

e.g.) ~/example_lima/lima_docker.yaml

内容は基本的に公式のexamples/docker.yamlで良い
あとは mounts > locationdocker-compose.ymlが格納されるであろうディレクトリを指定することで、プロジェクトがLimaのVM上にマウントされる。
LimaのVMのリソースを変更する方法もあるので、default.yamlを参考に変更していくのも良い。

# Example to use Docker instead of containerd & nerdctl
# $ limactl start ./lima_docker.yaml
# $ limactl shell docker docker run -it -v $HOME:$HOME --rm alpine

# To run `docker` on the host (assumes docker-cli is installed):
# $ export DOCKER_HOST=$(limactl list docker --format 'unix://{{.Dir}}/sock/docker.sock')
# $ docker ...

# This example requires Lima v0.8.0 or later
images:
  # Hint: run `limactl prune` to invalidate the "current" cache
  - location: 'https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.img'
    arch: 'x86_64'
  - location: 'https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-arm64.img'
    arch: 'aarch64'
mounts:
  - location: '~'
  - location: '/tmp/lima'
    writable: true
    # ☆任意のプロジェクトをマウント
  - location: '~/example_lima/projectx/'
    writable: true
# containerd is managed by Docker, not by Lima, so the values are set to false here.
containerd:
  system: false
  user: false
provision:
  - mode: system
    script: |
      #!/bin/sh
      sed -i 's/host.lima.internal.*/host.lima.internal host.docker.internal/' /etc/hosts
  - mode: system
    script: |
      #!/bin/bash
      set -eux -o pipefail
      command -v docker >/dev/null 2>&1 && exit 0
      export DEBIAN_FRONTEND=noninteractive
      curl -fsSL https://get.docker.com | sh
      # NOTE: you may remove the lines below, if you prefer to use rootful docker, not rootless
      systemctl disable --now docker
      apt-get install -y uidmap dbus-user-session
  - mode: user
    script: |
      #!/bin/bash
      set -eux -o pipefail
      systemctl --user start dbus
      dockerd-rootless-setuptool.sh install
      docker context use rootless
probes:
  - script: |
      #!/bin/bash
      set -eux -o pipefail
      if ! timeout 30s bash -c "until command -v docker >/dev/null 2>&1; do sleep 3; done"; then
        echo >&2 "docker is not installed yet"
        exit 1
      fi
      if ! timeout 30s bash -c "until pgrep rootlesskit; do sleep 3; done"; then
        echo >&2 "rootlesskit (used by rootless docker) is not running"
        exit 1
      fi
    hint: See "/var/log/cloud-init-output.log". in the guest
portForwards:
  - guestSocket: '/run/user/{{.UID}}/docker.sock'
    hostSocket: '{{.Dir}}/sock/docker.sock'
message: |
  To run `docker` on the host (assumes docker-cli is installed):
  $ export DOCKER_HOST=unix://{{.Dir}}/sock/docker.sock
  $ docker ...

LimaのVMを起動する

$ pwd
/Users/hogefuga/example_lima
$ limactl start ./lima_docker.yaml
# 何か聞かれるので、> Proceed with the default configuration を選択
? Creating an instance "lima_docker" Proceed with the default configuration

#.....

INFO[0193] [hostagent] The final requirement 1 of 1 is satisfied
INFO[0193] READY. Run `limactl shell lima_docker` to open the shell.
INFO[0193] To run `docker` on the host (assumes docker-cli is installed):
INFO[0193] $ export DOCKER_HOST=unix:///Users/hogefuga/.lima/lima_docker/sock/docker.sock
INFO[0193] $ docker ...

ホストの DOCKER_HOST の向き先を変更する

lima start したログの終盤に export DOCKER_HOST= うんぬんがあるので、そのまま実行すると Docker の向き先が変更される

# パスは上記ログを参照
export DOCKER_HOST=unix:///Users/hogefuga/.lima/lima_docker/sock/docker.sock

LimaのVM内に入る

立ち上がったらVMの中に入ってみる

$ limactl shell lima_docker
# ここでVMのアーキテクチャを確認
# M1でMacで起動した場合自動的にaarch64になっているはず。(Limaの設定ファイルで固定することも可能)
hogefuga@ubuntu:/Users/hogefuga/example_lima$ uname -m
aarch64

LimaVM内にbinfmtをインストール

ARMで動作するLimaのVM上に、Intelアーキテクチャのコンテナを起動するためbinfmtを導入する。

公式のドキュメントのIntel-on-ARM and ARM-on-Intelに近い。

hogefuga@ubuntu:/Users/hogefuga/example_lima$ sudo docker run --privileged --rm tonistiigi/binfmt --install all
Unable to find image 'tonistiigi/binfmt:latest' locally
latest: Pulling from tonistiigi/binfmt
66903ceeef2e: Pull complete
828e5112f0ea: Pull complete
Digest: sha256:8de6f2decb92e9001d094534bf8a92880c175bd5dfb4a9d8579f26f09821cfa2
Status: Downloaded newer image for tonistiigi/binfmt:latest
installing: arm OK
installing: s390x OK
installing: ppc64le OK
installing: riscv64 OK
installing: 386 OK
installing: mips64le OK
installing: mips64 OK
installing: amd64 OK
{
  "supported": [
    "linux/arm64",
    "linux/amd64",
    "linux/riscv64",
    "linux/ppc64le",
    "linux/s390x",
    "linux/386",
    "linux/mips64le",
    "linux/mips64",
    "linux/arm/v7",
    "linux/arm/v6"
  ],
  "emulators": [
    "qemu-arm",
    "qemu-i386",
    "qemu-mips64",
    "qemu-mips64el",
    "qemu-ppc64le",
    "qemu-riscv64",
    "qemu-s390x",
    "qemu-x86_64"
  ]
}

docker compose up

ホストPCへ戻り、docker compose up

$ cd projectx
$ pwd
/Users/hogefuga/example_lima/projectx
$ docker compose up

これで立ち上がるはずです。以上!