Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework debug docs #3875

Merged
merged 2 commits into from
Mar 26, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 164 additions & 41 deletions docs/content/en/docs/workflows/debug.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,53 +9,30 @@ aliases: [/docs/how-tos/debug]
`skaffold debug` acts like `skaffold dev`, but it configures containers in pods
for debugging as required for each container's runtime technology.
The associated debugging ports are exposed and labelled so that they can be port-forwarded to the
local machine. Helper metadata is also added to allow IDEs to detect the debugging
configuration parameters.

## How It Works

`skaffold debug` examines the built artifacts to determine the underlying runtime technology.
Any Kubernetes manifest that references these artifacts are transformed to enable the runtime technology's
debugging functions.

`skaffold debug` uses a set of heuristics to identify the runtime technology.
The Kubernetes manifests are transformed on-the-fly such that the on-disk representations
are untouched.

Each Pod will have an `debug.cloud.google.com/config` annotation with a JSON object
describing the debug configurations for the pod's containers (linebreaks for readability):
```
debug.cloud.google.com/config={
"<containerName>":{"runtime":"<runtimeId>",...},
"<containerName>":{"runtime":"<runtimeId>",...},
}
```
local machine. IDEs can use Skaffold's events to automatically configure debug sessions.

For example the following annotation indicates that the container named `web` is a Go application
that is being debugged by a headless Delve session on port `56268` (linebreaks for readability):
```
debug.cloud.google.com/config={
"web":{
"artifact":"gcr.io/random/image",
"runtime":"go",
"ports":{"dlv":56268},
"workingDir":"/some/path"}}
```
## How It Works

`artifact` is the corresponding artifact's image name in the `skaffold.yaml`.
`runtime` is the language runtime detected.
`ports` is a list of debug ports keyed by the language runtime debugging protocol.
`workingDir` is the working directory (if not an empty string).
`skaffold debug` examines the built artifacts to determine the underlying language runtime technology.
Kubernetes manifests that reference these artifacts are transformed on-the-fly to enable the
language runtime's debugging functionality. These transforms add or alter environment variables
and entrypoints, and more.

Some language runtimes require additional support files to enable debugging.
For these languages, a special set of [runtime-specific images](https://github.com/GoogleContainerTools/container-debug-support)
are configured as _init-containers_ to populate a shared-volume that is mounted into
each of the appropriate containers. These images are hosted at `gcr.io/gcp-dev-tools/duct-tape`.


### Supported Language Runtimes

Debugging is currently supported for Go, Java (and JVM languages), NodeJS, and Python.
Debugging is currently supported for:
- Go (runtime ID: `go`)
- NodeJS (runtime ID: `nodejs`)
- Java and JVM languages (runtime ID: `jvm`)
- Python (runtime ID: `python`)

Note that many debuggers may require additional information for the location of source files.
We are looking for ways to identify this information and to pass it back if found.

#### Go

Expand All @@ -67,9 +44,12 @@ Go-based applications are configured to run under [Delve](https://github.com/go-
- Go applications should be built without optimizations, so your build should be capable of building with
`-gcflags='all=-N -l'`. Skaffold [_Profiles_]({{< relref "/docs/environment/profiles.md" >}}) are a useful option.

Note for users of [VS Code's debug adapter for Go](https://github.com/Microsoft/vscode-go): Delve seems
to treat the source location for headless launches as being relative to `/go`. The following
[remote launch configuration](https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code#remote-debugging) was useful:
Note for users of [VS Code's debug adapter for Go](https://github.com/Microsoft/vscode-go):
the source location must be set to the remote source location _during compilation_. For example, the
`golang` images, which are [often used in multi-stage builds](https://github.com/GoogleContainerTools/skaffold/tree/master/examples/getting-started/Dockerfile),
copy the source code to `/go`. The following
[remote launch configuration](https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code#remote-debugging)
works in this case:
```json
{
"name": "Skaffold Debug",
Expand Down Expand Up @@ -108,6 +88,149 @@ The DAP is supported by Visual Studio Code, [Eclipse LSP4e](https://projects.ecl
[and other editors and IDEs](https://microsoft.github.io/debug-adapter-protocol/implementors/tools/).
DAP is not yet supported by JetBrains IDEs like PyCharm.

## IDE Support via Events and Metadata

`debug` provides additional support for IDEs to detect the debuggable containers and to determine
appropriate configuration parameters.

### Workload Annotations

Each transformed workload object carries a `debug.cloud.google.com/config` annotation with
a JSON object describing the debug configurations for the pod's containers (linebreaks for readability):
```
debug.cloud.google.com/config={
"<containerName>":{"runtime":"<runtimeId>",...},
"<containerName>":{"runtime":"<runtimeId>",...},
}
```

For example the following annotation indicates that the container named `web` is a Go application
that is being debugged by a headless Delve session on port `56268` (linebreaks for readability):
```
debug.cloud.google.com/config={
"web":{
"artifact":"gcr.io/random/image",
"runtime":"go",
"ports":{"dlv":56268},
"workingDir":"/some/path"}}
```

`artifact` is the corresponding artifact's image name in the `skaffold.yaml`.
`runtime` is the language runtime detected (one of: `go`, `jvm`, `nodejs`, `python`).
`ports` is a list of debug ports keyed by the language runtime debugging protocol.
`workingDir` is the working directory (if not an empty string).


### API: Events

Each debuggable container being started or stopped raises a _debug-container-event_ through
Skaffold's event mechanism ([gRPC](../references/api/grpc/#debuggingcontainerevent),
[REST](../references/api/swagger/#/SkaffoldService/Events)).

<details>
<summary>`/v1/events` stream of `skaffold debug` within `examples/jib`</summary>

In this example, we do a `skaffold debug`, and then kill the deployed pod. The deployment starts a new pod. We get a terminated event for the container for the killed pod.

```json
{
"result": {
"timestamp": "2020-02-05T03:27:30.114354Z",
"event": {
"debuggingContainerEvent": {
"status": "Started",
"podName": "web-f6d56bcc5-6csgs",
"containerName": "web",
"namespace": "default",
"artifact": "skaffold-jib",
"runtime": "jvm",
"debugPorts": {
"jdwp": 5005
}
}
},
"entry": "Debuggable container started pod/web-f6d56bcc5-6csgs:web (default)"
}
}
```

</details>



### API: State

The API's _state_ ([gRPC](../references/api/grpc/#skaffoldservice), [REST](../references/api/swagger/#/SkaffoldService/GetState)) also includes a list of debuggable containers.

<details>
<summary>The `/v1/state` listing debugging containers</summary>

```json
{
"buildState": {
"artifacts": {
"skaffold-jib": "Complete"
}
},
"deployState": {
"status": "Complete"
},
"forwardedPorts": {
"5005": {
"localPort": 5005,
"remotePort": 5005,
"podName": "web-f6d56bcc5-6csgs",
"containerName": "web",
"namespace": "default",
"portName": "jdwp",
"resourceType": "pod",
"resourceName": "web-f6d56bcc5-6csgs",
"address": "127.0.0.1"
},
"8080": {
"localPort": 8080,
"remotePort": 8080,
"namespace": "default",
"resourceType": "service",
"resourceName": "web",
"address": "127.0.0.1"
},
"8081": {
"localPort": 8081,
"remotePort": 8080,
"podName": "web-f6d56bcc5-6csgs",
"containerName": "web",
"namespace": "default",
"resourceType": "pod",
"resourceName": "web-f6d56bcc5-6csgs",
"address": "127.0.0.1"
}
},
"statusCheckState": {
"status": "Not Started"
},
"fileSyncState": {
"status": "Not Started"
},
"debuggingContainers": [
{
"status": "Started",
"podName": "web-f6d56bcc5-6csgs",
"containerName": "web",
"namespace": "default",
"artifact": "skaffold-jib",
"runtime": "jvm",
"debugPorts": {
"jdwp": 5005
}
}
]
}

```

</details>


## Limitations

Expand All @@ -118,7 +241,7 @@ DAP is not yet supported by JetBrains IDEs like PyCharm.
`skaffold debug` requires being able to examine and alter the
command-line used in the container entrypoint. This transformation
will not work with images that use intermediate launch scripts or
binaries. For example, `debug` cannot work with an image produced
binaries. For example, `debug` currently does not work with an image produced
by the Cloud Native Buildpacks builder as it uses a `launcher`
binary to run commands that are specified in a set of configuration
files.
Expand Down