Go Debugging
Raftt supports interactive Go debugging using JetBrains IDEs and VS Code.
To debug with Raftt, you must first install Raftt's IDE plugin. See here for installation instructions.
Configuration
To configure Go debugging you need to define two things -
- Where and when to compile your Go binary
- Add a builder container to the workload
- Define a pre-launch task
- Create a run/debug configuration
If you can compile in your app container
In most cases when using Go, the production version of the app container can't build the Go binary, so you need to go through the steps described in this guide. If your container can compile your binary, there's a much simpler configuration for debugging, described here.
You first need a "standard" debug configuration, as if you would debug the process locally. For help creating such a configuration, see JetBrains and VS Code docs. In addition, you need to configure the workload to be debugged. This is done using different methods in different IDEs.
For example, here you can see the configuration for debugging the shipping
service, as a part of our tutorial -
- JetBrains IDEs
- VS Code
The workload is defined using the RAFTT_WORKLOAD
environment variable.
The workload is defined in the workload
property of the raftt
attribute.
{
"name": "shipping",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/src/shippingservice",
"raftt": {
"workload": "shipping"
}
}
Add a builder container
The best way to let your env compile Go binaries without modifying your application container is by adding a builder container to the pod. This can be easily defined in your .raftt
file. Here you can see the configuration for adding a builder container to the shipping
service of our sample project -
# Fetch the shipping workload, assuming `resources` was imported earlier
shipping = resources.deployments["shipping"]
# Define the container and add it to the workload
builder = Container(yaml="""
name: builder
image: golang:1.21.3-alpine3.18
workingDir: /src
""")
shipping.spec.template.spec.containers.append(builder)
# Mount the source code and the compiled artifact folder to
# both the application container and the builder container
shipping_out = volume("shipping-out")
shipping.mount(repo_root.subpath("src/shippingservice"), "/src", container="builder")
shipping.mount(repo_root.subpath("src/shippingservice"), "/src")
shipping.mount(shipping_out, "/tmp/out", container="builder")
shipping.mount(shipping_out, "/app", init_on_rebuild=True)
We recommend the builder container to have the same underlying distribution as the application container. In the above example we chose Alpine, like the shipping
service.
The example shows a simple builder container that should be enough for most cases, but you need to make sure that it contains all the requirements to build your binary.
The rest of the configuration differs between different IDEs -
- JetBrains IDEs
- VS Code
Create a run/debug configuration
To debug with Raftt, you need to create a run/debug configuration of the type Go Executable with Raftt
. Most of the fields are equivalent to a standard Go run/debug config. The Executable Path
parameter is unique to debugging with Raftt and contains the path of the artifact created by the compilation (see below for the compilation definition). Then, add a single env var called RAFTT_WORKLOAD
stating the workload to debug.
Here you can see the configuration for the shipping
service of our sample project -
Debugging a sidecar container
To debug a sidecar container, add an additional env var - RAFTT_CONTAINER
, whose value is the debugged container name. If not stated, the selected container is the workload's main container - either the one annotated as default, or if no container is annotated - the first one in the manifest.
Create a before launch task
To recompile your code before every run/debug session, you need to define a before launch task in you debug configuration. Create a task of the type Run on Raftt Workload
and define what build script to run and where -
The command is go build -v -o /tmp/out/shipping -gcflags='all=-N -l' .
To easily share your run/debug configuration with the rest of the team, mark the "store as project file" checkbox and commit the new file, typically located under .run
, to the repo.
Create a preLaunchTask
To recompile your code before every run/debug session, you first need to define a task in the project's tasks.json
file (create it if it doesn't already exist). The task should define a build task in the builder container, using raftt sh
to the builder container. For example, here you can see the build task for the shipping container of our sample project -
{
"label": "build-shipping",
"type": "shell",
"command": "raftt sh shipping -c builder -- go build -v -o /tmp/out/shipping -gcflags='all=-N -l' .",
"group": "build",
"detail": "Build shipping service"
}
Once configured, you can trigger the build task without starting a run/debug session using Tasks: Run build commands
from the command palette, or using the cmd/ctrl+shift+B
keyboard shortcut.
Create a run/debug configuration
To debug with Raftt, start by defining a "standard" debug configuration in your launch.json
file for debugging a pre-built binary, a.k.a exec
mode. For help creating such a configuration, see VS Code docs. To this configuration, you need to assign the preLaunchTask
you defined in the previous section.
Then, add the raftt
attribute to the debug config. This attribute has a single property, stating the workload
to debug.
For example, here you can see the configuration for debugging the recommendations
service, as a part of our tutorial -
{
"name": "Shipping",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "/app/shipping",
"raftt": {
"workload": "shipping"
},
"preLaunchTask": "build-shipping"
}
Note the program
is the path to which the build artifact is mounted (or copied) in the application container.
Debugging a sidecar container
To debug a sidecar container, add a property to the raftt
attribute - container
, whose value is the debugged container name. If not stated, the selected container is the workload's main container - either the one annotated as default, or if no container is annotated - the first one in the manifest.
Here you can see how to debug the builder
container -
{
"name": "Shipping",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "/app/shipping",
"raftt": {
"workload": "shipping",
"container": "builder"
},
"preLaunchTask": "build-shipping"
}
To easily share your run/debug configuration with team members, make sure your launch.json
and tasks.json
files are committed to the project repo.
Debugging
Once you completed the configuration, you can experience fully-featured interactive debugging directly in your cluster, including breakpoints, stepping, watching and modifying variables, etc..
The method for starting a run/debug session with Raftt differs between different IDEs -
- JetBrains IDEs
- VS Code
To start a run/debug session with Raftt, use the Run with Raftt
or Debug with Raftt
blue buttons, or select these options from the Run
menu.
Starting a run/debug session with a configuration that has the raftt
attribute will automatically start a Raftt debugging session. This can be triggered using the debugging pane in the side bar, keyboard shortcuts or the command palette.