🐳

MBP移行直後に踏んだdocker buildのエラー

2025/01/31に公開

要約

新しいMBPに移行してdockerイメージをbuildしたところ、 これまで正常に動いていたCloud Runのジョブが exec format error となって処理が失敗しました。
buildのオプションとして--platform linux/amd64を指定してもダメでした。
DOCKER_BUILDKIT=0 を指定して BuildKit を無効にしてビルドしたところ、諸々インストールされて依存関係が改善されたらしくうまくいきました。

Docker BuildKitとマルチプラットフォーム対応についての教訓

Dockerを使えば、異なるCPUプラットフォーム(x86_64 と arm64 など)へ対応するイメージをビルドできます。しかし、一部の環境ではマルチプラットフォームビルドにより、以下のような問題が起こることがあります。

  • Cloud Run で exec format error が発生して起動しない
  • QEMUエミュレーションが正しく機能せずキャッシュ不整合が起きる

本記事では、私が遭遇した事例をもとに、解決策や注意点をまとめました。


背景

  • ベースイメージ: python:3.11-slim
  • Docker Buildx: --platform linux/amd64,linux/arm64 でマルチプラットフォームビルド
  • 環境: M4 Mac / Orbstack
  • 目的: Cloud Run 上でコンテナジョブを実行
  • 遭遇したエラー: exec format error

アーキテクチャ図 (簡易版)

以下は、マルチプラットフォームビルドを行う際の概念図です。

┌────────────────────┐
│   Host (ARM/M4)    │
│                    │
│  Docker BuildKit   │
└────────┬───────────┘
         │
         │(buildx build)
         ▼
┌─────────────────────┐
│  Docker Registry    │
│ (Artifact Registry) │
│  ├─ amd64 Image     │
│  └─ arm64 Image     │
└────────┬────────────┘
         │
         │(pull)
         ▼
┌───────────────────┐
│    Cloud Run      │
│   (linux/amd64)   │
│                   │
└───────────────────┘
  1. ビルドプロセス: M1ホスト上で docker buildx build --platform=... を実行すると、BuildKit + QEMU がエミュレーションを通じて amd64 / arm64 両方のイメージを構築。
  2. レジストリへプッシュ: それぞれのイメージが1つのマニフェスト(マルチプラットフォーム対応)としてRegistryに登録される。
  3. 実行環境 (例: Cloud Run): 必要に応じて適切なアーキテクチャのイメージをプルして実行。ただし、Cloud Run は linux/amd64 のみ対応なので、amd64 イメージが正しく生成されていないとエラーになる。

試した対策と学び

  1. キャッシュを破棄してクリーンビルド

    • docker buildx prune --all などでキャッシュ削除し、 --no-cache 付きで再ビルド。
    • キャッシュの不整合が原因で、過去の不完全なバイナリが再利用されるのを防ぐ。
  2. DOCKER_BUILDKIT=0 で依存を再インストール

    • 一度従来のビルドを使うことで、全モジュールが再インストールされ、キャッシュがリセットされる。
    • その後、docker buildx build に戻しても問題が解消することがある。
  3. FROM --platform=linux/amd64 python:3.11-slim の明示化

    • ベースイメージを amd64 に固定してビルドし、ターゲットが確実に amd64 になるようにする。
    • 複雑なアプリでは arm64 版とあわせてビルドしたい場合、プラットフォームごとにマルチステージ構成を検討。
  4. Orbstack を避け、Docker Desktop標準環境で再検証

    • Orbstack など特定の仮想化レイヤが原因の場合、公式 Docker Desktop で同手順を試すと成功するケースがある。
  5. マニフェストの確認

    • docker manifest inspect <イメージ>architectureamd64 / arm64 の2つが含まれているか確認。
  6. エントリポイントやファイル構成の再点検

    • exec format error はアーキテクチャ以外にも、CMDENTRYPOINT が存在しないファイルを指している、権限がない、などで発生することがある。
    • 単純なケアレスミスがないか要チェック。

補足リンク


まとめ

  • キャッシュ管理依存インストールの安定化 がとても重要
  • マルチプラットフォームビルドは便利だが、環境ごとの癖がある
  • まずは単一アーキテクチャで正常動作させ、次にマルチプラットフォーム化を試す
  • エラーが続く場合は BuildKit をオフにしてビルドし、問題を切り分け

このアプローチで何とか exec format error 問題を解決し、Cloud Run でのジョブ実行が成功しました。 もし同様の現象に悩んでいる方のヒントになれば幸いです。

Discussion