There wasn’t a necessity for me to debug code running in a container until now. It was because I develop my code on a Mac, run it on Linux boxes, and all dependencies are listed in the requirements file. One thing is missing here though – the Python version.

Of course, there are ways of running various Python versions on the workstation. However, after a while trying making it work on Big Sur beta, I gave up and went for learning how can I debug a container instead.
Docker tip: to save building time and allowing Docker to reuse layers, move the least frequent changing step to the top of the Dockerfile. Like installing updates and requirements:
FROM ubuntu:18.04 as base
RUN apt-get update
RUN apt-get install -y python3.7-dev python3-pip gcc
CMD mkdir -p /app/src
WORKDIR /app
COPY ./requirements.txt .
RUN pip3 install -r ./requirements.txt
Dockerfile: I went with two Dockerfiles, one for debug, the other for production.
In the Dockerfile_debug, we need to install debugpy and configure the image’s entry point. More examples are in the debugpy’s repo, my example:
RUN pip3 install debugpy
ENTRYPOINT [ "python3", "-m", "debugpy", "--listen", "0.0.0.0:5678", "--wait-for-client", "bot.py" ]
The production Dockerfile would merely launch the Python script.
CMD ["python3", "bot.py"]
Docker-compose: It is also possible to have a single Dockerfile with multiple build stages like debug, test, production. The target build stage would be specified in Docker-compose or when running docker run
command.
Debugging in Visual Code
First, we need to run a debugpy configured container. If we specify the --wait-for-client
parameter, debugpy waits with any code execution before a debugger is attached.
Add a debug configuration and pick Remote Attach
, specify localhost and port configured in Dockerfile (5678).

If our code is in the repo’s subfolder (in my case ./app/src, it needs), we need to specify the path so mapping between the local and remote py
files would work. If the mapping is incorrect, breakpoints get disabled, and the interpreter swishes through.
"configurations": [
{
"name": "Python: Remote Attach",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}/app/src",
"remoteRoot": "."
}
]
},
One more thing, if there’s a code change, we need to rebuild the image and then run the container. A working example of the setup is in my Photo of the Day app repo.
Credits: DevOps Directive
Leave a Reply