☁️

【App Service】exec /docker-entrypoint.sh: exec format error の原因調査と解決方法

2024/05/04に公開

こんにちは、株式会社FIXER@名古屋オフィス所属の村上です。

自分のローカルPC(Appleシリコン端末)から検証目的にAzureのサービスへコンテナイメージをPushしたい時ありますよね。

私は適当なアプリをDockerコンテナ上で起動させたい時、Nginxをよく使うのですが、以下のエラーが出ました。
exec /docker-entrypoint.sh: exec format error

本ブログでは、Macユーザー(Appleシリコン)向けに上記のエラーが発生した場合の調査方法と解決方法を紹介します。

当時発生したエラーを再現する

Azure Container RegistryとApp Serviceは構築しといてください。
※ローカルPCではbash/zsh上で動作するコマンドを紹介しています。

1. 変数を定義する

ACR_NAME="<Azure Container Registry名を記載>"

2. プライベート コンテナレジストリへログインする

以下のコマンドを実行後、管理者ユーザーとパスワードを求められます。認証に成功すると「Login Succeeded」と表示されます。

docker login ${ACR_NAME}.azurecr.io

3. DokcerイメージをPullする

ローカルPCにDockerイメージを取得させます。

docker pull nginx

4. Dokcerイメージにタグを付与する

Dockerイメージにタグ(名前空間)を付与します。

docker tag nginx ${ACR_NAME}.azurecr.io/tutorial/nginx:0.9.0

5. DokcerイメージをコンテナレジストリへPushする

docker push ${ACR_NAME}.azurecr.io/tutorial/nginx:0.9.0

6. App Service上の参照イメージを更新する

App Serviceコンソールの「デプロイセンター」から先ほどPushしたDockerイメージを参照するように設定します。

7. 動作確認

ブラウザで実行してみました。 案の定エラーが出ましたね。 503エラーが出ています。

:( Application Error
If you are the application administrator, you can access the diagnostic resources.

原因調査

App Serviceに限らず、AzureのPaaSはMicrosoftによって簡単な調査をやってくれます。「問題の診断と解決」を開きます。 前段のブラウザに「Application Error」のエラーが表示されていたため、Application Logs を押下し、診断結果を見てみます。

表示結果は以下のとおりです。どのインスタンスでエラーが発生してて、サーバー上の振る舞いが一目できます。

Application Logs に表示されているログが致命的でコンテナ起動に失敗していることが予想できます。

exec /docker-entrypoint.sh: exec format error

考えられる要因は4つある

  1. スクリプトの実行権限がない
  2. スクリプトが破損している
  3. スクリプトの実行形式が間違っている
  4. Dockerコンテナの実行環境の問題

今回はDocker Hubで一般公開されているDockerイメージをデプロイしている関係上 1〜3はエラーの原因とは可能性が低いため「4. Dockerコンテナの実行環境の問題」を疑ってみます。

Dockerコンテナの実行環境を調べる

Dockerコンテナは、Dockerホストとコンテナ内のOSやアプリケーションのCPUアーキテクチャが異なると互換性エラーが発生します。

① Dockerホストの実行環境

App ServiceのコンテナにSSHして、CPUプロセッサ情報を確認してみます。
コマンドは lscpu を使用しました。

root@77aab04f7cbf4754ad81596ea66641ae:/home# lscpu
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
CPU family:          6
Model:               79
Model name:          Intel(R) Xeon(R) CPU E5-2673 v4 @ 2.30GHz
Hypervisor vendor:   Microsoft

Dockerホストでは、Intelのx86_64アーキテクチャを使用していることがわかりました。

② Dockerコンテナの実行環境

Azure Container Registry上のDockerイメージをローカルPC上にPullします。

docker pull ${ACR_NAME}.azurecr.io/tutorial/nginx:0.9.0

起動します。

docker run -it --rm -p 8080:80 ${ACR_NAME}.azurecr.io/tutorial/nginx:0.9.0

別タブを立ち上げ、起動したDockerコンテナにSSHするため、コンテナIDを確認します。

docker ps

CONTAINER ID   IMAGE                                                 COMMAND                   CREATED         STATUS         PORTS                  NAMES
799d865b5253   acrtechblog20240504.azurecr.io/tutorial/nginx:0.9.0   "/docker-entrypoint.…"   3 minutes ago   Up 3 minutes   0.0.0.0:8080->80/tcp   tender_ardinghelli

DockerコンテナへSSHします。※本ブログでは799d865b5253がコンテナIDになります。

docker exec -it <コンテナID> bash
root@799d865b5253:/# lscpu
Architecture:            aarch64
  CPU op-mode(s):        64-bit
  Byte Order:            Little Endian
Vendor ID:               Apple

Dockerコンテナでは、Appleのaarch64アーキテクチャを使用していることがわかりました。

調査結果

予想通り、互換性のないアーキテクチャ同士で構成されていたため、コンテナ起動に失敗していそうです。

CPUアーキテクチャ
Dockerホスト x86_64
Dockerコンテナ aarch64

x86_64はamd64ととintel64の総称です。

解決方法

Dockerホスト、つまりApp Service側の変更はできないためDockerコンテナのイメージをx86_64上で動作するものに変更する必要があります。

パターン① Buildのときにplatformを指定する

このパターンでは、Dokcerfileを用意する必要があります。とは言いつつ、現場ではDokcerfileによる運用がほぼ100%だと思うので基本的にはこちらの対応を実施します。このバターンは様々なブログで紹介されているため、割愛します。

パターン② pullのときにplatformを指定する

私のようなサクッとDockerコンテナを立てたい人向けです。

docker pull時にplatformを指定することもできます。

docker pull --platform=linux/amd64 nginx

あとは「当時発生したエラーを再現する」にて紹介した方法でDockerイメージの再PushとApp Serviceの更新を行います。

docker tag nginx ${ACR_NAME}.azurecr.io/tutorial/nginx:1.0.0

docker push ${ACR_NAME}.azurecr.io/tutorial/nginx:1.0.0

Nginxのスタート画面が表示されましたね👍

Discussion