In the previous article of this series, we discussed how to get started using Docker to run our Go applications. Today, we’ll take a look at how to debug a Go application that runs inside a container.

Creating the Dockerfile for debugging

Using the same repository that we used in the last article, we can switch our branch to the debug branch.

Change Reposigory Branch

First, we’ll need to make a few changes to our Dockerfile.

# Compile stage
FROM golang:1.13.8 AS build-env

# Build Delve
RUN go get github.com/go-delve/delve/cmd/dlv

ADD . /dockerdev
WORKDIR /dockerdev

RUN go build -gcflags="all=-N -l" -o /server

# Final stage
FROM debian:buster

EXPOSE 8000 40000

WORKDIR /
COPY --from=build-env /go/bin/dlv /
COPY --from=build-env /server /

CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/server"]

These changes add Delve, the Go debugger, to the container image and instruct the container to start the application via Delve.

We also need to compile the application with special flags to enable a better debugging experience that results from turning off optimizations from the compiler. And finally, we’ll add both Delve and our binary to the image.

Changing the Run Configuration to allow the debugger to run

Before we start the debugging session, we also need to change how the container runs. In the Command line options section of the Docker container Run Configuration, we need to add the following value:

`--security-opt="apparmor=unconfined" --cap-add=SYS_PTRACE`

Debugging a Container with a Go container

This allows us to run a debugger inside the container at the cost of some security features, so it should only be used on debugging containers, but not production ones.

Pro tip: If you don't want to alter your original Docker container or the Run Configuration used for it, then you can create a duplicate Dockerfile and a duplicate Run Configuration. Use the Copy refactoring on the Dockerfile to copy it to a new file named Dockerfile.debug.

If you’ve never used the .debug extension before, the IDE will ask you how to associate the file. In the file pattern, use Dockerfile.debug and then select the Dockerfile type in the list that appears.

Copy Dockerfile to Dockerfile.debug

To start the debugger, place breakpoints as you normally would, then create a new Go Remote Run Configuration, and the debugger will start as usual.

As you’ve probably noticed, there's no need to add file path mapping manually to the IDE, as it will automatically know how to map the source code from the container to the host.

Note: This works as long as the binary is not stripped of debugging information.

Debugging Docker Container with GoLand

That's it for today. We’ve discussed creating and running Docker configurations, which allow us to debug Go applications inside containers. In our future articles, we'll look at how to start and debug our application using Docker Compose and Kubernetes. Please share your feedback with us, either in the comments section below, on our issue tracker, or by tweeting to us at our Twitter account.