How to use PDB inside a docker container.
Hello there fellow, if you’re reading now this article, then you probably ran into some problems related to debugging inside a docker container by means of pdb.
There are several nuances that uncovered on the internet, so I’d like to share with others my personal experience with those. First of all, I start with the configuration part.
You need to have something like this inside your docker-compose.yml
Nuances to know:
- It’s important to set
stdin_open
andtty
parameters totrue
on every service that will use PDB. - Usually inside
docker-compose.yml
specified bundles of services like Nginx & Gunicorn, Nginx & uWSGI etc., so you need to set timeout flag for your WSGI server, because if you won’t do it, then you’ll be only limited with 1 minute (mostly default timeout for all WSGI servers) to debug something and after that, a connection will be lost, so we need to increase it for development purposes. ports
parameter should be complemented with4444
or any other available port, you can check unavailable ports by means such commandnetstat -lntu
inside your terminal. Likewise, the first bullet point, on every service that will be using PDB you need to provide a port.
That’s it for docker-compose.yml
file. Other problems will appear when you’ll set breakpoints by means lovely pdb
from Python standard library and alongside it, you have continuous spawning of logs to STDOUT. Yes, you can attach a docker container and jump into it, but you won’t be able to type something, because logs will always override your input.
The solution is to use remote-pdb
library and debug it remotely by means of telnet
. So you need to add remote-pdb
to your requirements.txt
and set an appropriate breakpoint. E.g.:
The next step is to connect to our remote debugger by means of telnet
. You need to specify host and port that you provided inside your docker-compose.yml
, but be careful, host inside our Python code always should be 0.0.0.0
and port you set likewise docker-compose.yml
, but host differs for telnet
. For example, if you use docker-machine
then, you need to figure out the IP of this machine. You can do it simply by such command docker-machine ip {name_of_your_machine}
and then connect by telnet
. E.g.:
telnet 0.0.0.0 4444
— it’s a default case of connection if you don’t usedocker-machine
and the scheme is next if you dotelnet {docker_machine_ip} {provided_port_from_docker_compose.yml}
- worth to mention, you need to connect when your Python interpreter will reach a breakpoint.
UPD: There is a fancy pdb wrapper there called pdb++. You can improve your debugging experience with this tool. All that you need is to add this fancy lib to your requirements.txt
and you’ll get something like this when you’ll be debugging inside telnet
.
One thing about pdb++ in sticky mode, when used by telnet, truncate an output what is not really we want. It can be changed easily. In the case of Dockerfile (or docker-compose command
), we can put the following inside a bash script and use it as an ENTRYPOINT. E.g.:
Last but not least, there is an option to set argument --log-level CRITICAL
for gunicorn and use vanilla pdb with docker attach
(thanks Colin Miller). This will avoid usage of telnet
and remote-pdb library and won’t overwrite attached pdb screen with gunicorn logs. Moreover, in this case, tab autocomplete will work. See repository to learn more.
You can run python manage.py runserver 0.0.0.0:8000
from a Docker container itself too, so you won’t need to modify docker-compose.yml
and use telnet
, remote-pdb and even docker attach
, just don’t forget to disable logging.
So as you can see there are plenty of ways to use pdb in a docker container. I hope it was helpful for you. Cheers.