しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

M2 MacBook Air で Dev Container を使った Azure Functions 開発が行えない問題を直す

これまでも何度か取り上げた Azure Functions の開発を Dev Container / GitHub Codespaces で行う方法ですが、公開している Dev Container Template が結構使われているみたいで作って良かったという気持ちです。

GitHub Codespaces を使う場合は例外ですが C# や Node.js 向けの場合は Dev Container を使わずに開発しているので、Dev Container を使うシナリオは専ら Python 向けという感じです。

これまで問題なく Dev Container Template を使って Python の Azure Functions 開発を行ってきたのですが、最近になって手持ちの M2 MacBook Air では func コマンド実行時に謎のエラーが出て失敗するようになりました。同じ定義を WSL 2 や GitHub Codespaces で動かしてもエラーにはなりません。

これまでの経験的に実行毎にメモリアクセス周りのエラーが発生するのは、エミュレーションが原因だと当たりが付いていたので Docker Desktop の設定で Rosetta を無効化して試すことにしました。

デフォルトでは以下のように Apple Virtualization framework と Rosetta が有効になっていますが、Rosetta を x86/x64 のエミュレーションに使わないようにチェックを外して試しました。

この設定で Rosetta を使わないように変更すると QEMU が使われるようになるようです。ちなみに Azure Functions 向けの Dev Container Template では Azure Functions Core Tools が linux-arm64 向けにリリースされていないため、明示的に linux/amd64 で動くように指定しています。

Rosetta を無効にすることで func コマンドは通るようになりましたが、肝心の func start コマンドを実行するとこれまでと同様に実行時エラーとなってしまい完全には解消できませんでした。

ということを Twitter で呟いてみると、Microsoft の中の人からヒントが飛んできました。この辺りには全く詳しくないので GPT-4o に解説してもらいましたがよくわかりませんでした。とにかく Rosetta はダブルマッピングを正しく扱えないため Rosetta 上で動いている場合には無効化するように変更されたようです。

Rosetta を無効化して QEMU を使っても失敗したのは気になりますが、とにかく .NET 9 の GA タイミングでは今回の問題は既に修正されているようです。

但し Azure Functions Core Tools は現在 .NET 8.0.8 を使ってビルドされているため、今回 macOS 上の Docker で実行しようとした際にエラーとなったという流れのようです。

今回の修正と同じ挙動になる設定は既に組み込まれているため、修正が組み込まれた Azure Functions Core Tools がリリースされるまでは、以下の Dockerfile のように環境変数に DOTNET_EnableWriteXorExecute=0 を追加することで今回の問題を回避可能でした。

FROM mcr.microsoft.com/devcontainers/python:1-3.11-bookworm

ENV DOTNET_EnableWriteXorExecute=0

この定義を使って Dev Container を再作成すると func start コマンドも問題なく動作しました。

ちなみに .NET 8.0.10 以降のバージョンに今回の修正がバックポートされているので、Azure Functions Core Tools のビルド環境が更新されていれば次のバージョンから修正される可能性が高いです。

根本的な解決方法としては Azure Functions Core Tools の linux-arm64 向けバージョンがリリースされることなのですが、何故か Windows と macOS 向けは Arm64 が用意されているのに Linux だけは滞っています。

Issue や Pull Request は上がっているので何時か対応されるのを期待するというのが現状です。