Hello,
I made the switch recently from an x86 MacBook to Apple silicon (M3) and it seems to fail my Docker/Minikube workflow that perfectly worked under my old machine.
My app is a Phoenix app that is started in Minikube with a sidecar container (same pod) doing the migrations before the real app is started.
I’m using Elixir v1.15.7 with OTP v26.
I can’t speak to your specific migration error, but I’m surprised that you need to target x86 to build/run a Docker image in your local environment.
I’ve had to wrestle with cross-arch Elixir+Docker quirks when building images on my M1 Macbook to run on x86 hosts, but have had no issues building ARM images to run locally on my Macbook.
Tho I’m also using the k8s “cluster” built into Docker Desktop instead of minikube.
You’re absolutely right, I actually don’t need to build my Docker image with --platform linux/amd64.
I can now reproduce the same error with an arm64 image .
Cross-architecture support in docker is iffy at best since it uses QEMU in user-mode emulation mode, which:
Cannot handle JIT’ed code gracefully in all cases, as it is unaware of dual-mapped pages and cannot detect that code mapped that way has been modified. The +JMsingle true flag (implied by +JPperf true) works around the most egregious bugs, but not all.
Keeps multi-threaded code generation enabled even when this is known not to work due to differences in the target and host memory orders. Emulating ARM (weakly ordered) on x86 (strongly ordered) is fine, but the opposite is a recipe for disaster.
In short, don’t use cross-architecture docker unless you want to spice up your life with super-mysterious bugs.
Does the problem happen outside of a container? Does it work when disabling the JIT (--disable-jit configure flag)?
Seems like other folks who have run into this were inadvertently using erlang/elixir installations (or macOS system libs) originally compiled for x86 and/or have Rosetta emulation enabled in their terminal. When you switched to your M3 Macbook, did you use Apple’s migration tool to move things over from your Intel machine? Could be some lingering x86 packages from that.
I believe @jhogberg is referring to using the --disable-jit flag when configuring the Erlang build, which I have had good luck with when building cross-arch, but if you’re now using an ARM Docker image, I don’t think that’s the issue here.
[edit: I believe Rosetta emulation only comes into play while installing elixir/erlang packages, as it may result in x86 versions being installed rather than native ARM]
[edit: my suggestions about macOS sys libs is probably irrelevant to your Docker build ]
That to say that since I use the Apple Virtualization Framework + Rosetta enabled in Colima, QEMU is not in use in my workflow.
But using Colima stills results in the exact same error
I’ve never needed to do any extra config to build ARM images to run on my local ARM machine. I’ve only had to mess with that while building on ARM for x86 platform. Are you sure the Elixir base image you’re using is also ARM? For instance:
$ docker run --rm elixir:1.15-alpine uname -m
aarch64
But in case this is helpful (and maybe there’s a more elegant way to do this), you can copy the Erlang Dockerfile and update it to read:
…then build the Erlang image, then create a local copy of the Elixir Dockerfile to build FROM ... that local Erlang image in order to create your own JIT-disabled Elixir base image.
One more thing I’ll add: in some circumstances I’ve found it necessary to specify the platform in the Dockerfile (rather than with the docker build flag):
Okay, this feels like the real problem. Is it possible that there is a base image further down the stack which is x86? I believe this can come up when a base image doesn’t offer an ARM version.
Yes, the hexpm/elixir base image that I was using is x86 based.
Once I could try it with the linux/arm64 version of the image, the problem was gone, can you believe it?
Thanks a lot, I really appreciate your support!
[edit: and no more need for the ERL_FLAGS, as you said]