Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ccampo133 committed Dec 10, 2022
1 parent 195eace commit 3b1f6ff
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 3 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/
.idea
6 changes: 6 additions & 0 deletions .run/remote-debug.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="remote-debug" type="GoRemoteDebugConfigurationType" factoryName="Go Remote" port="40000">
<option name="disconnectOption" value="ASK" />
<method v="2" />
</configuration>
</component>
32 changes: 32 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM golang:alpine3.17 AS build

WORKDIR /app

# Turning off Cgo is required to install Delve on Alpine.
ENV CGO_ENABLED=0

# Download and install the Delve debugger.
RUN go install github.com/go-delve/delve/cmd/dlv@latest

COPY go.mod .
COPY go.sum .

RUN go mod download

# You'll want to copy all your .go files here in a bigger project.
COPY main.go .

# Disable inlining and optimizations that can interfere with debugging.
RUN go build -gcflags "all=-N -l" -o /main main.go

FROM alpine:3.17

WORKDIR /

COPY --from=build /go/bin/dlv /bin/dlv
COPY --from=build /main /bin/app
COPY run.sh /bin/run.sh

EXPOSE 8080

ENTRYPOINT ["/bin/run.sh"]
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,75 @@
# go-docker-alpine-remote-debug
Example how to enable remote debugging using Delve for a Dockerized Go application.

A simple example on how to enable remote debugging using [Delve](https://github.com/go-delve/delve)
for a Go application running in an Alpine Linux Docker container.

## Background

This example contains a simple Go web application which returns `Hello world!`
on all HTTP requests to the endpoint `/hello`. The application is packaged into
a Docker image which includes the Delve debugger and can accept remote debugging
sessions on a user specified port.

Explore the code to see how this is accomplished :).

## Build and Run

Build the application and Docker image. This example utilizes a multi-stage
Docker build to download and install Delve, and compile the application:
```sh
$ docker build ./ -t debug-example:latest -f Dockerfile

[+] Building 9.5s (18/18) FINISHED
...
````

Run a container:
```sh
$ docker run \
--rm \
-p 8080:8080 \
-p 40000:40000 \
-e REMOTE_DEBUG_PORT=40000 \
-e REMOTE_DEBUG_PAUSE_ON_START=true \
debug-example:latest
Starting application with remote debugging on port 40000
Process execution will be paused until a debug session is attached
Executing command: /bin/dlv --listen=:40000 --headless=true --log --api-version=2 --accept-multiclient exec /bin/app --
API server listening at: [::]:40000
...
```
Once the container is running, you can establish a remote debugging session for
the application on port `40000` (feel free to change the port - there's nothing
special about `40000`, I just like that number). While you can always use the
[Delve command line client](https://github.com/go-delve/delve/blob/master/Documentation/cli/README.md)
to debug, I recommend using your IDE for this:
* [GoLand / IDEA](https://www.jetbrains.com/help/go/attach-to-running-go-processes-with-debugger.html)
* [Visual Studio Code](https://github.com/golang/vscode-go/blob/master/docs/debugging.md)
Note that because we set `REMOTE_DEBUG_PAUSE_ON_START`, the `main` function will
not be executed until a debug session is connected. This is particularly useful
if you want to debug an application from its first line of execution, however if
you don't need that, feel free to omit that environment variable and the
application will start normally.
Finally, set some breakpoints and make a request:
```sh
$ curl http://localhost:8080/hello
Hello world!
```
## GoLand/IDEA Run/Debug Configuration
The [`.run`](.run) directory contains a
[run/debug configuration](https://www.jetbrains.com/help/go/run-debug-configuration.html)
which you use for this example.
## References
* https://github.com/go-delve/delve/blob/master/Documentation/faq.md#how-do-i-use-delve-with-docker
* https://github.com/go-delve/delve/blob/master/Documentation/usage/dlv_exec.md
* https://www.jetbrains.com/help/go/attach-to-running-go-processes-with-debugger.html#attach-to-a-process-on-a-remote-machine
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/ccampo133/go-docker-alpine-remote-debug

go 1.19
Empty file added go.sum
Empty file.
21 changes: 21 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import (
"fmt"
"net/http"
)

func main() {
// This is a good spot for a breakpoint :)
http.HandleFunc("/hello", hello)
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}

func hello(w http.ResponseWriter, req *http.Request) {
// Try setting a breakpoint here too :)
if _, err := fmt.Fprintf(w, "Hello world!\n"); err != nil {
panic(err)
}
}
22 changes: 22 additions & 0 deletions run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env sh

# Ensure this script is executable!

cmd="/bin/app"
if [ "$REMOTE_DEBUG_PORT" ]; then
echo "Starting application with remote debugging on port $REMOTE_DEBUG_PORT"
dlvFlags="--listen=:$REMOTE_DEBUG_PORT --headless=true --log --api-version=2 --accept-multiclient"
execFlags=""
# Simply setting this environment variable is enough to force the debugger to
# pause on start --- we don't care about the value.
if [ "$REMOTE_DEBUG_PAUSE_ON_START" ]; then
echo "Process execution will be paused until a debug session is attached"
else
execFlags="$execFlags --continue"
fi
cmd="/bin/dlv $dlvFlags exec $cmd $execFlags -- "
fi

echo "Executing command: $cmd $*"

exec $cmd "$@"

0 comments on commit 3b1f6ff

Please sign in to comment.