5

I can't remember where I saw it, I thought it was on Datadog or on NewRelic or maybe CloudFlare? but I remember someone mentioning that with Golang, they run release binaries in production (of course), and within their Docker containers, they also include a separate file containing debug symbols in case a crash occurs so as to be able to see what happened.

Background

I'm building and running in Docker with a Dockerfile like this:

# do all of our docker building in one image
FROM golang:latest as build

WORKDIR /usr/src/api

COPY go.mod go.sum ./
RUN go mod download

COPY . .

# build the application with relevant flags to make it completely self-contained for a scratch container
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags "-s" -a -installsuffix cgo -o app

# and then copy the built binary to an empty image
FROM ubuntu:latest

COPY --from=build /usr/src/api/app /
COPY --from=build /usr/src/api/config.defaults.json /config.json
COPY --from=build /usr/src/api/logo.png /

# default to running in a dev environment
ENV ENV=dev

EXPOSE 8080

ENTRYPOINT ["/bin/bash"]

If I don't use the flags above, the binary will fail to execute in alpine and scratch base images:

standard_init_linux.go:219: exec user process caused: no such file or directory

Running this in ubuntu:latest just works, so the above compile flags seem to fix the issue for alpine and scratch.

Question

With this environment in mind, is it possible to have go build emit debug symbols into a separate file to live alongside my static binary in the Docker image?

Naftuli Kay
  • 87,710
  • 93
  • 269
  • 411

2 Answers2

3

You don't need to use " -a -installsuffix cgo" flags when building with CGO_ENABLED=0 -- just setting the environment variable will do the trick.

You are building with "-ldflags -s", which is going to strip out all debug symbols and ELF symbol table information. Instead of doing that, do a regular build, archive that executable (in case you need the symbols later) and then remove symbols using strip. E.g.

 $ CGO_ENABLED=0 GOOS=linux go build -o app.withsymbols
 $ cp app.withsymbols /my/archive/for/debugging/production/issues
 $ strip app.withsymbols -o app.stripped
 $ cp app.stripped /production/bin

That should give you the behavior you're asking for (e.g. a small production binary, but also a backup binary with symbols for debugging problems in production).

2

Use go tool compile using -E flag to Debug symbol export. Is that what you need?

$ go tool compile -E *.go

Type:

go tool compile

for more help regarding how to use it and what are the options available.

Reference:

  1. https://golang.org/cmd/compile/
shmsr
  • 3,802
  • 2
  • 18
  • 29