Dock Stay
M1/M2 Mac で amd64 イメージが動かない
動かない時

M1/M2 Mac で amd64 イメージが動かない

Apple Silicon で `exec format error` や `qemu: uncaught target signal` が出るときの切り分けと、`--platform`・`buildx`・`qemu-user-static` による対処。

M1/M2 Mac で amd64 イメージが動かない diagram

症状

  • Apple Silicon(M1/M2/M3)の Mac で docker run some/image すると exec /entrypoint.sh: exec format error が出る
  • 起動は通るが途中で qemu: uncaught target signal 11 (Segmentation fault) でクラッシュする
  • docker compose up では動くのに docker run だと落ちる(または逆)
  • GitHub Container Registry からプルした古めの社内イメージだけ動かない

原因

Apple Silicon の CPU は arm64 ですが、配布されているコンテナイメージの多くは依然として amd64 のみ、あるいはマルチアーキ対応でも arm64 バリアントの品質が低い場合があります。

  • exec format error: amd64 のみのイメージを arm64 の Docker でそのまま実行しようとした。エミュレータ(QEMU)が挿されていないと即死する
  • qemu: uncaught target signal: エミュレータ経由で amd64 バイナリを動かしているが、QEMU が特定の命令(AVX 命令や syscall)を正しく翻訳できずクラッシュ。Java や Node.js の JIT、ネイティブ拡張つきの Python パッケージで起きやすい
  • マルチアーキの落とし穴: レジストリ側のマニフェストリストが壊れている / arm64 イメージが amd64 のバイナリを含んでしまっている社内ビルドで誤動作

確認コマンド

bash
# ホストのアーキと Docker のデフォルトプラットフォーム
uname -m               # arm64
docker info | grep -i arch

# イメージがどのアーキに対応しているか(マニフェストリスト)
docker buildx imagetools inspect some/image:tag

# pull したローカルイメージのアーキ
docker image inspect some/image:tag --format '{{.Architecture}} {{.Os}} {{.Variant}}'

# 実行時のプロセスから見える arch(QEMU で動いているなら x86_64 と返る)
docker run --rm some/image:tag uname -m

# QEMU エミュレータが登録されているか
docker run --rm --privileged tonistiigi/binfmt
# 出力の "emulators" に qemu-x86_64 等が含まれているか確認

解決策

  • まず arm64 ネイティブのタグを探す: docker buildx imagetools inspect でマニフェストに linux/arm64 があるかを確認。公式イメージ(node, python, postgres 等)は大半がマルチアーキ対応済み。あるならそれを使うのが最速・最安定
  • 明示的に --platform=linux/amd64 を指定してエミュレーション実行: 社内イメージなどで arm64 ビルドがない場合。ただし性能は落ち、QEMU 起因のバグにはまるリスクあり
    docker run --platform=linux/amd64 some/image:tag
    
  • QEMU エミュレータを登録する: Docker Desktop for Mac には同梱されているが、初回のみ binfmt 経由で明示登録が必要なことがある
    docker run --privileged --rm tonistiigi/binfmt --install all
    
  • 自分でビルドするなら buildx でマルチアーキを一度に作る: CI でも使えてローカルと同じ成果物になる
    docker buildx create --use
    docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/you/app:v1 --push .
    
  • Compose の platform: を書く: チーム内で M1/Intel が混在しているときは各サービスに platform: linux/amd64(または linux/arm64)を明記し、環境差を封じる
  • QEMU で動かない JIT 問題の回避策: Node.js なら NODE_OPTIONS=--jitless、Java なら -XX:-UseCompiler で JIT を切ると起動する場合がある(根本解決ではなく暫定対応)