<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Omri Eival</title>
    <description>The latest articles on DEV Community by Omri Eival (@omrikiei).</description>
    <link>https://dev.to/omrikiei</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F269217%2F1b65881d-ff86-4e62-b66f-417a4e2c4a44.jpeg</url>
      <title>DEV Community: Omri Eival</title>
      <link>https://dev.to/omrikiei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/omrikiei"/>
    <language>en</language>
    <item>
      <title>Debugging a python application running on  Kubernetes with PyCharm (with breakpoints and the whole shebang)</title>
      <dc:creator>Omri Eival</dc:creator>
      <pubDate>Thu, 26 Dec 2019 07:47:38 +0000</pubDate>
      <link>https://dev.to/omrikiei/debugging-a-python-application-running-on-kubernetes-with-pycharm-with-breakpoints-and-the-whole-shebang-1h3c</link>
      <guid>https://dev.to/omrikiei/debugging-a-python-application-running-on-kubernetes-with-pycharm-with-breakpoints-and-the-whole-shebang-1h3c</guid>
      <description>&lt;p&gt;One of the pains of running a containerized application on Kubernetes is the inability to debug it with a normal IDE.&lt;br&gt;
With Python, there are nice solutions for remote debugging such as &lt;a href="https://pypi.org/project/remote-pdb/" rel="noopener noreferrer"&gt;remote-pdb&lt;/a&gt; but it would never be as convenient as debugging your application with a real IDE.&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Although IntelliJ did an amazing job with &lt;a href="https://www.jetbrains.com/help/pycharm/remote-debugging-with-product.html" rel="noopener noreferrer"&gt;guidance and support&lt;/a&gt; for remote debugging, their solutions are incompatible with a remote runtime that is unfamiliar with the development environment,&lt;br&gt;
or in simpler terms - in order for remote debugging to work, the runtime (python process) needs to have network access to the IDE(your workstation).&lt;/p&gt;

&lt;p&gt;Under the hood PyCharm uses a debugger based on &lt;a href="https://www.pydev.org/manual_adv_remote_debugger.html" rel="noopener noreferrer"&gt;pydevd&lt;/a&gt; - which only supports connecting from the runtime as a client and not listening to incoming connections inside the runtime as a server.&lt;/p&gt;

&lt;p&gt;A naive solution to this problem can be coupling a sidecar running SSHd with your deployment, and running a reverse SSH client tunnel .&lt;br&gt;
It would probably work - but in order to make it transparent one will need to inject the sidecar with one's public key, then run the SSH client and keep the tunnel open... seems like a lot of work.&lt;/p&gt;

&lt;p&gt;Another alternative is using &lt;a href="//telepresence.io"&gt;telepresence&lt;/a&gt; to actually run the service locally, but that would mean one would need to build/install dependencies locally - which sometimes mean a lot of time and work and without even mentioning the CPU and memory that our app will consume.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ktunnel to the rescue
&lt;/h2&gt;

&lt;p&gt;&lt;a href="//github.com/omrikiei/ktunnel"&gt;Ktunnel&lt;/a&gt; is a CLI that establishes a reverse tunnel from Kubernetes and exposes your workstation to traffic from Kubernetes, this means one can expose one's workstation to a Kubernetes pod,&lt;br&gt;
or even as a service. for our use case - it means one can tell a pod running our python app to connect to localhost on the debug port,&lt;br&gt;
when actually behind the scenes a tunnel will be established to the IDE which is listening on that port on my workstation. pretty neat!&lt;/p&gt;
&lt;h3&gt;
  
  
  Getting started
&lt;/h3&gt;

&lt;p&gt;As an example I created a simple flask web server with two endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; - will return a random number&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/debug&lt;/code&gt; - will run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the &lt;code&gt;/debug&lt;/code&gt; endpoint is called, the runtime should attempt to connect to the debugger and block until it succeeds.&lt;/p&gt;

&lt;p&gt;The code along with the kubernetes manifests can be found &lt;a href="https://github.com/omrikiei/ktunnel/tree/master/examples/pycharm-remote-debugging-on-k8s" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1 - Deploy the app to Kubernetes
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml
deployment.extensions/pyremotedebug created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;let's also port-forward to the web server and send a request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl port-forward pyremotedebug-5dcf9cf4c6-q9tr9 8000
 Forwarding from &lt;span class="o"&gt;[&lt;/span&gt;::1]:8000 -&amp;gt; 8000

 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; curl localhost:8000
Handling connection &lt;span class="k"&gt;for &lt;/span&gt;8000
Hello, Ktunnel! random number: 409
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2 - Open the project on Pycharm and configure a remote debugger
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Open pycharm, open the project (&lt;code&gt;File-&amp;gt;open-&amp;gt;"project directory"&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Put some breakpoints in the &lt;code&gt;main.py&lt;/code&gt; file
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fomrikiei%2Fktunnel%2Fraw%2Fmaster%2Fexamples%2Fpycharm-remote-debugging-on-k8s%2Fdocs%2Fbreakpoint.png" alt="Set a breakpoint"&gt;
&lt;/li&gt;
&lt;li&gt;Configure a remote debugger according to &lt;a href="https://www.jetbrains.com/help/pycharm/remote-debugging-with-product.html#remote-debug-config" rel="noopener noreferrer"&gt;these&lt;/a&gt; instructions. use local host name 'localhost' and port 4321. &lt;strong&gt;Important note! use 'Path Mapping' to map your local project directory to the source Workdir in the container image&lt;/strong&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fomrikiei%2Fktunnel%2Fraw%2Fmaster%2Fexamples%2Fpycharm-remote-debugging-on-k8s%2Fdocs%2F%2Fdbg_config.png" alt="Debugger config example"&gt;
&lt;/li&gt;
&lt;li&gt;Start the debugger (&lt;code&gt;Run-&amp;gt;debug remote_server&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 3 - Establish the tunnel
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ./ktunnel inject deployment pyremotedebug 4321
INFO[0000] Debug level is &lt;span class="nb"&gt;set &lt;/span&gt;to info
INFO[0000] Injecting tunnel sidecar to default/pyremotedebug
INFO[0000] Waiting &lt;span class="k"&gt;for &lt;/span&gt;deployment to be ready
INFO[0011] All pods located &lt;span class="k"&gt;for &lt;/span&gt;port-forwarding
INFO[0011] Waiting &lt;span class="k"&gt;for &lt;/span&gt;port forward to finish
INFO[0011] Forwarding from 127.0.0.1:28688 -&amp;gt; 28688
Forwarding from &lt;span class="o"&gt;[&lt;/span&gt;::1]:28688 -&amp;gt; 28688
INFO[0011] starting tcp tunnel from &lt;span class="nb"&gt;source &lt;/span&gt;4321 to target 4321
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4 - Call the debug endpoint
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; curl localhost:8000/debug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the container log you will see the following line:&lt;br&gt;
&lt;code&gt;INFO:root:Connecting to remote debugger on 127.0.0.1:4321&lt;/code&gt;&lt;br&gt;
This means that the debugger is now connected to the runtime&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 5 - Mind Blown
&lt;/h4&gt;

&lt;p&gt;Now, sending a request to the root endpoint will trigger the breakpoint in the IDE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; curl &lt;span class="nt"&gt;-v&lt;/span&gt; localhost:8000/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can change the value of &lt;code&gt;r&lt;/code&gt; in the &lt;code&gt;Evaluate Expression&lt;/code&gt; window to -1, and the result in our terminal:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fomrikiei%2Fktunnel%2Fraw%2Fmaster%2Fexamples%2Fpycharm-remote-debugging-on-k8s%2Fdocs%2Fset_r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fomrikiei%2Fktunnel%2Fraw%2Fmaster%2Fexamples%2Fpycharm-remote-debugging-on-k8s%2Fdocs%2Fset_r.png" alt="Change var"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; curl &lt;span class="nt"&gt;-v&lt;/span&gt; localhost:8000/
&lt;span class="k"&gt;*&lt;/span&gt;   Trying 127.0.0.1...
&lt;span class="k"&gt;*&lt;/span&gt; TCP_NODELAY &lt;span class="nb"&gt;set&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt; Connected to localhost &lt;span class="o"&gt;(&lt;/span&gt;127.0.0.1&lt;span class="o"&gt;)&lt;/span&gt; port 8000 &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="c"&gt;#0)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; GET / HTTP/1.1
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Host: localhost:8000
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; User-Agent: curl/7.54.0
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Accept: &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt; HTTP 1.0, assume close after body
&amp;lt; HTTP/1.0 200 OK
&amp;lt; Content-Type: text/html&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;utf-8
&amp;lt; Content-Length: 33
&amp;lt; Server: Werkzeug/0.16.0 Python/3.7.6
&amp;lt; Date: Wed, 25 Dec 2019 06:15:53 GMT
&amp;lt;
&lt;span class="k"&gt;*&lt;/span&gt; Closing connection 0
Hello, Ktunnel! random number: &lt;span class="nt"&gt;-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Important Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For this to work with your Pycharm installation, the container needs to have a compatible 'pydevd-pycharm' version, in my case it's &lt;code&gt;pydevd-pycharm~=191.7141.48&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If you plan on doing this on production services, know that setting breakpoints on production services is not recommended, do at your own risk!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>python</category>
      <category>pycharm</category>
      <category>intellij</category>
    </item>
  </channel>
</rss>
