This is absolutely just a post written for me so I have a reference point to come back to when I forget how to do this in like 2 weeks!
I'm currently a backend engineer, working in Python, using Visual Studio Code as my editor of choice. And at the company I work at, my team has already done the hard work of Docker-izing all of it's applications and leveraging
docker-compose files for local development. Additionally, our team is very live-and-let-live when it comes to each team member picking their own personal IDEs and setup, so I use VS Code, others use VS Code + devcontainers, others use Pycharm, others use emacs, etc etc etc.
Fortunately, VS Code provides great debugging tooling for Python and for Docker! Unfortunately, all of my googling so far led to docs about how to create dockerfiles or docker-compose files for use in debugging, and typically for standalone applications. I couldn't find anything to clearly lay out how to start debugging on an already-existing docker-compose file that may contain many different services and containers other than the app you're trying to debug (like dependencies or databases) and that has to be maintained for all the other people working on the application alongside you.
So, that's what this is! It works! Maybe there's a better way, but this is My Way!
1: Install debugpy
debugpy is the Python debugging tool that VS Code uses, so you need to make sure it's installed on the container that will run the application. If you have a requirements file (
debugpy in that. If you separate out requirements files for local, dev, or test environments separate from your production requirements, I'd highly recommend only including it in your local/dev/test!
Alternatively, make sure that when your Docker container is created you at some point run
pip install debugpy prior to starting up your actual application.
2: Expose port 5678
In your docker-compose file, for the service you want to debug, make sure to expose port
5678. This involves adding a line something like this:
# any existing port mappings you have
This tells Docker to expose the container's local
5678 port as port
5678 on the Docker network (which best I can tell will default to
3: Start the app in the context of debugpy
In your docker-compose file there's probably some
command that is given to container on startup and that probably starts the application. At the very least, all the examples I have to deal with do!
If so, one of those commands will probably either be a python command to start the application (ex for django something like
python manage.py runserver) or, if you're running a web application, some command to start up a webserver (ex for a FastAPI app using uvicorn,
If it's the former, then modify that command to start up debugpy as part of it. If for example it's a django app with the command
python manage.py runserver, change that to
python -m debugpy --wait-for-client --listen 0.0.0.0:5678 manage.py runserver
This tells python to start up
debugpy, have it halt execution of the subsequent script until a debugger is connected, and to listen on port
5678 of host
If you aren't already starting your app via a
python call, then you can turn it into one with
python -m. If for example you have a FastAPI app with a startup command like
uvicorn app.main:app then you can modify it to
python -m debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn app.main:app
This does the same thing as the django example, except instead of debugpy overseeing the running of a
manage.py script, it oversees python running the
4: Add a launch.json configuration
.vscode/launch.json add the following to the
"name": "Attach (remote debug)",
This creates a command for VS Code called "Attach (remote debug)" that will tell it to attach a python debugger to
127.0.0.1:5678. If you've been paying attention, that should mean the debugger is now attaching to the port exposed by the application container that is being listened to by debugpy.
5: Start debugging!
docker-compose up to start up your application like normal. It should hang on startup because we passed that
--wait-for-client flag in the initial debugpy command.
Then in VS Code go to "Run and Debug" (cmd-shift-D), select "Attach (remote debug)", and press the green triangle.
From there, your debugger should attach to the running container, the rest of the application startup should continue, and you should be able to do all the cool fun stuff the VS Code debugger allows!