An useful tip about debugging a python flask application running inside docker

I wanted to document an useful tip about debugging an application that runs inside docker container. Mainly how to configure for an application inside docker to connect to a service on the host.

This article will use flask application and pycharm debugger service as an example but I guess the principle can be applied for any such combination of application to service connectivity.

Setup

Let the setup be such that you are running a python flask app inside docker. We want to debug this app by using pycharm debugger.

Below is a screenshot of a pycharm debugger as configured for a sample flask application.

pycharm debug config

Once you click ok and start the debugger, you will see below message essentially saying the debugger is waiting for the application to connect to it.
It also provides the code snippet that the application need to use so it can connect to the debugger.

pycharm debugger wait

Let us also assume in the docker config, we have exposed the application port to the outside host so that when you hit localhost:8000 for example,
it would call the application running inside docker and in the entrypoint of the application we place the code snippet which essentially connects
to the debugger. So far so good!

Problem

Now the problem is, we need to connect to the debugger on the host which is waiting at localhost:3000
and the code that was suggested to be used is

import pydevd_pycharm
pydevd_pycharm.settrace('localhost', port=3000, stdoutToServer=True, stderrToServer=True)

In the above code snippet that was suggested, the localhost will be the localhost of the docker container and does not refer to the host.

Solution

Here, we need a way to tell docker to use the localhost of the host and here is where the handy special DNS name host.docker.internal comes in handy.
This will resolve to the internal ip address used by the host and as long as we have configured the debugger to use localhost (in case the host is using dynamic ip or none at all),
this should work perfectly.

So, the solution is to replace localhost in the above code snippet with host.docker.internal.

© 2019. All rights reserved.