Open4

Mac で Podman を動かす。docker コマンドも使えるようにする

naonao

環境構築

Podman Desktop

Podman Desktop を入れておくと環境を簡単に作成できる。

https://podman-desktop.io/

Homebrew でもインストール可能。

brew install podman-desktop

アプリを起動し「Initialize and Start」をクリックすると環境を作成できる。Docker Desktop などで docker 環境を立ち上げてる場合は停止しておくことをおすすめする。

Lima

Podman Desktop 上から作成できる環境は現時点で x86_64 のエミュレーションに rosetta が利用できない。また qemu によるマシン構築の都合でファイル共有は virtio-9p を使って行われ、その関係で bind mount 利用時にファイルのモード変更で問題が起きたり、パフォーマンスがあまりよくなかったりする。

ので、仮想マシンを Lima ベースにするのが個人的なおすすめ。

Lima も Homebrew でインストールできる。

brew install lima

Lima マシンで virtiofs や rosetta を利用できるような設定を以下に紹介しておく。

~/.lima/_config/default.yaml を次のように作成する。[1]

# VirtualizationFramework を利用
vmType: "vz"
# virtiofsを使う
mountType: "virtiofs"

# 割当メモリの設定。未指定ならホストのメモリ量の半分
memory: "8GiB"

# ディスクサイズ。未指定なら 100 GiB に
disk: null

# x86_64 のエミュレーションに rosetta を利用する
rosetta:
  enabled: true
  binfmt: true

# ホームディレクトリを書き込み可能でマウントする(Docker Desktopと同様)
mounts:
  - location: "~"
    writable: true

# VirtualizationFramework有効なら以下も有効化できる。ゲストマシンとの疎通が速くなる
networks:
  - vzNAT: true

# rootlessテンプレートを使うなら、pastaの設定を有効化しておくのがおすすめ
provision:
  - mode: system
    script: |
      #!/bin/bash
      set -Eeux -o pipefail

      # ログを見られるように
      # see: https://github.com/containers/podman/issues/15159#issuecomment-1203851953
      sudo usermod -a -G systemd-journal {{.User}}

  - mode: system
    script: |
      #!/bin/bash
      set -Eeux -o pipefail

      if [[ -e /etc/binfmt.d/qemu-x86_64-static.conf ]] ; then
        exit 0
      fi

      # fedora アップデート時に rosetta が使えなくなる問題を防ぐ
      # https://github.com/containers/podman/pull/21670#issuecomment-2014694173
      ln -s /dev/null /etc/binfmt.d/qemu-x86_64-static.conf

  - mode: user
    script: |
      #!/bin/bash
      set -Eeux -o pipefail

      CONF=~/.config/containers/containers.conf.d/pasta.conf

      if [[ -e "$CONF" ]] ; then
        exit 0
      fi

      mkdir -p $(dirname "$CONF")

      cat <<-EOF > "$CONF"
      [network]
      default_rootless_network_cmd = "pasta"
      EOF

本当はホームディレクトリ(~) のwritable(書き込み可能)なマウントはテストされてないのでやるべきではない のだが、8ヶ月くらい使っていて特に問題が起きたことはない。

また上記サンプルでは podman の network 設定network.default_rootless_network_cmdpasta をセットした。pasta は rootless コンテナを立ち上げるときのネットワークをいい感じにやってくれるツールである。

少し補足すると、インターネットへの疎通が可能な veth(4)(仮想イーサネットデバイス)を作成するには特権が必要なので、このあたりをルートレスのまま上手く取り回すためにこれまで slirp4netns が使われてきた。

ただ slirp4netns はパフォーマンスや疎通元の IP アドレスが取れないなどの課題があり、それらの課題を一定解消したのが pasta である。(かなりざっくりした説明なので詳しくはドキュメントを参照されたい)

network.default_rootless_network_cmd="pasta" を設定することで、ルートレスネットワークを作成するデフォルトのプログラムに pasta が使われるようになる。

Lima の起動・停止など

Lima には仮想マシンのテンプレートがいくつかある。Podman 用のテンプレートでは(仮想マシン上で)root 権限を使わない rootless なものと root 権限ありの rootful なものとがある。

以下は Lima のコマンド例。

# rootless 環境の作成
# マシン名が「podman」になる
limactl create template://podman

# rootful 環境の作成
# そのままだとマシン名が podman-rootful になるので `--name=podman` で名称変更している
limactl create --name=podman template://podman-rootful

# 仮想マシン起動
limactl start podman

# 仮想マシンにアクセス
limactl shell podman

# 仮想マシンは fedora ベースなので、dnf で環境のアップデートができる
limactl shell podman -- sudo dnf update -y

マシンが起動したらメッセージが現れるので、それに従って

podman system connection add lima-<マシン名> "unix://<マシンの場所>/sock/podman.sock"
podman system connection default lima-<マシン名>

のコマンドを実行すると、podman から利用できるようになる。

Lima マシンを Podman Desktop に認識させる

Lima のマシン名を podman にしておくと、Podman Desktop の Lima 拡張で認識してくれるようになる。
(コンテナやボリュームを Podman Desktop 上で確認できるようになる)

もし Podman Desktop に認識させるマシン名を変更したい場合は、Extention: Lima の設定から変更できる。

docker クライアントの利用

Podman は Docker 互換の REST API を提供しているため、Docker CLI も利用できる。[2]

Podman Desktop をインストールすると docker コマンドもインストールされる。
もしインストールされてないようなら設定の Extentions からインストールできるはず。
(Docker Desktop をインストールしている場合 docker コマンドもインストール済のため、あまり意識する必要はなさそう)

Podman Desktop で環境を構築していればそのまま docker コマンドを使ってコンテナを作成できるはずだが、Lima で環境を構築した場合、先程のマシン起動時のメッセージ

podman system connection add lima-<マシン名> "unix://<マシンの場所>/sock/podman.sock"
podman system connection default lima-<マシン名>

を確認し "unix://<マシンの場所>/sock/podman.sock"DOCKER_HOST 環境変数に指定することで、docker コマンドで利用できるようになる。

export DOCKER_HOST=unix://<マシンの場所>/sock/podman.sock

もしくは /var/run/docker.sock にシンボリックを作成してもよい[3] が、再起動すると消えるので、やるなら自動化した方がいいかも。

# もし既にあるなら削除
sudo rm /var/run/docker.sock
# シンボリックリンクを作成
sudo ln -s /<マシンの場所>/sock/podman.sock /var/run/docker.sock

もちろん docker context に設定する形でも可能。こちらの場合、Docker Desktop の環境を残しながら切り替えて使える。

docker context create lima-<マシン名> --docker "host=unix://<マシンの場所>/sock/podman.sock"
docker context use lima-<マシン名>

# context 一覧を確認
docker context list
# 利用する context の切り替え(default に切り替えている)
docker context use default

buildkit の無効化

docker がイメージのビルドにデフォルトで使う buildkit はサポートされていない。ので無効化しておかないと、イメージをビルドするときに失敗する。buildkit は環境変数で無効化できる。

# buildkit の無効化
export DOCKER_BUILDKIT=0
脚注
  1. 詳しくは デフォルトテンプレート のコメントを参照されたい ↩︎

  2. docker compose も利用できる ↩︎

  3. Podman Desktop 上から環境を作成するとシンボリックは自動で作成される ↩︎

naonao

Shion さんにアドバイスいただいていた applehv + rosetta な手順を自分で試したときのメモを整理しておいておく。

https://twitter.com/tnk4on/status/1754398083436421134

仮想マシン設定

~/.config/containers/containers.conf に以下を追加。環境変数 CONTAINERS_MACHINE_PROVIDER=applehv を設定するのと同様の設定になる。

[machine]
  provider = "applehv"

↑の設定は podman v5 でデフォルトになるらしい

マシン作成

podman machine init

↑必要なら CPU コア数(--cpus)やメモリ(--memory)などを設定する

起動設定

仮想マシン起動前に、vfkit に渡すフラグを追加し、rosetta を利用できるようにする。

ドキュメント:

https://github.com/crc-org/vfkit/blob/452c2e07fd22987295e33732ea21fc220589c805/doc/usage.md?plain=1#L326

具体的には、

~/.config/containers/podman/machine/applehv/podman-machine-default.json (仮想マシンの設定ファイル)の .Vfkit.VirtualMachine.devices に以下を追加する。

    {
     "kind": "rosetta",
     "MountTag": "rosetta",
     "InstallRosetta": true
    }

マシン起動

podman machine start

マシン内の設定

仮想マシンが起動したら podman machine ssh でログインする

rosetta のマウント

/etc/systemd/system/var-mnt.mount に以下を作成し、マシン起動時に rosetta をマウントするようにする。

[Unit]
Description=Mount Rosetta
Before=systemd-binfmt.service

[Mount]
What=rosetta
Where=/var/mnt
Type=virtiofs
Options=context=system_u:object_r:container_runtime_exec_t:s0

[Install]
WantedBy=multi-user.target

systemd unit 追加直後は手動でマウント

sudo systemctl daemon-reload
sudo systemctl enable --now var-mnt.mount

rosetta を binfmt (エミュレーションに使う)に登録。

sudo sh -c "echo ':rosetta:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/mnt/rosetta:F' > /etc/binfmt.d/rosetta.conf"

# qemu による x86_64 エミュレーションは無効化しておく
sudo ln -s /dev/null /etc/binfmt.d/qemu-x86_64-static.conf

# binfmt 再起動
sudo systemctl restart systemd-binfmt.service

以下はおまけ

ルートレスコンテナでポート番号 80 まで公開可能にする


sudo sh -c "echo 'net.ipv4.ip_unprivileged_port_start=80' > /etc/sysctl.d/00-port-80.conf"
sudo sysctl --system

rootless コンテナで pasta ネットワークを使う

~/.config/containers/containers.conf.d/pasta.conf に以下を設定

[network]
default_rootless_network_cmd = "pasta"
naonao

ちなみに applehv な環境では v4.9.2 時点で bind mount 時に :Z:z のフラグがないとエラーになった。

# 例
podman run -v ./hoge:foo:z

https://github.com/containers/podman/issues/21085

ただ、2024/2/7 時点の main HEAD のコミット 6b592bd4e46b では :Z:z のフラグなしでも動作した。(以下修正によるものと思われる)

https://github.com/containers/podman/pull/21297
https://github.com/containers/podman/pull/21320


v5.0.0 がリリースされ、rosetta も標準で有効になれば macOS 上の podman の使いやすさが格段に上がりそう。布教を本格化したい(?)