{
"$type": "site.standard.document",
"canonicalUrl": "https://rednafi.com/python/debug-dockerized-apps-in-vscode/",
"description": "Set up VSCode debugger for containerized Python applications using debugpy. Step-by-step guide with Docker Compose and launch configurations.",
"path": "/python/debug-dockerized-apps-in-vscode/",
"publishedAt": "2023-12-22T00:00:00.000Z",
"site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
"tags": [
"Python",
"TIL",
"Docker"
],
"textContent": "Despite using VSCode as my primary editor, I never really bothered to set up the native\ndebugger to step through application code running inside Docker containers. Configuring the\ndebugger to work with individual files, libraries, or natively running servers is\n[straightforward]. So, I use it in those cases and just resort back to my terminal for\ndebugging containerized apps running locally. However, after seeing a colleague's workflow\nin a pair-programming session, I wanted to configure the debugger to cover this scenario\ntoo.\n\nI'm documenting this to save my future self from banging his head against the wall trying to\nfigure it out again.\n\nDesiderata\n\nI want to start a web app with docker compose up and connect the VSCode debugger to it\nfrom the UI. For this to work, along with the webserver, we'll need to expose a debug server\nfrom the app container which the debugger can connect to.\n\nApp layout\n\nFor demonstration, I'll go with a simple containerized [Starlette] app served with\n[uvicorn]. However, the strategy will be similar for any web app. Here's the app's directory\nstructure:\n\nIn main.py, we're exposing an endpoint as follows:\n\nThe requirement.txt lists out the runtime dependencies:\n\nThen the Dockerfile builds the application:\n\nFinally, we orchestrate the app in a docker-compose.yml file:\n\nAdd launch.json\n\nNow, in the .vscode folder of the project's root directory, add a file named\nlaunch.json. Create the folder if it doesn't exist. You can also do this part manually; to\ndo so:\n\n- Click on the debugger button and then click on _create a launch.json file_.\n- Select the _Python_ debugger.\n- Finally, select the _Remote Attach_ debug config.\n\nHowever, if you dislike clicking around, here's the full content of launch.json for you to\ncopy and paste (into $PWD/.vscode/launch.json):\n\nThis instructs the VSCode debugger to attach to a debug server running on localhost\nthrough port 5678. The next section will elaborate on how to run the debug server in a\ncontainer.\n\nLaunch configuration will vary depending on your project and each project needs to be set up\nindividually. The [VSCode debugging documentation] lists out all the supported application\ntypes with example configurations. To avoid having to reconfigure the same app repetitively,\ntracking the entire .vscode directory via source control is probably a good idea.\n\nAdd docker-compose.debug.yml\n\nNext up, we'll need to update the command section of services.web in the\ndocker-compose.yml to expose the debug server. The [debugpy] tool from Microsoft does that\nfor us.\n\nHowever, instead of changing the docker-compose.yml file for debugging, we can add a\nseparate file for it named docker-compose.debug.yml. Here's the content of it:\n\nHere:\n\n- sh -c: Selects the shell inside the Docker container.\n- pip install debugpy -t /tmp: Installs the debugpy tool into the /tmp directory of\n the container.\n- python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678: Runs debugpy, sets it to\n wait for a client connection and listen on all network interfaces at port 5678.\n- -m uvicorn main:app --host 0.0.0.0 --port 8000: Starts an uvicorn server hosting the\n application defined in main:app, making it accessible on all network interfaces at\n port 8000.\n\nStart the debugger\n\nBefore starting the VScode debugger, go to the project root and run:\n\nNow click on the debugger button and select the Python: Remote attach profile to start\ndebugging. Hack away!\n\n_P.S.: An altruist on Reddit brought to my attention that a more elaborate version of this,\nwith prettier screenshots, can be found in the [official documentation]._\n\n\n\n\n[straightforward]:\n https://code.visualstudio.com/docs/python/debugging#_debugging-by-attaching-over-a-network-connection\n\n[starlette]:\n https://www.starlette.io/\n\n[uvicorn]:\n https://www.uvicorn.org/\n\n[vscode debugging documentation]:\n https://code.visualstudio.com/docs/containers/debug-python\n\n[debugpy]:\n https://github.com/microsoft/debugpy/tree/main/src/debugpy\n\n[official documentation]:\n https://code.visualstudio.com/docs/containers/quickstart-python",
"title": "Debugging dockerized Python apps in VSCode"
}