Go Docker builds are slow

Hi Docker forums!

I have a weird one: Given the following basic Go web server—see http package - net/http - Go Packages page:

package main

import (
	"fmt"
	"log"
	"net/http"
)

const color = "blue7"

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello from app1 with COLOR=%s", color)
	})

	log.Fatal(http.ListenAndServe(":80", nil))
}

The build finishes in less than a second on my macOS system:

$ sw_vers
ProductName:		macOS
ProductVersion:		13.6
BuildVersion:		22G120
$ time go build app1.go

real	0m0.084s
user	0m0.117s
sys	0m0.183s

But with the following multi-stage Dockerfile, the build takes about 1 minute:

FROM golang AS builder
WORKDIR /code
COPY app1.go .
RUN go build app1.go

FROM debian
WORKDIR /app
COPY --from=builder /code/app1 .
EXPOSE 80
ENTRYPOINT ["/app/app1"]
$ time docker build -t app1 .
[+] Building 54.1s (13/13) FINISHED                        docker:desktop-linux
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 2B                                            0.0s
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 206B                                       0.0s
 => [internal] load metadata for docker.io/library/debian:latest           0.0s
 => [internal] load metadata for docker.io/library/golang:latest           0.0s
 => [builder 1/4] FROM docker.io/library/golang                            0.0s
 => [stage-1 1/3] FROM docker.io/library/debian                            0.0s
 => [internal] load build context                                          0.0s
 => => transferring context: 29B                                           0.0s
 => CACHED [builder 2/4] WORKDIR /code                                     0.0s
 => [builder 3/4] COPY app1.go .                                           0.0s
 => [builder 4/4] RUN go build app1.go                                    54.0s
 => CACHED [stage-1 2/3] WORKDIR /app                                      0.0s
 => [stage-1 3/3] COPY --from=builder /code/app1 .                         0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:53d6af9bafef973d6ebc5a8f2b2d7c2dd1bac94ff93d2  0.0s
 => => naming to docker.io/library/app1                                    0.0s

real	0m59.171s

And that’s with the following General settings and pretty generous Resource settings—like 6 CPU and 16 GB:

Question: Why is the Docker build taking so long? Am I missing something? Guess: The problem is related to macOS M1 chip.

Thanks for considering my issue!

You probably sat in front of the screen: which build step takes so long?

Not enough CPU or memory assigned to the virtual machine maybe? It took 7 seconds on my Mac

 => [internal] load build definition from Dockerfile                                                     0.0s
 => => transferring dockerfile: 207B                                                                     0.0s
 => [internal] load .dockerignore                                                                        0.0s
 => => transferring context: 2B                                                                          0.0s
 => [internal] load metadata for docker.io/library/debian:latest                                         1.8s
 => [internal] load metadata for docker.io/library/golang:latest                                         0.0s
 => [auth] library/debian:pull token for registry-1.docker.io                                            0.0s
 => [builder 1/4] FROM docker.io/library/golang                                                          0.0s
 => [stage-1 1/3] FROM docker.io/library/debian@sha256:eaace54a93d7b69c7c52bb8ddf9b3fcba0c106a497bc1fdb  0.0s
 => => resolve docker.io/library/debian@sha256:eaace54a93d7b69c7c52bb8ddf9b3fcba0c106a497bc1fdbb89a6299  0.0s
 => => sha256:eaace54a93d7b69c7c52bb8ddf9b3fcba0c106a497bc1fdbb89a6299cf945c63 1.85kB / 1.85kB           0.0s
 => => sha256:79e4d6b03e237637096d5a2ccf42aa60b2591505d87c78f237c6174c454b13f9 529B / 529B               0.0s
 => => sha256:5cd8b6447933486318a77c560bbd8562f7c9c4d31e0d7f65e2392fef8e79a590 1.48kB / 1.48kB           0.0s
 => [internal] load build context                                                                        0.0s
 => => transferring context: 302B                                                                        0.0s
 => [builder 2/4] WORKDIR /code                                                                          0.0s
 => [stage-1 2/3] WORKDIR /app                                                                           0.0s
 => [builder 3/4] COPY app1.go .                                                                         0.0s
 => [builder 4/4] RUN go build app1.go                                                                   7.3s
 => [stage-1 3/3] COPY --from=builder /code/app1 .                                                       0.0s
 => exporting to image                                                                                   0.0s
 => => exporting layers                                                                                  0.0s
 => => writing image sha256:bc110673d104f8bbd51b16f5111dd01cff2f52cf199815251de4da9d2528a4f5             0.0s
 => => naming to docker.io/library/app1

I assigned 3 cpu cores, 4 GB ram and 1GB swap.

You can find 54.0s on the right side in the line of go build. :slight_smile:

Using mobile, didn’t see it, sorry :blush:

Thank you for considering my issue! Dang, that’s rough to hear; it’s a bummer that after all these years I find myself on the other side of well it works on my computer lol. I wonder what the important difference is. What sort of mac do you have?

I cranked up all my CPU and memory to full—see screenshot. Surprisingly, no time improvement—see shell session and notice that I included my machine details.

$ docker build -t app1 .
[+] Building 51.3s (13/13) FINISHED                        docker:desktop-linux
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 206B                                       0.0s
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 2B                                            0.0s
 => [internal] load metadata for docker.io/library/debian:latest           0.0s
 => [internal] load metadata for docker.io/library/golang:latest           0.0s
 => [builder 1/4] FROM docker.io/library/golang                            0.0s
 => [internal] load build context                                          0.0s
 => => transferring context: 302B                                          0.0s
 => [stage-1 1/3] FROM docker.io/library/debian                            0.0s
 => CACHED [builder 2/4] WORKDIR /code                                     0.0s
 => [builder 3/4] COPY app1.go .                                           0.0s
 => [builder 4/4] RUN go build app1.go                                    51.2s
 => CACHED [stage-1 2/3] WORKDIR /app                                      0.0s
 => [stage-1 3/3] COPY --from=builder /code/app1 .                         0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:590ef784d9dc0aa6ba880f786c9a4ccddd94a065d220c  0.0s
 => => naming to docker.io/library/app1                                    0.0s

$ neofetch --off
max@mac2021.local
-----------------
OS: macOS 13.6 22G120 arm64
Host: MacBookPro18,1
Kernel: 22.6.0
Uptime: 2 days, 1 hour, 41 mins
Packages: 121 (brew)
Shell: bash 5.2.15
Resolution: 2056x1329
DE: Aqua
WM: Quartz Compositor
WM Theme: Blue (Dark)
Terminal: iTerm2
Terminal Font: Monaco 12
CPU: Apple M1 Pro
GPU: Apple M1 Pro
Memory: 3470MiB / 32768MiB

Edit: I kept at it and searched around my env vars for anything relevant and I notice that I set DOCKER_DEFAULT_PLATFORM=linux/amd64 env var; when I unset that env, then I went down to 3 seconds!

$ env | grep DOCKER
DOCKER_DEFAULT_PLATFORM=linux/amd64
DOCKER_CLI_HINTS=false
$ unset DOCKER_DEFAULT_PLATFORM
$ docker build -t app1 .
# ...
 => [builder 4/4] RUN go build app1.go                                     3.9s
# ...

Edit 2: Note: I also ran the softwareupdate --install-rosetta command based on the Install Docker Desktop on Mac | Docker Docs page; but that didn’t speed up my builds.

So case closed: Resolution: linux/amd64 Go builds under Docker on Apple M1 Pro (arm) are slow; avoid pinning the platform to linux/amd64 with the DOCKER_DEFAULT_PLATFORM=linux/amd64 env var.

People often say that when you use Docker everything runs the same way on every machine. That is not true it just gives you a better chance to run the same way on different machines. :slight_smile:

MacBook Air with the M1 chip

Emulation was my first guess, but then I saw golang was supported on arm, so I thought that couldn’t be the problem. Good that you found the env variable. Emulated processes are always at least a little slower depending on what has to be emulated.

Thank you for sharing your solution.

1 Like