【App Service】exec /docker-entrypoint.sh: exec format error の原因調査と解決方法
自分のローカル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. DockerイメージをPullする
ローカルPCにDockerイメージを取得させます。
docker pull nginx
4. Dockerイメージにタグを付与する
Dockerイメージにタグ(名前空間)を付与します。
docker tag nginx ${ACR_NAME}.azurecr.io/tutorial/nginx:0.9.0
5. Dockerイメージをコンテナレジストリへ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つある
- スクリプトの実行権限がない
- スクリプトが破損している
- スクリプトの実行形式が間違っている
- 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を指定する
このパターンでは、Dockerfileを用意する必要があります。とは言いつつ、現場ではDockerfileによる運用がほぼ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