|
| 1 | +--- |
| 2 | +title: Debugging an Application with OpenShift Toolkit |
| 3 | +sidebar_position: 7 |
| 4 | +--- |
| 5 | + |
| 6 | +Debugging is an unavoidable part of development, and it can prove even more difficult when developing an application that runs remotely. |
| 7 | + |
| 8 | +However, this task is made absurdly simple with the help of the OpenShift Toolkit IDE plugin. |
| 9 | + |
| 10 | +## OpenShift Toolkit |
| 11 | +OpenShift Toolkit is an IDE plugin available on [VS Code](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-openshift-connector) and [Jet Brains](https://plugins.jetbrains.com/plugin/12030-openshift-toolkit-by-red-hat/) IDEs, that allows you to do all things that `odo` does, i.e. create, test, debug and deploy cloud-native applications on a cloud-native environment in simple steps. |
| 12 | +`odo` enables this plugin to do what it does. |
| 13 | + |
| 14 | +## Prerequisites |
| 15 | +1. [You have logged in to your cluster](../quickstart/nodejs.md#step-1-connect-to-your-cluster-and-create-a-new-namespace-or-project). |
| 16 | +2. You have [initialized an application with `odo`](/docs/command-reference/init), for example [the Node.JS quickstart application](../quickstart/nodejs.md#step-2-initializing-your-application-odo-init). |
| 17 | +:::note |
| 18 | + This tutorial uses a Node.js application, but you can use any application that has Devfile with debug command defined in it. If your Devfile does not contain a debug command, refer to [Configure Devfile to support debugging](#configure-devfile-to-support-debugging). |
| 19 | +::: |
| 20 | +3. You have [installed](/docs/overview/installation#ide-installation) the OpenShift Toolkit Plugin in your preferred VS Code or a JetBrains IDE. |
| 21 | +4. You have opened the application in the IDE. |
| 22 | + |
| 23 | +In the plugin window, you should be able to see the cluster you are logged into in "APPLICATION EXPLORER" section, and your component "my-nodejs-app" in "COMPONENTS" section. |
| 24 | + |
| 25 | + |
| 26 | + |
| 27 | +## Step 1. Start the Dev session to run the application on cluster |
| 28 | + |
| 29 | +1. Right click on "my-nodejs-app" and select "Start on Dev". |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +2. Wait until the application is running on the cluster, i.e. until you see "Keyboard Commands" appear in your "TERMINAL" window. |
| 34 | + |
| 35 | + |
| 36 | + |
| 37 | +Our application is now available at 127.0.0.1:20001. The debug server is available at 127.0.0.1:20002. |
| 38 | + |
| 39 | +## Step 2. Start the Debugging session |
| 40 | + |
| 41 | +1. Right click on "my-nodejs-app" and select "Debug". |
| 42 | + |
| 43 | + |
| 44 | + |
| 45 | +2. Debug session should have started successfully in the container at the debug port, in this case, 5858. And you must be looking at the "DEBUG CONSOLE". |
| 46 | + |
| 47 | + |
| 48 | + |
| 49 | +## Step 3. Set Breakpoints in the application |
| 50 | + |
| 51 | +Now that the debug session is running, we can set breakpoints in the code. |
| 52 | + |
| 53 | +1. Open 'server.js' file if you haven't opened it already. We will set a breakpoint on Line 55 by clicking the red dot that appears right next to line numbers. |
| 54 | + |
| 55 | + |
| 56 | + |
| 57 | +2. From a new terminal, or a browser window, ping the URL at which the application is available, in this case, it is 127.0.0.1:20001. |
| 58 | + |
| 59 | + |
| 60 | + |
| 61 | +3. The debug session should halt execution at the breakpoint, at which point you can start debugging the application. |
| 62 | + |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +## Configure Devfile to support debugging |
| 67 | +Here, we are taking example of a Go devfile that currently does not have a debug command out-of-the-box. |
| 68 | +<details> |
| 69 | +<summary>Sample Go Devfile</summary> |
| 70 | + |
| 71 | +```yaml |
| 72 | +schemaVersion: 2.1.0 |
| 73 | +metadata: |
| 74 | + description: "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software." |
| 75 | + displayName: Go Runtime |
| 76 | + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg |
| 77 | + name: go |
| 78 | + projectType: Go |
| 79 | + provider: Red Hat |
| 80 | + language: Go |
| 81 | + tags: |
| 82 | + - Go |
| 83 | + version: 1.0.2 |
| 84 | +starterProjects: |
| 85 | + - name: go-starter |
| 86 | + description: A Go project with a simple HTTP server |
| 87 | + git: |
| 88 | + checkoutFrom: |
| 89 | + revision: main |
| 90 | + remotes: |
| 91 | + origin: https://github.com/devfile-samples/devfile-stack-go.git |
| 92 | +components: |
| 93 | + - container: |
| 94 | + endpoints: |
| 95 | + - name: http-go |
| 96 | + targetPort: 8080 |
| 97 | + image: registry.access.redhat.com/ubi9/go-toolset:latest |
| 98 | + args: ["tail", "-f", "/dev/null"] |
| 99 | + memoryLimit: 1024Mi |
| 100 | + mountSources: true |
| 101 | + name: runtime |
| 102 | +commands: |
| 103 | + - exec: |
| 104 | + env: |
| 105 | + - name: GOPATH |
| 106 | + value: ${PROJECT_SOURCE}/.go |
| 107 | + - name: GOCACHE |
| 108 | + value: ${PROJECT_SOURCE}/.cache |
| 109 | + commandLine: go build main.go |
| 110 | + component: runtime |
| 111 | + group: |
| 112 | + isDefault: true |
| 113 | + kind: build |
| 114 | + workingDir: ${PROJECT_SOURCE} |
| 115 | + id: build |
| 116 | + - exec: |
| 117 | + commandLine: ./main |
| 118 | + component: runtime |
| 119 | + group: |
| 120 | + isDefault: true |
| 121 | + kind: run |
| 122 | + workingDir: ${PROJECT_SOURCE} |
| 123 | + id: run |
| 124 | +``` |
| 125 | +</details> |
| 126 | +
|
| 127 | +1. Add an exec command with `group`:`kind` set to `debug`. The debugger tool you use must be able to start a debug server that we can later on connect to. The binary for your debugger tool should be made available by the container component image. |
| 128 | +```yaml |
| 129 | +commands: |
| 130 | +- exec: |
| 131 | + env: |
| 132 | + - name: GOPATH |
| 133 | + value: ${PROJECT_SOURCE}/.go |
| 134 | + - name: GOCACHE |
| 135 | + value: ${PROJECT_SOURCE}/.cache |
| 136 | + commandLine: | |
| 137 | + dlv \ |
| 138 | + --listen=127.0.0.1:${DEBUG_PORT} \ |
| 139 | + --only-same-user=false \ |
| 140 | + --headless=true \ |
| 141 | + --api-version=2 \ |
| 142 | + --accept-multiclient \ |
| 143 | + debug --continue main.go |
| 144 | + component: runtime |
| 145 | + group: |
| 146 | + isDefault: true |
| 147 | + kind: debug |
| 148 | + workingDir: ${PROJECT_SOURCE} |
| 149 | + id: debug |
| 150 | +``` |
| 151 | +For the example above, we use [`dlv`](https://github.com/go-delve/delve) debugger for debugging a Go application and it listens to the port exposed by the environment variable *DEBUG_PORT* inside the container. The debug command references a container component called "runtime". |
| 152 | + |
| 153 | +2. Add Debug endpoint to the container component's [`endpoints`](https://devfile.io/docs/2.2.0/defining-endpoints) with `exposure` set to `none` so that it cannot be accessed from outside, and export the debug port number via `DEBUG_PORT` `env` variable. |
| 154 | + |
| 155 | +The debug endpoint name must be named **debug** or be prefixed by **debug-** so that `odo` can recognize it as a debug port. |
| 156 | + |
| 157 | +```yaml |
| 158 | +components: |
| 159 | + - container: |
| 160 | + endpoints: |
| 161 | + - name: http-go |
| 162 | + targetPort: 8080 |
| 163 | + # highlight-start |
| 164 | + - exposure: none |
| 165 | + name: debug |
| 166 | + targetPort: 5858 |
| 167 | + # highlight-end |
| 168 | + image: registry.access.redhat.com/ubi9/go-toolset:latest |
| 169 | + args: ["tail", "-f", "/dev/null"] |
| 170 | + # highlight-start |
| 171 | + env: |
| 172 | + - name: DEBUG_PORT |
| 173 | + value: '5858' |
| 174 | + # highlight-end |
| 175 | + memoryLimit: 1024Mi |
| 176 | + mountSources: true |
| 177 | + name: runtime |
| 178 | +``` |
| 179 | + |
| 180 | +For the example above, we assume that the "runtime" container's `image` provides the binary for delve debugger. We also add an endpoint called "debug" with `targetPort` set to *5858* and `exposure` set to `none`. We also export debug port number via `env` variable called `DEBUG_PORT`. |
| 181 | + |
| 182 | +The final Devfile should look like the following: |
| 183 | +<details> |
| 184 | +<summary>Go Devfile configured for debugging</summary> |
| 185 | + |
| 186 | +```yaml showLineNumbers |
| 187 | +commands: |
| 188 | +- exec: |
| 189 | + commandLine: go build main.go |
| 190 | + component: runtime |
| 191 | + env: |
| 192 | + - name: GOPATH |
| 193 | + value: ${PROJECT_SOURCE}/.go |
| 194 | + - name: GOCACHE |
| 195 | + value: ${PROJECT_SOURCE}/.cache |
| 196 | + group: |
| 197 | + isDefault: true |
| 198 | + kind: build |
| 199 | + workingDir: ${PROJECT_SOURCE} |
| 200 | + id: build |
| 201 | +- exec: |
| 202 | + commandLine: ./main |
| 203 | + component: runtime |
| 204 | + group: |
| 205 | + isDefault: true |
| 206 | + kind: run |
| 207 | + workingDir: ${PROJECT_SOURCE} |
| 208 | + id: run |
| 209 | +# highlight-start |
| 210 | +- exec: |
| 211 | + env: |
| 212 | + - name: GOPATH |
| 213 | + value: ${PROJECT_SOURCE}/.go |
| 214 | + - name: GOCACHE |
| 215 | + value: ${PROJECT_SOURCE}/.cache |
| 216 | + commandLine: | |
| 217 | + dlv \ |
| 218 | + --listen=127.0.0.1:${DEBUG_PORT} \ |
| 219 | + --only-same-user=false \ |
| 220 | + --headless=true \ |
| 221 | + --api-version=2 \ |
| 222 | + --accept-multiclient \ |
| 223 | + debug --continue main.go |
| 224 | + component: runtime |
| 225 | + group: |
| 226 | + isDefault: true |
| 227 | + kind: debug |
| 228 | + workingDir: ${PROJECT_SOURCE} |
| 229 | + id: debug |
| 230 | +# highlight-end |
| 231 | +components: |
| 232 | +- container: |
| 233 | + args: |
| 234 | + - tail |
| 235 | + - -f |
| 236 | + - /dev/null |
| 237 | + endpoints: |
| 238 | + - name: http-go |
| 239 | + targetPort: 8080 |
| 240 | +# highlight-start |
| 241 | + - name: debug |
| 242 | + exposure: none |
| 243 | + targetPort: 5858 |
| 244 | + env: |
| 245 | + - name: DEBUG_PORT |
| 246 | + value: '5858' |
| 247 | +# highlight-end |
| 248 | + image: registry.access.redhat.com/ubi9/go-toolset:latest |
| 249 | + memoryLimit: 1024Mi |
| 250 | + mountSources: true |
| 251 | + name: runtime |
| 252 | +metadata: |
| 253 | + description: Go is an open source programming language that makes it easy to build |
| 254 | + simple, reliable, and efficient software. |
| 255 | + displayName: Go Runtime |
| 256 | + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg |
| 257 | + language: Go |
| 258 | + name: my-go-app |
| 259 | + projectType: Go |
| 260 | + provider: Red Hat |
| 261 | + tags: |
| 262 | + - Go |
| 263 | + version: 1.0.2 |
| 264 | +schemaVersion: 2.1.0 |
| 265 | +starterProjects: |
| 266 | +- description: A Go project with a simple HTTP server |
| 267 | + git: |
| 268 | + checkoutFrom: |
| 269 | + revision: main |
| 270 | + remotes: |
| 271 | + origin: https://github.com/devfile-samples/devfile-stack-go.git |
| 272 | + name: go-starter |
| 273 | +``` |
| 274 | +</details> |
| 275 | + |
| 276 | +## Extra Resources |
| 277 | +To learn more about running and debugging an application on cluster with OpenShift Toolkit, see the links below. |
| 278 | +1. [Using OpenShift Toolkit - project with existing devfile](https://www.youtube.com/watch?v=2jfV0QqG8Sg) |
| 279 | +2. [Using OpenShift Toolkit with two microservices](https://www.youtube.com/watch?v=8SpV6UZ23_c) |
| 280 | +3. [Using OpenShift Toolkit - project without devfile](https://www.youtube.com/watch?v=sqqznqoWNSg) |
0 commit comments