Remote Debugging with Pycharm and Docker

The scenario

I use PyCharm for python development. Being able to use the python debugger is absolutely crucial. For some of my projects the code needs to run on special hardware, but my development environment is on my local machine. In this case, the remote interpreter option which PyCharm provides is amazing. I can run the code as if it were running on my own machine, but the code is actually executed on a remote machine.

Now, all of this works great if I use a native python distribution running on the system, but what happens when I try to run things inside a Docker container? PyCharm has pretty good support for docker, and if used locally, debugging works fine. The problem starts when I want to run my project inside a docker container running on a remote device, but I also need remote debugging. There isn’t really a documented way to do this, but it is possible. After quite a bit of trial and error by my colleague Marcell, we got it working.

Remote setup

Enabling Docker Remote API

First, the docker remote API has to be enabled. Looking at the dockerd documentation, we need to enable the TCP socket. For example, we can use the -H tcp://0.0.0.0:8888switch, to listen on port 8888. On Ubuntu we can modify the service file here: /lib/systemd/system/docker.service. At the line where we see ExecStart=/usr/bin/dockerd -H fd://, we can add our -H flag to the end. Now we just reload everything with these two commands, and the remote API should work:
systemctl daemon-reload
service docker restart.

For the remote debugger to work, we need to copy some helper files from our local PyCharm to the remote device. Inside PyCharm’s installation directory there should be a directory called debugg_eggs. Let’s copy these over.

Local setup

Changes to the python code

For the remote debugging to work, we need to make changes to our python code. Essentially what we are doing is instructing our program to connect back to us, where we have a debugger running. After this, our debugger will hook into the program, and we can debug as usual. Now, instead of putting IP addresses inside my code, I like to setup environment variables for these settings, and just refer to these in my python app, that way its more portable. For example, I will use an environment variable to indicate if the program should try to connect to my debugger, or just run normally.

Put the following at the beginning of your python code:
if 'DEBUG' in os.environ:
  import sys
  sys.path.append('/path/to/pycharm-debug-py3k.egg')
  import pydevd
  pydevd.settrace(os.environ['DEBUG_IP'], port=int(os.environ['DEBUG_PORT']), suspend=False, stdoutToServer=True, stderrToServer=True)

PyCharm configuration

  1. Create a new Python Remote Debug configuration
    1. put your desktop’s ip in the Local host name field
    2. choose a port to use for the debug server (eg.: 35953)
  2. Create a new Docker Image configuration
    1. under server create a new one
      1. choose TCP socket
      2. write tcp://{$remote_ip}:8888 in the Engine API URL field
      3. press OK
    2. select the new server
    3. fill in the Image ID field with your imag ename (if you use a different tag from latest, then PyCharm might complain, but just ignore it)
    4. fill in the remaining fields as needed (ports, mounts)
  3. Start the Python Remote Debug config you created in debug mode
  4. Start the Docker Image config you created

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.