M1 MacでHeroku containerにデプロイしたら `Exec format error` と出て困った話
環境
- date: 2021/04/26 (事象が起きたのは2月後半ですが、本記事執筆日に再現することを確認)
- heroku cli: 7.52.0
- docker desktop: 3.3.1 (63152)
- docker engine: 20.10.5 build 55c4c88
先に結論
自分の場合は、armアーキテクチャ向けのDocker ImageをBuild/Pushしていたため、失敗していました。(Heroku側がx86なのでしょう、多分)
x86アーキテクチャ向けのDocker ImageをBuild/Pushすることで、正常に動作するようになりました。
方法は後述します。
はじめに
友人たちとオンラインでボードゲームをしている時に使うツールの開発[1]で、バックエンドをHerokuにしようとしていました。[2]
Herokuを使うのは約4年ぶりだったのですが、知らない間にDockerサポートが来ていたので、こりゃ楽だな、と高をくくっていました。
エラーとの遭遇
ローカルのDockerコンテナで動作することを確認して、いざデプロイといきます。
基本的に上記のページ通り、ただHerokuアプリ名は指定する、という形で、以下のコマンドを打っていました。(以下アプリ名はexample
とします)
$ heroku login
$ heroku container:login
$ heroku container:push web -a example
=> Your image has been successfully pushed. You can now release it with the 'container:release' command.
$ heroku container:release web -a example
=> Releasing images web to example... done
楽勝だったなぁと思いつつ、アプリのAPIを叩いても結果が帰ってこない。
久しぶりだったからポートの扱いでも間違えたかな、など思いつつ heroku logs -a example
でログを確認しました。
2021-04-26T13:08:01.635688+00:00 heroku[web.1]: Starting process with command `java -jar /work/app.jar`
2021-04-26T13:08:04.757975+00:00 app[web.1]: Error: Exec format error
2021-04-26T13:08:04.832667+00:00 heroku[web.1]: Process exited with status 126
2021-04-26T13:08:04.929320+00:00 heroku[web.1]: State changed from starting to crashed
見慣れないExec format error
で調べると、アーキテクチャが云々出てきたので、試行錯誤しているうちに、以下の解決策1で解決しました。
解決方法1. M1 Macでx86向けのDocker Imageをビルドする
色々試しているうち[3]に、x86向けのイメージじゃないからだと当てがついたので、x86向けイメージをどうにか作れないかと調べていたところ、マルチプラットフォームのイメージビルドなるものがありました。
それに従い以下のような形で、コマンドを打ち、無事成功しました。(以下タグに使うユーザ名をusernameとしています)
$ docker buildx build . --platform linux/amd64 -t username/example:latest
$ docker tag username/example registry.heroku.com/example/web
$ docker push registry.heroku.com/example/web
$ heroku container:release web -a example
解決方法2. x86のマシンを使う(CIなど)
自分では試していないのですが、本記事執筆にあたって再度調べてみると、別の方法でやっている方がおり、自分より賢いやり方だと思ったので、ここで紹介しておきます。
GitHub Actionsで行われていますね。
終わりに
自分はM1 Macでハマることは無いだろうと思っていたので、こんなこともあるんだなぁと思いました。
また、改めて調べてみて別の解決法を知ると視野が広がって、とても良い気持ちになります。
こういうのもアウトプットの副次的な効果かと思うと、ますますアウトプットしないとな、と思います。
最後に、本題とズレるのですが、尊敬する先輩の言葉で、「まずエラーログを読む」というのを身に染みるまで教わってよかったと思います。[4]
Discussion