PodmanでRosettaを使う

Red Hatでソリューションアーキテクトをしている田中司恩(@tnk4on)です。

Podman v5.1.0がリリースされました!

github.com

リリースノートの先頭にあるRosettaのサポートは私がPull Requestを書いて機能を実装したものです。

github.com

本記事ではこの「PodmanのRosettaのサポート」について紹介します。

(※本文の初出は執筆中のPodman Advanced Pod-02からの先出しで、そこから内容を抜粋したものとなります。)

-目次-


Rosettaとは

AppleのRosettaは、異なるプロセッサアーキテクチャ間の互換性を提供するためのバイナリトランスレーション技術です。初代Rosettaは*1、2006年にAppleがPowerPCからIntelのx86アーキテクチャに移行する際の支援技術として導入されました。 その後、Rosetta 2は*2、2020年にAppleがIntel x86から自社製のApple Silicon(ARMベース)への移行の際に導入されました。初代Rosetta、Rosetta 2のどちらもアプリケーションの移行を支援し、Mac上でのアプリケーションの実行を前提としています。

  • (初代)Rosetta:2006年リリース。PowerPC向けアプリをIntelチップのMac上で実行する目的
  • Rosetta 2:2020年リリース。Intel向けアプリをApple SiliconチップのMac上で実行する目的

その後リリースされたmacOS 13(macOS Ventura)では、Virtualization FrameworkがRosetta 2(以後、Rosetta)をサポートしました。 これによりApple Silicon搭載MacにおけるLinux仮想マシン(ARMアーキテクチャーのLinux)上でx86_64バイナリを実行できるようになりました*3。 Podman v5.1.0で追加されたRosettaのサポートはこの技術を利用します。

Podmanにおけるエミュレーションの利用

QEMUを使ったPodmanでのエミュレーションのアーキテクチャー
QEMUを使ったPodmanでのエミュレーションのアーキテクチャー

Podmanはコンテナの実行時やビルド時に--arch--platformをオプションを付けることで、実行元ホストのCPUアーキテクチャーとは異なるコンテナイメージを実行できます。 Podman machineでは、デフォルトでqemu-user-staticがインストールされているため、利用者はその内部の仕組みを意識することなくエミュレーションを使うことができます。

% arch 
arm64
% podman run --rm --arch amd64 ubi9 uname -m
x86_64
% podman build -t arch-test --platform linux/amd64 .  
% podman inspect arch-test --format {{.Architecture}} 
amd64

他にも、たとえばamd64のイメージしかないコンテナイメージを実行した場合に、アーキテクチャーの指定をしなくても自動でエミュレーションが行われる機能もあります。この場合は実行元ホストのCPUアーキテクチャーと異なっている警告が表示されます。

% podman run -d --name mssql mcr.microsoft.com/mssql/rhel/server
WARNING: image platform (linux/amd64) does not match the expected platform (linux/arm64)
a7f77aa2262fef96dbed32cf311ed2ab0327a4393dcdd8b2dc0c4ea3606838cb

このようにこれまでもエミュレーションの利用はできましたが、QEMU*4の機能を使ったCPUエミュレーションのためネイティブな環境での実行に比べて性能面での課題が多くあります。 ARMベースのApple Silicon MacにおけるRosettaのサポートは、この性能面の課題を解決する技術となります。

PodmanにおけるRosettaサポートの概要

Rosettaを使ったPodmanでのエミュレーションのアーキテクチャー
Rosettaを使ったPodmanでのエミュレーションのアーキテクチャー

Podman v5.1.0で実装されたRosettaのサポートにより、qemu-user-staticの代わりにRosettaを使用した高性能なx86_64エミュレーションができるようになりました。

このRosettaを使用したx86_64エミュレーションにより、ネイティブなx86_64環境で実行した場合と遜色ない性能をApple Silicon Mac上で利用できます。 手元でのSysbenchを使った簡易ベンチマークの結果では、Rosettaを使った場合はネイティブ環境と比較して85-6%程度の性能が出ました(QEMUの場合は4%程度)。QEMU vs Rosettaの場合は22倍以上の性能差となりました(Sysbenchのベンチマーク結果は本記事の最後に載せておきます)。 エミュレーション性能が向上したことでコンテナイメージのビルド時のdnf updatednf installで大量のパッケージのインストールなども、I/O処理性能の大幅な向上に伴い短時間で終了できるようになります。

またその他の利点として、QEMUのエミュレーションでは実行できないコンテナイメージを実行できる場合があります。ケースバイケースではありますが、QEMUではうまく実行できないコンテナイメージをRosettaで起動できる場合があります。ただし、その逆のケースもありますので、Rosetta経由で実行できない場合は後述するRosettaを無効化して対応ください。Rosettaを使うか使わないかはグローバルな設定となるため、個別のコンテナ単位で選択できない点はご注意ください。

実行方法

RosettaのサポートはPodman v5.1.0以降ではデフォルトで有効化されていますがいくつか前提条件があります。

前提条件:

  • Apple Silicon搭載Mac(M1、M2、M3チップのMacシリーズ、※執筆時点)
  • macOS 13(macOS Ventura)以降
  • Podman v5.1.0以降

Rosettaに対応するためには、Podman v5.1.0以降のpodman machineコマンドを使用してPodman machineを作成します。 既存のPodman v5.0のPodman machineがある場合は一度削除し再作成します。 なお、Podman v5.0のPodman machineをアップデートする方法は既知の問題として後述します。

既存のPodman machineを削除します。-fオプションをつけると確認画面を出さず即座に削除します。 ※ Podman machine内のすべてのデータは削除されますのでご注意ください

% podman machine rm -f

Podman machineを作成します。--nowオプションを付けると作成と同時にPodman machineを起動できます。

% podman machine init --now

この時点でmacOS上にRosettaがインストールされていない場合は、Rosettaのインストールを促すウィンドウが表示されます。 インストールするファイルは軽量で(数百KB程度)、インストール自体は一瞬で完了します。 その後続けてPodman machineの起動が実行されます。

Rosetta 2のインストール画面
Rosetta 2のインストール画面

--arch amd64を付けてコンテナを実行しエミュレーションが動作しているか確認します。

% uname -m
arm64
% podman run --rm --arch amd64 ubi9 uname -m
x86_64

Rosettaを手動でインストールする場合はsoftwareupdateコマンドを使用します。--agree-to-licenseオプションを付けることでライセンス契約同意のインタラクティブな手順を省略できます。

% softwareupdate --install-rosetta --agree-to-license

動作確認

Rosettaが使用できるかどうかはいくつかの確認方法があります。

podman machine inspectを使いPodman machineの設定を確認します。デフォルトで有効化されているのでtrueが自動で設定されます。

% podman machine inspect
[
     {
          "ConfigDir": {
               "Path": "/Users/shtanaka/.config/containers/podman/machine/applehv"
          },
...
          "Rootful": false,
          "Rosetta": true
     }
]

または、--formatオプションを使うことでJSONデータをパースできます

% podman machine inspect --format {{.Rosetta}}
true

podman machine inspectで表示されるのはあくまで設定上のフラグなので、Podman machine内で使用できる状態かどうかを確認します。

podman machine sshコマンドでPodman machineにログインしてコマンドを実行します。 /mnt/配下にrosettaとrosettadファイルがマウントされているか確認します。

% podman machine ssh
...
core@localhost:~$ ls -ld /mnt/rosetta*
-rwxr-xr-x. 1 core core 1660888 Feb 15 11:04 /mnt/rosetta
-rwxr-xr-x. 1 core core  298792 Feb 15 11:04 /mnt/rosettad

次に、binfmt_misc*5にrosettaが登録されているか確認します

core@localhost:~$ ls -ld /proc/sys/fs/binfmt_misc/rosetta
-rw-r--r--. 1 root root 0 May 21 09:30 /proc/sys/fs/binfmt_misc/rosetta

Podman machineにはデフォルトでqemu-user-staticがインストールされており、Rosetta以外のエミュレーションにも対応します。

core@localhost:~$ podman run --rm --arch s390x ubi9 uname -m
s390x

登録されているエミュレーション方式は/proc/sys/fs/binfmt_miscリストすると確認できます

core@localhost:~$ ls -l /proc/sys/fs/binfmt_misc
total 0
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-aarch64_be
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-alpha
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-armeb
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-hexagon
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-hppa
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-i386
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-i486
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-loongarch64
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-m68k
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-microblaze
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-microblazeel
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-mips
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-mips64
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-mips64el
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-mipsel
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-mipsn32
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-mipsn32el
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-or1k
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-ppc
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-ppc64
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-ppc64le
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-riscv32
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-riscv64
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-s390x
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-sh4
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-sh4eb
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-sparc
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-sparc32plus
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-sparc64
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-xtensa
-rw-r--r--. 1 root root 0 May 21 09:30 qemu-xtensaeb
--w-------. 1 root root 0 May 21 09:30 register
-rw-r--r--. 1 root root 0 May 21 09:30 rosetta
-rw-r--r--. 1 root root 0 May 21 09:30 status

Rosettaが有効化されている場合、排他的にqemu-x86_64は無効化されておりbinfmt_miscディレクトリには存在しません。逆にRosettaが無効化された場合はqemu-x86_64が登録されてQEMUによるx86_64バイナリの実行がエミュレーションに使用されます。

その他の確認方法としてプロセス上でRosettaが動作していることを確認する方法もあります。 Rosettaを使ったコンテナを実行し、podman topコマンドを使用してプロセスの状況を確認します。 podman top*6はpsコマンド互換のAIXフォーマットで出力されます。

% podman run --rm -d --name rosetta --arch amd64 ubi9 sleep inf
% podman top rosetta
USER        PID         PPID        %CPU        ELAPSED        TTY         TIME        COMMAND
root        1           0           0.000       11.303605881s  ?           0s          /mnt/rosetta /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep inf

Rosettaの無効化

Rosettaを無効化するにはcontainers.confのmachineセクションにrosetta=falseを追加します。 macOSの場合ユーザー固有の設定ファイルは$HOME/.config/containersに配置します。 containers.confにファイルがまだない場合は新規でファイルを作成してください。

% cat > ~/.config/containers/containers.conf <<EOF
[machine]
rosetta=false
EOF

または、$HOME/.config/containers.conf.dディレクトリに、*.confの任意のファイル名で特定の設定のみを分割管理できます。 containers.confにすでに既存の設定があり、変更を加えたくない場合などには便利な方法です。

% mkdir -p ~/.config/containers.conf.d
% cat > ~/.config/containers/containers.conf.d/machine.conf <<EOF
[machine]
rosetta=false
EOF

containers.confに変更を加えた場合はPodman machineを再起動して設定を反映します。

% podman machine stop
% podman machine start
% podman machine inspect --format {{.Rosetta}}
false

Rosettaを無効化すると/mnt/rosetta*のマウントはされなくなり、binfmt_miscにはrosettaの代わりにqemu-x86_64が登録されます

% podman machine ssh
...
core@localhost:~$ ls -ld /mnt/rosetta*
ls: cannot access '/mnt/rosetta*': No such file or directory
core@localhost:~$ ls -ld /proc/sys/fs/binfmt_misc/rosetta
ls: cannot access '/proc/sys/fs/binfmt_misc/rosetta': No such file or directory
core@localhost:~$ ls -ld /proc/sys/fs/binfmt_misc/qemu-x86_64
-rw-r--r--. 1 root root 0 May 22 03:07 /proc/sys/fs/binfmt_misc/qemu-x86_64

QEMUのエミュレーションを使った場合のpodman topコマンド出力ではqemu-x86_64-staticが使用されていることが確認できます。

% podman run --rm -d --name qemu --arch amd64 ubi9 sleep inf
% podman top qemu
USER        PID         PPID        %CPU        ELAPSED        TTY         TIME        COMMAND
root        1           0           0.000       29.883195833s  ?           0s          /usr/bin/qemu-x86_64-static /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep inf

containers.confを使ったRosettaの設定については、containers/commonのドキュメントに記載がありますので参考にしてください。

PodmanのGUIツールであるPodman DesktopにはRosettaを有効化/無効化設定する機能がまだありません。 機能追加のリクエストは上げたので、もしかしたら今後はGUIを通じて設定ができるようになるかもしれません。 github.com

Rosettaのアンインストール

RosettaをアンインストールするにはmacOSのシステム整合性保護(SIP)*7*8を無効化して、対象のファイルを手動で削除する必要があります。

SIPを無効化するには下記の手順を実行します。*9

  1. 再起動しリカバリーモードで起動します
  2. ユーティリティーメニューからターミナルを起動します
  3. csrutil disableコマンドを実行します
  4. 再起動します

SIPを無効化した状態でターミナルを起動し、該当のファイルを削除します。 Rosettaの関連ファイルのインストール場所を確認します。

% ls -l /Library/Apple/usr/lib/libRosettaAot.dylib 
% ls -l /Library/Apple/usr/libexec
% ls -l /Library/Apple/usr/share/rosetta

sudo付きでファイルとフォルダの削除を実行します。

% sudo rm -rf /Library/Apple/usr/lib/libRosettaAot.dylib
% sudo rm -rf /Library/Apple/usr/libexec
% sudo rm -rf /Library/Apple/usr/share/rosetta

Rosettaのファイルを削除したらSIPを有効化します。SIPを有効化する手順は無効化の手順と同様です。

  1. 再起動しリカバリーモードで起動します
  2. ユーティリティーメニューからターミナルを起動します
  3. csrutil enableコマンドを実行します
  4. 再起動します

既知の問題

Rosettaサポートを利用するためには、Podman CLI v5.1.0以上とPodman machine v5.1以上の組み合わせが必要です。 Podman v5.0で作成したPodman machineはPodman machine v5.0のイメージを使用しており、Rosettaには対応していません。 また、Podman machineの機能でv5.0からv5.1への移行機能は現時点でありません。 Podman machineはFedora CoreOS(FCOS)をベースとしており、FCOSの標準機能のrpm-ostree upgradeコマンドは使えるものの、 参照先のイメージが適切に設定されておらず、コマンドの実行が失敗します。 この問題はすでにIssueとして作成されています。

Can't upgrade core machine · Issue #22678 · containers/podman

現時点でのワークアラウンドとしては、podman machine os applyコマンドを使用し、Podman machine v5.1のイメージを指定することで更新は可能です。 ただし、この方法は公式な更新手段として提供されているわけではないため、あくまで一時的な処置としてご利用ください。 推奨方法としては、本記事で紹介したPodman machineの再作成となります。

まとめ

Podman v5.1.0で追加されたRosettaサポートについて解説しました。 macOSユーザー待望の機能がようやく正式に使えるようになりました。 これまでエミュレーションやマルチアーキテクチャーイメージに触れることがなかった方も、ぜひこの機会にいろいろ試してこの便利さを体感してください。

また、本記事では紹介できなかったPull Requestの作業を通じて実装したRosettaサポート周りの技術や苦労話などを、別の機会にディープダイブして解説したいと思います。

参考:Sysbenchの結果

arm64コンテナイメージで実行

出力結果を開く

[root@9a0ccd4c2d7f /]# sysbench cpu run
sysbench 1.0.20 (using system LuaJIT 2.1.0-beta3)

Running the test with following options:
Number of threads: 1
Initializing random number generator from current time


Prime numbers limit: 10000

Initializing worker threads...

Threads started!

CPU speed:
    events per second:  8406.67

General statistics:
    total time:                          10.0002s
    total number of events:              84075

Latency (ms):
         min:                                    0.12
         avg:                                    0.12
         max:                                    0.52
         95th percentile:                        0.13
         sum:                                 9982.11

Threads fairness:
    events (avg/stddev):           84075.0000/0.00
    execution time (avg/stddev):   9.9821/0.00

amd64コンテナイメージをRosettaを使って実行

出力結果を開く

[root@a693e721cbd3 /]# sysbench cpu run
sysbench 1.0.20 (using system LuaJIT 2.1.0-beta3)

Running the test with following options:
Number of threads: 1
Initializing random number generator from current time


Prime numbers limit: 10000

Initializing worker threads...

Threads started!

CPU speed:
    events per second:  7241.41

General statistics:
    total time:                          10.0006s
    total number of events:              72425

Latency (ms):
         min:                                    0.14
         avg:                                    0.14
         max:                                    0.28
         95th percentile:                        0.14
         sum:                                 9989.74

Threads fairness:
    events (avg/stddev):           72425.0000/0.00
    execution time (avg/stddev):   9.9897/0.00

amd64コンテナイメージをqemu-user-staticを使って実行

出力結果を開く

[root@1ef656b6323c /]# sysbench cpu run
sysbench 1.0.20 (using system LuaJIT 2.1.0-beta3)

Running the test with following options:
Number of threads: 1
Initializing random number generator from current time


Prime numbers limit: 10000

Initializing worker threads...

Threads started!

CPU speed:
    events per second:   323.51

General statistics:
    total time:                          10.0037s
    total number of events:              3237

Latency (ms):
         min:                                    3.05
         avg:                                    3.09
         max:                                    3.93
         95th percentile:                        3.19
         sum:                                 9996.01

Threads fairness:
    events (avg/stddev):           3237.0000/0.00
    execution time (avg/stddev):   9.9960/0.00

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。