Docker で M1/M2/M3 Mac ビルドのイメージが本番・CI で動かない・エラーになる:arm64/amd64 プラットフォーム不一致の解決法

公開日:2026-09-01/カテゴリ:Docker・開発環境・CI/CD・Apple Silicon/AnchorUp 技術ブログ

M1/M2/M3 Mac でビルドした Docker イメージが本番・CI で動かない症状

Apple Silicon(M1/M2/M3)の Mac を使っていて、こんな経験はありませんか?

このとき出ているエラーがこちら:

exec /bin/sh: exec format error

または:

WARNING: The requested image's platform (linux/arm64/v8) does not match
the detected host platform (linux/amd64/v2) and no specific platform was
requested

原因は1つ:Apple Silicon は arm64 アーキテクチャで、本番環境・CI は linux/amd64(x86_64)だから。

この記事では原因の仕組みから、実際の解決策(開発・CI・本番すべての設定)まで解説します。

なぜこの問題が起きるのか

CPU アーキテクチャが違う

環境 アーキテクチャ
M1/M2/M3 Mac arm64(aarch64)
Intel Mac amd64(x86_64)
GitHub Actions(ubuntu-latest) amd64
AWS ECS(デフォルト) amd64
Google Cloud Run(デフォルト) amd64
Fly.io(デフォルト) amd64

Docker はビルドしたマシンのアーキテクチャに合わせたバイナリを含むイメージを作ります。M1 Mac でビルドすると arm64 のバイナリが入ったイメージができます。このイメージを amd64 の環境で実行しようとすると、バイナリが実行できずに exec format error が発生します。

なぜローカルでは動くのか

Docker Desktop for Mac は QEMU エミュレーションを内蔵しており、arm64 マシン上でも amd64 イメージを(遅いですが)動かせます。そのため、手元では気づきません。

解決策1:docker build に --platform を指定する(最速)

ローカルでのビルドに --platform linux/amd64 を付けるだけで解決します。

# NG: プラットフォーム未指定(M1 Mac では arm64 イメージになる)
docker build -t myapp .

# OK: amd64 を明示指定
docker build --platform linux/amd64 -t myapp .

docker run でも同様に指定:

docker run --platform linux/amd64 myapp

QEMU エミュレーションが走るためローカルでの起動は少し遅くなりますが、CI・本番と同じ環境を手元で確認できます。

解決策2:Dockerfile に FROM --platform を書く

Dockerfile の先頭に --platform を固定することで、ビルドコマンドを打つ人が指定を忘れても常に amd64 になります。

# FROM の前に --platform を指定
FROM --platform=linux/amd64 node:20-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

CMD ["node", "dist/index.js"]

ただし、チームに Apple Silicon と Intel が混在していて将来的にマルチアーキテクチャ対応したい場合は後述の buildx 方式が柔軟です。

解決策3:docker buildx でマルチアーキテクチャビルド(推奨)

本番は amd64、ローカル開発は arm64 でネイティブ速度で動かしたい場合は、docker buildx でマルチプラットフォームイメージを作るのが最善です。

buildx のセットアップ

# ビルダーを作成して使用開始
docker buildx create --name mybuilder --use

# QEMU の設定(クロスプラットフォームビルドに必要)
docker run --privileged --rm tonistiigi/binfmt --install all

# ビルダーの確認
docker buildx inspect --bootstrap

マルチアーキテクチャビルド

# arm64 と amd64 の両方をビルドして Docker Hub にプッシュ
docker buildx build   --platform linux/amd64,linux/arm64   -t yourname/myapp:latest   --push   .

--push を付けるとビルド後に自動でレジストリ(Docker Hub 等)にプッシュされます。この1つのイメージタグを使えば、amd64 の本番サーバーでも arm64 の M1 Mac でも最適なバイナリが自動選択されます。

GitHub Actions の設定

CI で毎回 QEMU エミュレーションのビルドが走ると遅いので、GitHub Actions では公式アクションを使います。

# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: yourname/myapp:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

ポイント:

ネイティブモジュール(sharp、better-sqlite3)の落とし穴

sharp や better-sqlite3 など、C++ のネイティブアドオンを含む npm パッケージは特に注意が必要です。

よくある失敗

FROM node:20-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci  # ← ここで arm64 向けのバイナリがインストールされる
COPY . .

M1 Mac でビルドすると arm64 向けの .node ファイルがインストールされ、amd64 本番環境では動きません。

解決策:FROM に --platform を指定する

FROM --platform=linux/amd64 node:20-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci  # ← amd64 向けのバイナリがインストールされる
COPY . .

または buildx でビルドする場合、npm ci はクロスコンパイル環境で実行されるため、正しいアーキテクチャのバイナリが入ります。

docker-compose.yml での設定

docker-compose.yml で開発環境を管理している場合は platform キーを追加します。

# docker-compose.yml
services:
  app:
    build:
      context: .
      platform: linux/amd64  # 追加
    ports:
      - "3000:3000"

  db:
    image: postgres:16
    platform: linux/amd64  # イメージ指定のサービスにも追加
    environment:
      POSTGRES_PASSWORD: password

症状・原因・対策の一覧

症状 原因 対策
exec format error arm64 バイナリを amd64 で実行 --platform linux/amd64 を指定
CI でコンテナが起動しない M1 Mac でビルドした arm64 イメージ Dockerfile に FROM --platform
ネイティブモジュールが動かない アーキテクチャ違いの .node ファイル --platform 指定で再 npm install
ローカルでは動くのに本番で落ちる QEMU エミュレーションでローカル動作 buildx マルチアーキテクチャビルド
arm64 イメージで本番が遅い QEMU エミュレーション実行 amd64 専用または Graviton 検討

まとめ

Apple Silicon Mac でビルドした Docker イメージが CI・本番で動かない原因は、arm64 と amd64 のアーキテクチャ不一致です。

推奨する対処の優先順位:

  1. 即効薬: docker build --platform linux/amd64 を追加する
  2. チーム共有: Dockerfile に FROM --platform=linux/amd64 を書く
  3. 本番運用: docker buildx でマルチアーキテクチャイメージをビルドする
  4. CI 最適化: GitHub Actions で docker/setup-buildx-action + docker/build-push-action を使う

本番環境が AWS Graviton(arm64)や M-series Mac に統一されるチームであれば、逆に全環境を arm64 に揃えることでエミュレーションを排除できます。環境が混在するチームは buildx のマルチアーキテクチャビルドが最もメンテナンスしやすい選択肢です。

技術ブログの記事一覧へ