How to Shrink Go Docker Images from 1GB to 16MB: Multi‑Stage Build Tips
This guide walks through nine incremental strategies—ranging from direct binary compilation to multi‑stage builds with Alpine and Scratch bases—to dramatically reduce the size of Go Docker images while preserving runtime performance and addressing practical trade‑offs.
1. Direct compilation (22 MB binary)
Compile the Go source for Linux on the host and copy the resulting binary into a minimal container.
set GOOS=linux
set GOARCH=amd64
go build main.goThe resulting image contains only the 22 MB executable.
2. Run source without compilation (≈941 MB)
Use the official golang image, copy the source code, and let the container execute go run at startup.
# Base image
FROM golang
MAINTAINER scoful
WORKDIR $GOPATH/kingProject
COPY . $GOPATH/kingProject
ENV GOPROXY https://goproxy.cn,direct
EXPOSE 8888
VOLUME ["/go/kingProject/config","/go/kingProject/log"]
ENTRYPOINT ["go","run","main.go"]The image size is roughly the same as the base golang image (≈941 MB) and startup is slow because compilation happens at runtime.
3. Compile inside the image (≈1.14 GB)
Build the binary during the image build and run the compiled binary.
# Base image
FROM golang
MAINTAINER scoful
WORKDIR $GOPATH/kingProject
COPY . $GOPATH/kingProject
ENV GOPROXY https://goproxy.cn,direct
RUN GOOS=linux GOARCH=amd64 go build main.go
EXPOSE 8888
VOLUME ["/go/kingProject/config","/go/kingProject/log"]
ENTRYPOINT ["./main"]The image grows to 1.14 GB because all Go dependencies are cached inside the image, but the container starts instantly.
4. Use an Alpine base (≈517 MB)
Switch the base image to golang:alpine, which is a minimal distribution.
# Base image
FROM golang:alpine
MAINTAINER scoful
WORKDIR $GOPATH/kingProject
COPY . $GOPATH/kingProject
ENV GOPROXY https://goproxy.cn,direct
RUN GOOS=linux GOARCH=amd64 go build main.go
EXPOSE 8888
VOLUME ["/go/kingProject/config","/go/kingProject/log"]
ENTRYPOINT ["./main"]The image size drops to 517 MB, about a 56 % reduction.
5. Multi‑stage build with Alpine runner (≈28.4 MB)
Separate the build environment (golang:alpine) from the runtime environment (plain Alpine) and copy only the compiled binary and needed config.
# Builder stage
FROM golang:alpine AS builder
MAINTAINER scoful
WORKDIR /go/kingProject
COPY . /go/kingProject
ENV GOPROXY https://goproxy.cn,direct
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build main.go
# Runner stage
FROM alpine AS runner
WORKDIR /go/kingProject
COPY --from=builder /go/kingProject/main .
COPY --from=builder /go/kingProject/config ./config
EXPOSE 8888
VOLUME ["/go/kingProject/config","/go/kingProject/log"]
ENTRYPOINT ["./main"]The resulting image is only 28.4 MB.
6. Multi‑stage with Scratch runner (≈22.8 MB)
Replace the Alpine runtime with the empty scratch image to eliminate all unnecessary layers.
# Builder (same as step 5)
FROM golang:alpine AS builder
... (same build commands) ...
# Runner
FROM scratch AS runner
WORKDIR /go/kingProject
COPY --from=builder /go/kingProject/main .
COPY --from=builder /go/kingProject/config ./config
EXPOSE 8888
VOLUME ["/go/kingProject/config","/go/kingProject/log"]
ENTRYPOINT ["./main"]The image shrinks to 22.8 MB, but a scratch container cannot be inspected with typical tools (no shell, no exec).
7. Strip binary symbols (≈16.3 MB)
Add -ldflags="-w -s" to the build command to remove debug information.
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" main.goThe final image size becomes 16.3 MB, a further 29 % reduction.
8. Final version with timezone configuration (still 16.3 MB)
Include a few extra RUN steps to set the container’s timezone to Asia/Shanghai.
RUN echo "https://mirrors.aliyun.com/alpine/v3.8/main/" > /etc/apk/repositories \
&& echo "https://mirrors.aliyun.com/alpine/v3.8/community/" >> /etc/apk/repositories \
&& apk add --no-cache tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo Asia/Shanghai > /etc/timezone \
&& apk del tzdataThe image size remains 16.3 MB while the container now reports the correct timezone.
9. Recommended recipe (Alpine runner, ≈21.9 MB)
Combine the multi‑stage approach with an Alpine runtime (instead of scratch) to keep the image small yet still usable for debugging.
# Builder
FROM golang:alpine AS builder
MAINTAINER scoful
WORKDIR /go/kingProject
COPY . /go/kingProject
ENV GOPROXY https://goproxy.cn,direct
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" main.go
# Runner (Alpine)
FROM alpine AS runner
WORKDIR /go/kingProject
COPY --from=builder /go/kingProject/main .
COPY --from=builder /go/kingProject/config ./config
# Set timezone
RUN echo "https://mirrors.aliyun.com/alpine/v3.8/main/" > /etc/apk/repositories \
&& echo "https://mirrors.aliyun.com/alpine/v3.8/community/" >> /etc/apk/repositories \
&& apk add --no-cache tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo Asia/Shanghai > /etc/timezone \
&& apk del tzdata
EXPOSE 8888
VOLUME ["/go/kingProject/config","/go/kingProject/log"]
ENTRYPOINT ["./main"]This configuration yields an image of about 21.9 MB, offering a good balance between minimal size and operability.
In summary, while scratch produces the tiniest image, its lack of utilities makes it impractical for most real‑world scenarios; the Alpine‑based multi‑stage build is therefore the recommended approach.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
