{"id":1915,"date":"2017-04-30T16:34:42","date_gmt":"2017-04-30T11:04:42","guid":{"rendered":"http:\/\/ramkulkarni.com\/blog\/?p=1915"},"modified":"2017-04-30T16:38:45","modified_gmt":"2017-04-30T11:08:45","slug":"debugging-django-project-in-docker","status":"publish","type":"post","link":"http:\/\/ramkulkarni.com\/blog\/debugging-django-project-in-docker\/","title":{"rendered":"Remote Debugging Django Project in Docker"},"content":{"rendered":"<p>In the <a href=\"http:\/\/ramkulkarni.com\/blog\/docker-project-for-python3-djaongo-and-apache2-setup\/\" target=\"_blank\" rel=\"noopener noreferrer\">last post<\/a> I described how to setup Django and Apache in Docker container. In this post I will describe\u00a0how to remote debug the Django application running in the same setup. If you look at the <a href=\"https:\/\/github.com\/ramkulkarni1\/django-apache2-docker\/blob\/master\/Dockerfile\" target=\"_blank\" rel=\"noopener noreferrer\">Dockerfile<\/a> of the project (in the last post), you would see that it installs <a href=\"https:\/\/pypi.python.org\/pypi\/ptvsd\" target=\"_blank\" rel=\"noopener noreferrer\">ptvsd<\/a> package &#8211; this package helps to debug Django applications running remotely using <a href=\"https:\/\/code.visualstudio.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Visual Studio Code<\/a>.<\/p>\n<p>Install <a href=\"https:\/\/code.visualstudio.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Visual Studio Code<\/a>, if you haven&#8217;t installed it already. Then install VS Code extension for Python. I have installed <a href=\"https:\/\/github.com\/DonJayamanne\/pythonVSCode\" target=\"_blank\" rel=\"noopener noreferrer\">this<\/a> extension by Don Jayamanne, and it supports\u00a0debugging of Python applications. If you don&#8217;t know how to install extensions in VS Code, <a href=\"https:\/\/code.visualstudio.com\/docs\/introvideos\/extend\" target=\"_blank\" rel=\"noopener noreferrer\">this video<\/a> might help you.<\/p>\n<p>To enable remote debugging of Django application, or Python applications in general, you need to run ptvsd server on the machine where Django is configure, which in our case is a Docker container. You need to embed following code snippet in your Django app, and it needs to run only once, because it listens\u00a0to a port.<\/p>\n<pre style=\"color: #000020; background: #f6f8ff;\"><span style=\"color: #200080; font-weight: bold;\">import<\/span> ptvsd\r\n\r\nptvsd<span style=\"color: #308080;\">.<\/span>enable_attach<span style=\"color: #308080;\">(<\/span><span style=\"color: #1060b6;\">\"my_secret\"<\/span><span style=\"color: #308080;\">,<\/span> address <span style=\"color: #308080;\">=<\/span> <span style=\"color: #308080;\">(<\/span><span style=\"color: #1060b6;\">'0.0.0.0'<\/span><span style=\"color: #308080;\">,<\/span> <span style=\"color: #008c00;\">3500<\/span><span style=\"color: #308080;\">)<\/span><span style=\"color: #308080;\">)<\/span>\r\n<\/pre>\n<p>The above snippet starts ptsvd server, that listens on port 3500. We configured Python to run in Apache2 using mod-wsgi in the Docker container, but I haven&#8217;t found a way to embed the above code in a Django application in this setup, where it would run only once (if it is run multiple times, it will try to attach to the same port and that would fail). So far the best way I have found to debug Django application remotely in Docker is to start Django development server on a different port (than one where Apache is listening) and embed the debugger code in manage.py. You run the development server by running manage.py, for example &#8211;<!--more--><\/p>\n<pre style=\"color: #000020; background: #f6f8ff;\">$ <span style=\"color: #1060b6;\">python<\/span> <span style=\"color: #1060b6;\">manage.py<\/span> <span style=\"color: #1060b6;\">runserver<\/span> <span style=\"color: #008000;\">0.0<\/span><span style=\"color: #1060b6;\">.0.0:8080<\/span>\r\n<\/pre>\n<p>This will run the dev server on port 8080. Insert the\u00a0code to start ptvsd server in manage.py, at the end of &#8216;try&#8217; block, just above &#8216;except&#8217; block. Next, start the dev server. But\u00a0there is one problem. If you change any application code, dev server will try to reload, and in the process it will execute the code to start the server, and since server is already started, it will fail with port in use error. I tried using is_attached API of ptvsd to check if debugger is already attached, but that did not work. So for now, I have disabled reload using &#8211;noreload switch\u00a0&#8211;<\/p>\n<pre style=\"color: #000020; background: #f6f8ff;\">$ <span style=\"color: #1060b6;\">python<\/span> <span style=\"color: #1060b6;\">manage.py<\/span> <span style=\"color: #1060b6;\">runserver<\/span> <span style=\"color: #1060b6;\">--noreload<\/span> <span style=\"color: #008000;\">0.0<\/span><span style=\"color: #1060b6;\">.0.0:81<\/span>\r\n<\/pre>\n<p>It is a big inconvenience to restart the server every time you make changes to the code, but I haven&#8217;t found any solution for this so far.<\/p>\n<p>Remember that we have mapped three ports in <a href=\"https:\/\/github.com\/ramkulkarni1\/django-apache2-docker\/blob\/master\/docker-compose.yml\" target=\"_blank\" rel=\"noopener noreferrer\">docker-compose.xml<\/a> &#8211;<\/p>\n<pre style=\"color: #000020; background: #f6f8ff;\">ports:\r\n      - '8005:80'\r\n      - '3500:3500'\r\n      - '8006:81'\r\n<\/pre>\n<p>Port 80, at which Apache is listening is mapped to 8005. Port 3500, at which\u00a0ptvsd debugger server is listening is mapped to the same number in the host machine. And port 81, at which our development server is running is mapped to 8006. So to access\u00a0the development server, you need to open http:\/\/localhost:8006 from the host machine.<\/p>\n<p>Once the server is running, we need to\u00a0configure the debugger in VS Code. Click debug icon in the activity bar (on the left)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1916\" data-permalink=\"http:\/\/ramkulkarni.com\/blog\/debugging-django-project-in-docker\/vs-code-debug-config-1\/\" data-orig-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-1.png?fit=662%2C532\" data-orig-size=\"662,532\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"vs-code-debug-config-1\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-1.png?fit=300%2C241\" data-large-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-1.png?fit=525%2C422\" class=\"alignnone size-medium wp-image-1916\" src=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-1.png?resize=300%2C241\" alt=\"\" width=\"300\" height=\"241\" srcset=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-1.png?resize=300%2C241 300w, https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-1.png?w=662 662w\" sizes=\"(max-width: 300px) 100vw, 300px\" data-recalc-dims=\"1\" \/><\/p>\n<p>Initially there may not be any configuration present. Click on the drop down and select &#8216;Add Configuration&#8217;. Alternatively you can\u00a0select Debug | Add Configurations menu option. This will create a new file launch.json with many configurations for Python debugging. We are interested in a configuration called &#8216;Attach (Remote Debug)&#8217;. In this configuration, change\u00a0localRoot,\u00a0remoteRoot and port. For the\u00a0setup being discussed in this post, the configuration should look like &#8211;<\/p>\n<pre style=\"color: #000020; background: #f6f8ff;\"><span style=\"color: #406080;\">{<\/span>\r\n    <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">name<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #406080;\">:<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">Attach (Remote Debug)<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span>\r\n    <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">type<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #406080;\">:<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">python<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span>\r\n    <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">request<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #406080;\">:<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">attach<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span>\r\n    <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">localRoot<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #406080;\">:<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">${workspaceRoot}\/www<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span>\r\n    <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">remoteRoot<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #406080;\">:<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">\/var\/www\/html<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span>\r\n    <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">port<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #406080;\">:<\/span> <span style=\"color: #008c00;\">3500<\/span><span style=\"color: #308080;\">,<\/span>\r\n    <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">secret<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #406080;\">:<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">my_secret<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #308080;\">,<\/span>\r\n    <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">host<\/span><span style=\"color: #800000;\">\"<\/span><span style=\"color: #406080;\">:<\/span> <span style=\"color: #800000;\">\"<\/span><span style=\"color: #1060b6;\">localhost<\/span><span style=\"color: #800000;\">\"<\/span>\r\n<span style=\"color: #406080;\">}<\/span>\r\n<\/pre>\n<p>Run the development server, if it is not already running.<\/p>\n<ol>\n<li>Start the docker container &#8211; &#8216;docker-compose up&#8217;<\/li>\n<li>Open a bash shell in the container &#8211; &#8216;docker exec -it django-apache2 bash&#8217;<\/li>\n<li>Go to the project folder &#8211; &#8216;cd \/var\/www\/html\/django_demo_app\/demo_site&#8217;<\/li>\n<li>Run Django dev server &#8211; &#8216;python manage.py runserver &#8211;noreload 0.0.0.0:81&#8217;<\/li>\n<\/ol>\n<p>From you host machine browse to http:\/\/localhost:8006 and make sure the application is working.<\/p>\n<p>In VS Code, open\u00a0\/www\/django_demo_app\/demo_site\/app1\/views.py file and set breakpoint on line 16, in index method (click in the left margin on the line to set breakpoint). Click on debug icon in the left activity bar and select &#8216;Attach (Remote Debug)&#8217; configuration and click play button.<\/p>\n<p>Open the application link, http:\/\/localhost:8006, in the browser. You should see execution stopped at the breakpoint in VC Code.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1920\" data-permalink=\"http:\/\/ramkulkarni.com\/blog\/debugging-django-project-in-docker\/vs-code-debug-config-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?fit=1876%2C948\" data-orig-size=\"1876,948\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"vs-code-debug-config-2\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?fit=300%2C152\" data-large-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?fit=525%2C265\" class=\"alignnone size-large wp-image-1920\" src=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?resize=525%2C265\" alt=\"\" width=\"525\" height=\"265\" srcset=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?resize=1024%2C517 1024w, https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?resize=300%2C152 300w, https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?resize=768%2C388 768w, https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?w=1876 1876w, https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2017\/04\/vs-code-debug-config-2.png?w=1575 1575w\" sizes=\"(max-width: 525px) 100vw, 525px\" data-recalc-dims=\"1\" \/><\/p>\n<p>Remember that if you change any Python code, you will need to restart the development server and re-attach debugger in VS Code.<\/p>\n<p><span class=\"embed-youtube\" style=\"text-align:center; display: block;\"><iframe loading=\"lazy\" class=\"youtube-player\" width=\"525\" height=\"296\" src=\"https:\/\/www.youtube.com\/embed\/htAk4Z6dIiA?version=3&#038;rel=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;fs=1&#038;hl=en-US&#038;autohide=2&#038;wmode=transparent\" allowfullscreen=\"true\" style=\"border:0;\" sandbox=\"allow-scripts allow-same-origin allow-popups allow-presentation allow-popups-to-escape-sandbox\"><\/iframe><\/span><\/p>\n<p>-Ram Kulkarni<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the last post I described how to setup Django and Apache in Docker container. In this post I will describe\u00a0how to remote debug the Django application running in the same setup. If you look at the Dockerfile of the project (in the last post), you would see that it installs ptvsd package &#8211; this &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/ramkulkarni.com\/blog\/debugging-django-project-in-docker\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Remote Debugging Django Project in Docker&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[54,135,115],"tags":[113,138,136,133,116],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2g9O8-uT","jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/1915"}],"collection":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/comments?post=1915"}],"version-history":[{"count":3,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/1915\/revisions"}],"predecessor-version":[{"id":1924,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/1915\/revisions\/1924"}],"wp:attachment":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/media?parent=1915"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/categories?post=1915"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/tags?post=1915"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}