Skip to content

Strip Go binary symbols to reduce image size by ~30% #48

@onesyue

Description

@onesyue

Pulled the latest image on a fresh VPS today and noticed the binary layer is unusually large for a Go program of this scope:

$ docker images ghcr.io/cedar2025/xboard-node:latest --format "{{.Size}}"
106MB

$ docker history --human ghcr.io/cedar2025/xboard-node:latest
IMAGE          CREATED      CREATED BY                                  SIZE
b98acd23da75   9 days ago   CMD ["-c" "/etc/xboard-node/config.yml"]    0B
<missing>      9 days ago   ENTRYPOINT ["xboard-node"]                  0B
<missing>      9 days ago   WORKDIR /etc/xboard-node                    4.1kB
<missing>      9 days ago   RUN mkdir -p /etc/xboard-node               12.3kB
<missing>      9 days ago   COPY /build/xboard-node /usr/local/bin/...  66.8MB   ← here
<missing>      9 days ago   RUN apk add --no-cache ca-certificates ...  3.01MB
<missing>      12 days ago  CMD ["/bin/sh"]                             0B
<missing>      12 days ago  ADD alpine-minirootfs-3.20.10 ...           8.47MB

The 66.8 MB binary layer almost certainly carries DWARF debug info + Go symbol table that aren't needed at runtime. Stripping them in the build flags typically cuts a Go binary roughly in half:

go build -trimpath -ldflags="-s -w" -o build/xboard-node .

-s drops the symbol table, -w drops DWARF. -trimpath is a small bonus that removes local build paths from panics, which is also a minor info-leak fix.

Expected outcome on the published image: ~106MB → ~70-75MB (-30%). Not huge in absolute bytes but it adds up when you're rolling many nodes and the registry pull dominates the tail of docker compose pull && up -d.

This change should be safe:

  • Doesn't affect panic stack traces (function names are kept, only DWARF/symtab dropped)
  • Doesn't affect Go's built-in pprof CPU/memory profiling
  • Doesn't affect systemd journal output

If there's interest I can open a PR — just point me at the right path. The build step is COPY /build/xboard-node ..., so the change would be in whatever produces that artifact (presumably a GitHub Actions workflow, Dockerfile builder stage, or a Makefile target).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions