Dockerでコンテナを起動した直後にexec format errorが出るときは、まずエラーが指している実行ファイルと、そのファイルを動かす環境を対応付けます。Apple Siliconで作ったものを別のサーバーへ移した、別の段階で作成したバイナリーをコピーした、起動スクリプトを差し替えた、といった変更点を残してください。再ビルドを繰り返す前に、イメージ、同梱ファイル、起動命令のどこが合っていないかを分けます。
この記事は、公式仕様を基にした診断の進め方です。Docker Engineやコンテナを実行して障害を再現した結果ではありません。コマンドは確認例で、実際のイメージ名や対象ファイルへ置き換える必要があります。
目次
CPUの違いだけで原因を決めない
Linuxのexecveマニュアル(新しいタブで開く)では、ENOEXECの原因に、認識できない実行形式、異なるアーキテクチャー、その他の形式上の問題が挙げられています。したがって、このエラーだけで「ARM用をx86で動かした」と断定できません。
Dockerのマルチプラットフォーム説明(新しいタブで開く)も、実行環境に対応するイメージやエミュレーションなどが必要になることを説明しています。手元のMacのCPUだけを見るのでなく、接続先のDocker Engineがどこにあり、どのプラットフォームで動いているかを確認します。リモートのEngineを使っている場合、手元端末の情報をそのまま実行先の情報にはできません。
表は横にスクロールできます
| 確認対象 | 残す情報 | それだけでは分からないこと |
|---|---|---|
| 実行先 | 接続先Engine、OS、CPU構成 | 手元端末と同じかどうか |
| イメージ | IDまたはdigest、OS、architecture | 中へコピーした全ファイルの形式 |
| 起動対象 | エラーに出たパス、形式、生成元 | イメージのタグだけからの互換性 |
| 起動命令 | ENTRYPOINT、CMD、実行時の上書き | Dockerfileの記載が実際にも使われたか |
同じタグでも別の成果物を参照していれば比較が崩れます。調査対象は、失敗したときのイメージIDやdigestで固定してください。
ローカルのイメージと配布先の情報を分ける
手元へ取得済みのイメージは、docker image inspect(新しいタブで開く)で調べられます。次は、イメージのメタデータと起動命令を読む例です。イメージを起動するコマンドではありません。
docker image inspect IMAGE --format '{{.Os}}/{{.Architecture}}'
docker image inspect IMAGE --format '{{json .Config.Entrypoint}} {{json .Config.Cmd}}'
IMAGEは、実在する対象の名前またはIDへ置き換えます。この情報で確認できるのはイメージの宣言で、コピーされた実行ファイルの中身まで検査したことにはなりません。
配布先のタグに複数のプラットフォームがあるかは、docker buildx imagetools inspect(新しいタブで開く)でmanifestを確認できます。ただし、これはレジストリーへの接続を伴う確認です。ローカルの取得済みイメージと、後から同じタグで取得したmanifestを混ぜず、参照したdigestと確認時刻を記録します。
「配布タグにはarm64がある」という情報だけでは、今回のコンテナがその成果物を使った証拠にはなりません。失敗したイメージとmanifestの関係を確認してから、対応プラットフォームが足りないのかを判断します。
コピーしたバイナリーの生成先を追う
イメージのarchitectureが実行先に合っていても、ビルド途中で別のCPU向け実行ファイルをコピーしている可能性があります。AIがDockerfileを作った場合も、ベースイメージの選択とアプリのコンパイル先が一つの契約になっているかを読みます。
たとえば、最終イメージはlinux/arm64、コピー元の実行ファイルはlinux/amd64という組合せを考えます。これは説明用の仮定で、実際に再現した結果ではありません。この場合、最終イメージのメタデータだけを見ても、アプリ本体の不一致を見落とします。
確認するのは、どのビルド段階がそのファイルを作り、どのコンパイラー設定を使い、どのCOPY --fromで最終イメージへ入ったかです。ホスト上で同一の成果物を参照できるなら、fileなどで形式を確認する方法もあります。ソースコード側の似た名前のファイルを調べて、コンテナ内の実物を検査したことにしないでください。
Docker公式資料には、BUILDPLATFORMとTARGETPLATFORM等を使ったクロスコンパイルの説明があります。ビルドする機械と、成果物を動かす機械の指定を分け、使用言語のコンパイラーにも対象が渡っているかを照合します。--platformを付けるだけで、外部から持ち込んだ全バイナリーが自動変換されるとは扱いません。
起動スクリプトなら先頭行と呼び出し方を見る
起動対象がバイナリーでなくスクリプトなら、CPU構成の確認だけでは足りません。ファイル先頭、文字コード、改行、指定されたインタープリターのパス、実行方法を調べます。
Dockerfile reference(新しいタブで開く)には、ENTRYPOINTのexec形式とshell形式の違いが説明されています。たとえば["/app/start.sh"]で直接呼ぶ場合と、["/bin/sh", "/app/start.sh"]で読む場合を同じものとして比較しないでください。後者が動いたとしても、前者のファイル形式や先頭行の問題を解決した証拠にはなりません。
表は横にスクロールできます
| 観察したこと | 次に確かめるもの |
|---|---|
| エラーの対象がコンパイル済み実行ファイル | 生成時のOS・CPU指定と最終コピー元 |
対象が.sh等のスクリプト | 先頭行、インタープリター、実際の呼び出し方 |
| 同じソースでもCIだけ失敗 | CIの成果物、ビルド段階、対象プラットフォーム |
| 手元だけ動く | エミュレーションの有無を含む環境差 |
改行や実行権限の問題でも、表示されるエラーは条件により異なります。permission deniedやno such file or directoryまで、すべて同じCPU不一致として処理しません。エラー全文と対象パスを残し、該当する原因へ戻ります。
修正後は同じ成果物を実行先で確かめる
修正は、足りない対象向けイメージを用意する、コンパイル先を合わせる、起動ファイルの形式を直す、といった確認結果に対応するものに絞ります。診断のためだけに共有イメージのタグを上書きしたり、コンテナやvolumeを一括削除したりする必要はありません。
再確認では、修正前後のDockerfile差分、イメージID、実行先、起動対象を一組で残します。起動できた後は、アプリの最小の応答まで確認します。ただし、プロセスの起動成功とDB接続・業務処理の成功は別の確認です。DBの準備待ちなら、起動形式の問題を直し続けるのではなく、接続先とreadinessの診断へ移ります。
AIへ調査を依頼するときは、秘密情報を除いたエラー全文、イメージの識別子、該当するDockerfileの段階、生成元、実行先の構成を渡してください。「動くように全部書き換えて」より、どのファイルと環境が食い違うかを説明させる方が、修正の妥当性を確認できます。
確認した公式情報
確認日:2026-10-20。価格、性能、エミュレーション速度の比較は扱っていません。
