Creation/Using of Docker Image on Mac M1 for DFX SDK

I try to build an Docker container on Mac M1 with the DFX SDK for Motoko.
Here is my Dockerfile:

FROM --platform=linux/amd64 node:20-bookworm-slim

# Install a basic environment needed for our build tools
RUN apt-get -yq update && \
    apt-get -yqq install --no-install-recommends \
    curl \
    ca-certificates \
    build-essential \
    pkg-config \
    libssl-dev \
    llvm-dev \
    liblmdb-dev \
    clang \
    cmake \
    rsync \
    git \
    libunwind-dev && \
    apt-get autoremove -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
# Install dfx
RUN DFX_VERSION=0.24.1 DFXVM_INIT_YES=true sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
ENV PATH="/root/.local/share/dfx/bin:$PATH"

# Verify installation
RUN dfx --version

When I try to start the Docker image, I encounter several errors, and after a short time, the replica stops with an error:

My docker-compose.yaml file looks like:

version: '3.8'

services:
  icp-dev-env:
    image: icp-dev-env-mac:latest
    container_name: icp-dev-env
    platform: linux/amd64
    working_dir: /root/app
    volumes:
      - .:/root/app
    command: tail -f /dev/null

After starting the local replica, I face the following prints:

root@f3d3547dd3ea:~/app# dfx start --background
Running dfx start for version 0.24.1
Using the default configuration for the local shared network.
  Installed dfx 0.24.1 to cache.
<jemalloc>: MADV_DONTNEED does not work (memset will be used instead)
<jemalloc>: (This is the expected behaviour if you are running under QEMU)
Initialized replica.
Initialized HTTP gateway.
Replica API running on 127.0.0.1:4943

And after a deployment try I get the following sandbox error:

Deploying all canisters.
Creating canisters...
Creating canister backend...
Creating a wallet canister on the local network.
Sandbox pid 163 for canister Some(thread 'MR Batch ProcessorProcessInfo' panicked at rs/canister_sandbox/src/replica_controller/sandboxed_execution_controller.rs:902: { 34:
called `Result::unwrap()` on an `Err` value: ServerError
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
canister_id: Some(CanisterId(bnz7o-iuaaa-aaaaa-qaaaa-caiqemu: uncaught target signal 6 (Aborted) - core dumped
)), panic_on_failure: true }) exited unexpectedly with status Signaled(Pid(163), SIGKILL, false)
thread '<unnamed>' panicked at rs/canister_sandbox/src/launcher.rs:151:38:
called `Result::unwrap()` on an `Err` value: ServerError
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
qemu: uncaught target signal 6 (Aborted) - core dumped
Error: Failed while trying to deploy canisters.
Caused by: Failed while trying to register all canisters.
Caused by: Failed to create canister 'backend'.
Caused by: Failed to create wallet
Caused by: Failed while installing wasm.
Caused by: The replica returned an HTTP Error: Http Error: status 502 Bad Gateway, content type "text/plain; charset=utf-8", content: connection_failure: client error (SendRequest)

root@f3d3547dd3ea:~/app# <jemalloc>: MADV_DONTNEED does not work (memset will be used instead)
<jemalloc>: (This is the expected behaviour if you are running under QEMU)

How can I resolve this and successfully build a Docker image on an M1 Mac?
I’d appreciate any guidance in the right direction. Thank you!

1 Like

If I use the official Docker image with

docker pull Package icp-dev-env · GitHub

I still encounter the same error.

Hi @rbole,
I was not able to reproduce that behavior for the ghcr.io/dinfity/icp-dev-env:latest image; dfx started and deployed without errors for me. Could you please let me know on which docker version you are and what exact steps you use to build and attach to your container?

Hey, I use:

Mac OS: 15.1
Docker Desktop: 4.14.1
Engine: 20.10.21
Compose: v2.12.2

The steps are according: https://internetcomputer.org/docs/current/developer-docs/getting-started/install/ see the windows part:

docker pull ghcr.io/dfinity/icp-dev-env:latest
docker run --platform linux/x86_64 -dit ghcr.io/dfinity/icp-dev-env:latest
docker exec -it xxx bash
dfx start --background

After hours of searching, I found a way to use Lima on my Mac instead of Docker Desktop. This setup allows me to run the official image and successfully deploy a Motoko canister.

The only remaining issue is configuring access to the canisters over HTTP. I’m currently troubleshooting a network configuration problem to resolve this.

The replica in the Docker image is currently running on http://127.0.0.1:4943. Is there a way to bind it to http://0.0.0.0:4943 so that the service can be accessed externally from outside the container?

Huh, this is a wild solution :joy::

Finally I got it working with Lima and socat. Socat redirects the traffic inside of the Docker container from http://127.0.0.1:4944/ to http://127.0.0.1:4943. + A small modification in lima.conf to register the Port 4944 from the Mac host to the Lima VM.

portForwards:
- guestPort: 4944
  hostPort: 4944
  ignore: false

Now I can run the official Docker Image on an Mac A1 OS 15.1 and access the candid UI with the browser.

Now I have to make it a bit easier to use …

I think you took a more difficult path, because the Lima VM imposes additional restrictions on the OS. I came across a similar problem and the solution turned out to be quite simple:

In networks.json must be granted access from an external network:

{
  "local": {
    "bind": "0.0.0.0:4943",
    "replica": {
      "subnet_type": "application"
    }
  }
}

My docker-compose.yaml:

services:
  backend:
    image: ghcr.io/dfinity/icp-dev-env-slim:latest
    platform: linux/amd64
    working_dir: /app
    volumes:
      - ./networks.json:/root/.config/dfx/networks.json
      - ./:/app:rw
    entrypoint: ['sh', '-c', 'scripts/install.sh']
    healthcheck: 
      test: ['CMD', 'dfx', 'ping']
      interval: 15s
      timeout: 1m
    tty: true
    ports:
      - 4943:4943

I’ll attach the contents just in case install.sh in it, I run dfx and deploy the canisters

. $HOME/.local/share/dfx/env

# import identity
# ...

# start replica
dfx start --clean &> /app/replica.log

# pull and setup internet identity canister in local
dfx deps pull
dfx deps init --argument '(null)' internet-identity

# deploy canisters in local
dfx deps deploy

# keep waiting
tail -f /app/replica.log

I hope these examples will make it easier for others to take the hard way in backend containerization.