<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><generator uri="https://gohugo.io/" version="0.156.0">Hugo</generator><title type="html">Debugging on Marcin Jasion - Pragmatic DevOps</title><link href="https://6f95e4af.mjasion.pages.dev/tags/debugging/" rel="alternate" type="text/html" title="html"/><link href="https://6f95e4af.mjasion.pages.dev/tags/debugging/index.xml" rel="alternate" type="application/rss+xml" title="rss"/><updated>2022-06-10T00:00:00+02:00</updated><id>https://6f95e4af.mjasion.pages.dev/tags/debugging/</id><entry><title type="html">How to enable debug and trace logs in Terraform Cloud and Enterprise</title><link href="https://6f95e4af.mjasion.pages.dev/posts/cloud/how-to-enable-debug-in-terraform-cloud/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://6f95e4af.mjasion.pages.dev/posts/kubernetes/how-to-debug-istio-upstream-reset/?utm_source=atom_feed" rel="related" type="text/html" title="How to debug Istio Upstream Reset 502 UPE (old 503 UC)"/><id>https://6f95e4af.mjasion.pages.dev/posts/cloud/how-to-enable-debug-in-terraform-cloud/</id><author><name>Marcin Jasion</name></author><published>2022-06-10T00:00:00+02:00</published><updated>2022-06-10T00:00:00+02:00</updated><content type="html"><![CDATA[<blockquote>Remote terraform execution does not forward CLI parameters. This post covers how to do this.</blockquote><p><a href="https://cloud.hashicorp.com/products/terraform" target="_blank" rel="noopener">Terraform Cloud</a> is an application that helps teams use Terraform together. I am using it for side projects like my cloud infrastructure. Last time I had to see trace logs to find an issue with one of the managed resources.</p>
<p><a href="https://www.terraform.io/" target="_blank" rel="noopener">Terraform</a> has detailed logs which can be enabled by setting the <code>TF_LOG</code> environment variable to any value. This will cause detailed logs to appear on execution.</p>
<h2 id="enabling-verbose-logging-in-cli">Enabling verbose logging in CLI</h2>
<p>You can set <code>TF_LOG</code> to one of the log levels <code>TRACE</code>, <code>DEBUG</code>, <code>INFO</code>, <code>WARN</code> or <code>ERROR</code> to change the verbosity of the logs. You can set this variable in two ways. First option is to set variable for shell session:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ export TF_LOG<span style="color:#f92672">=</span>TRACE
</span></span><span style="display:flex;"><span>$ terraform plan
</span></span></code></pre></div><p>Second option is to change variable before command execution</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ TF_LOG<span style="color:#f92672">=</span>TRACE terraform plan
</span></span></code></pre></div><h2 id="enabling-logging-in-terraform-cloud">Enabling logging in Terraform Cloud</h2>
<p>If this run is in Terraform Cloud or Terraform Enterprise with Remote Execution, perform these steps:</p>
<ul>
<li>Select your workspace,</li>
<li>Go to <strong>Variables</strong> tab,</li>
<li>Add variable in <strong>Workspace variables</strong> panel and create <code>TF_LOG</code> variable:
<img src="/posts/cloud/how-to-enable-debug-in-terraform-cloud/workspace_variables.png" alt="Workspace Variables">
<blockquote>
<p>Ensure you have selected <strong>Environment variable</strong> button</p>
</blockquote>
</li>
<li>Perform the run that you want to trace</li>
</ul>
<h3 id="another-option-is-to-enable-local-execution">Another option is to enable local execution</h3>
<p>If you are working on your own project, it will be much more convenient to disable Remote Execution and execute the run locally. Go to workspace <strong>Settings</strong> and in <strong>Execution Mode</strong> panel switch the button to <strong>Local</strong>. Then you can run plan from your local machine.</p>
<hr>
<p>Once the issue is resolved, unset the <code>TF_LOG</code> environment variable to disable the enhanced logging.</p>
]]></content><category scheme="https://6f95e4af.mjasion.pages.dev/tags/terraform" term="terraform" label="terraform"/><category scheme="https://6f95e4af.mjasion.pages.dev/tags/terraform-cloud" term="terraform-cloud" label="terraform-cloud"/><category scheme="https://6f95e4af.mjasion.pages.dev/tags/debugging" term="debugging" label="debugging"/></entry><entry><title type="html">How to debug Istio Upstream Reset 502 UPE (old 503 UC)</title><link href="https://6f95e4af.mjasion.pages.dev/posts/kubernetes/how-to-debug-istio-upstream-reset/?utm_source=atom_feed" rel="alternate" type="text/html"/><id>https://6f95e4af.mjasion.pages.dev/posts/kubernetes/how-to-debug-istio-upstream-reset/</id><author><name>Marcin Jasion</name></author><published>2022-04-25T00:00:00+02:00</published><updated>2022-04-25T00:00:00+02:00</updated><content type="html"><![CDATA[<blockquote>Istio can reset processing the request. This blog post shows how to analyze the issue if logs do not help</blockquote><p><a href="https://istio.io" target="_blank" rel="noopener">Istio</a> is a complex system. For the applications, the main component is the sidecar container Istio-Proxy, which proxies all traffic from all containers in Pod. And this can lead to some issues.</p>
<p>This post describes one of the most complicated problems I have encountered in my career.</p>
<h2 id="the-problem---connection-reset-">The problem - Connection Reset 🐛</h2>
<p>During Istio rollout on a huge system, with more than 40 different microservices, on a single endpoint, QA engineers found a bug. It was a POST endpoint, which was returning chunked data.</p>
<p>Istio was returning error 502, in logs an additional flag was visible: <code>upstream_reset_before_response_started</code>. The application logs confirmed that the result was correct.</p>
<blockquote>
<p>In legacy Istio versions of the presented problem Istio were returning <code>503</code> error with <code>UC</code> flag.</p>
</blockquote>
<h2 id="analyzing-issue-">Analyzing issue ⛏️</h2>
<p>Let&rsquo;s see the <code>curl</code> response and look at Istio-proxy logs:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl exec -it curl-0 -- curl http://http-chunked:8080/wrong -v
</span></span><span style="display:flex;"><span>&lt; HTTP/1.1 <span style="color:#ae81ff">502</span> Bad Gateway
</span></span><span style="display:flex;"><span>&lt; content-length: <span style="color:#ae81ff">87</span>
</span></span><span style="display:flex;"><span>&lt; content-type: text/plain
</span></span><span style="display:flex;"><span>&lt; date: Sun, <span style="color:#ae81ff">24</span> Apr <span style="color:#ae81ff">2022</span> 12:28:28 GMT
</span></span><span style="display:flex;"><span>&lt; server: istio-envoy
</span></span><span style="display:flex;"><span>&lt; x-envoy-decorator-operation: http-chunked.default.svc.cluster.local:8080/*
</span></span><span style="display:flex;"><span>upstream connect error or disconnect/reset before headers. reset reason: protocol error
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ kubectl logs http-chunked-0 -c istio-proxy
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span>2022-04-24T12:23:37.047Z<span style="color:#f92672">]</span> <span style="color:#e6db74">&#34;GET /wrong HTTP/1.1&#34;</span> <span style="color:#ae81ff">502</span> UPE upstream_reset_before_response_started<span style="color:#f92672">{</span>protocol_error<span style="color:#f92672">}</span> - <span style="color:#e6db74">&#34;-&#34;</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">87</span> <span style="color:#ae81ff">1001</span> - <span style="color:#e6db74">&#34;-&#34;</span> <span style="color:#e6db74">&#34;curl/7.80.0&#34;</span> <span style="color:#e6db74">&#34;3987a4cb-2e0e-4de6-af66-7e3447600c73&#34;</span> <span style="color:#e6db74">&#34;http-chunked:8080&#34;</span> <span style="color:#e6db74">&#34;10.244.0.17:8080&#34;</span> inbound|8080<span style="color:#f92672">||</span> 127.0.0.6:39063 10.244.0.17:8080 10.244.0.14:35500 - default
</span></span></code></pre></div><h2 id="time-for-spying-">Time for spying 🕵🏻‍♂️</h2>
<p>To analyze the traffic we can use <code>tcpdump</code> and Wireshark. Istio-proxy runs as a sidecar, which routes whole incoming and outgoing traffic to pod through own proxy.
<img src="/posts/kubernetes/how-to-debug-istio-upstream-reset/istio-pod.png" alt="Istio Pod"></p>
<p>To sniff traffic there are 3 ways:</p>
<ol>
<li>Running tcpdump in <code>istio-proxy</code> container,</li>
<li>Using <code>kubectl</code> plugin <code>ksniff</code> - a plugin to kubectl to dump packets from pod, <a href="https://github.com/eldadru/ksniff" target="_blank" rel="noopener">github repo</a>,</li>
<li>Adding additional container to pod, with <code>root</code> permission and <code>tcpdump</code>  installed,</li>
</ol>
<p>The first option will not work by default, because <code>istio-proxy</code> runs without root permission. The third is the backup if 1 and 2 would not work. Let&rsquo;s try <a href="https://github.com/eldadru/ksniff" target="_blank" rel="noopener">ksniff</a>.</p>
<h3 id="what-is-ksniff-">What is ksniff 🛠️</h3>
<p><code>ksniff</code> in three words is a plugin that:</p>
<ul>
<li>figures  out what node is running pod with an app,</li>
<li>deploys an own pod with an affinity to that node, bound to the host network,</li>
<li>opens Wireshark on your laptop with a packet stream from the application.</li>
</ul>
<p>Let&rsquo;s execute it to sniff our application:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>kubectl sniff http-chunked-0 -c istio-proxy -p -f <span style="color:#e6db74">&#39;-i lo&#39;</span> -n default
</span></span></code></pre></div><blockquote>
<p><strong>Important parameters</strong></p>
<ul>
<li><code>-p</code> is a parameter to support sniffing even if the pod is non-privileged. See <a href="https://github.com/eldadru/ksniff#non-privileged-and-scratch-pods" target="_blank" rel="noopener">docs</a>,</li>
<li><code>-f '-i lo'</code> passes filter to tcpdump, we want to sniff localhost interface inside the Pod.</li>
</ul>
</blockquote>
<p>If there is no issue, our system has Wireshark in <code>PATH</code>, <code>ksniff</code> should open a new window
<img src="/posts/kubernetes/how-to-debug-istio-upstream-reset/wireshark_init.png" alt="Wireshark"></p>
<h3 id="finding-the-root-cause-">Finding the root cause 🔎</h3>
<p>Wireshark will continuously follow with new packet records. It makes it hard to figure out our particular call. We can use filters to help with searching. Knowing the request path, method, response code - we can use it to find our packet using filter:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>http.request.uri <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;/wrong&#34;</span>
</span></span></code></pre></div><p>It shows only a single packet, our request. Wireshark allows to show the whole TCP conversation:</p>
<ul>
<li>click right click on the packet,</li>
<li>go to <code>Conversation Filter</code>,</li>
<li>select <code>TCP</code>.</li>
</ul>
<p>Wireshark will write a filter to show the whole communication between istio-proxy container and the application container!</p>
<p><img src="/posts/kubernetes/how-to-debug-istio-upstream-reset/wireshark_convesation_filter.png" alt="Wireshark - Filtering the conversation"></p>
<p>Let&rsquo;s see the above image. The first 3 records are the three-way handshake packets. Later is our GET request.  The most interesting happens in the last two packets. Application container returns response HTTP 200 OK. <code>istio-proxy</code> then closes the connection with <code>RST</code> packet.</p>
<p><img src="/posts/kubernetes/how-to-debug-istio-upstream-reset/app_reset.png" alt="Wireshark - Found RST Packet"></p>
<p>This is what we saw in the logs. The flag was <code>upstream_reset_before_response_started{protocol_error}</code>. But why? This still does not explain.</p>
<h3 id="swiss-knife-by-wireshark-">Swiss knife by Wireshark 🪛</h3>
<p>It is hard to read the HTTP protocol from multiple packet bodies. But Wireshark also has a solution for that. We can see data from L7, the application one. In our case, it is the HTTP protocol.</p>
<p>Click with the right mouse on a single packet, go to the <code>Follow</code> tab, and select <code>TCP Stream</code>:</p>
<p><img src="/posts/kubernetes/how-to-debug-istio-upstream-reset/wireshark_tcp_stream.png" alt="Wireshark - Filtering TCP stream"></p>
<p>Now we can check what the request from <code>istio-proxy</code> looked like, and what was the response from the app.
Do you have an idea from the above picture?</p>
<p>Look closer at the response, there is a double <code>Transfer-Encoding</code> header. One starts from uppercase, the second one does not.</p>
<h3 id="double-transfer-encoding-header---what-does-it-mean">Double transfer-encoding header - what does it mean❔</h3>
<p>Searching over Istio issues I found <a href="https://github.com/istio/istio/issues/24753#issuecomment-656380098" target="_blank" rel="noopener">this answer</a>. The most important are the first 2 points:</p>
<blockquote>
<ol>
<li>two <code>transfer-encoding: chunked</code> is equivalent to <code>transfer-encoding: chunked, chunked</code> as per RFC,</li>
<li><code>transfer-encoding: chunked, chunked</code> doesn&rsquo;t have the same semantic as <code>transfer-encoding: chunked</code></li>
</ol>
</blockquote>
<p>Why the response was taken as double-chunked? According to <a href="https://datatracker.ietf.org/doc/html/rfc7230#section-4" target="_blank" rel="noopener">Transfer Codings in Section 4</a>, transfer-coding names <strong>are case-insensitive</strong>.</p>
<h2 id="summary-">Summary 📓</h2>
<p>As you see, Istio stands as a guard 👮‍♂️ of the HTTP protocol. If the app is returning a double-chunked response, then Istio requires it, otherwise, it rejects processing the request. <code>curl</code> ignores this inconsistency.</p>
<p>This issue was one of the most difficult tasks, which I ever had :-)</p>
<h2 id="infrastructure-to-reproduce-and-example-app-">Infrastructure to reproduce and example app 🏭</h2>
<p>In <a href="https://github.com/mjasion/istio-upstream-reset" target="_blank" rel="noopener">Github repository</a> I created example infrastructure to reproduce the problem.</p>
<p>Bootstrap of the infrastructure installs ArgoCD, Istio and the App. The sample app exposes two endpoints:</p>
<ul>
<li><code>/correct</code> - endpoint, which creates a streamed response,</li>
<li><code>/wrong</code> - is doing same as above, but additionally it set value of the <code>Transfer-Encoding</code> header to <code>Chunked</code>(uppercase).</li>
</ul>
<hr>
<p><em>I would like to thank <a href="https://www.linkedin.com/in/przemyslaw-ozimkiewicz/" target="_blank" rel="noopener">Przemysław</a> for his help and for showing me how to use Wireshark efficiently during this issue.🤝🏻</em></p>
]]></content><category scheme="https://6f95e4af.mjasion.pages.dev/tags/istio" term="istio" label="istio"/><category scheme="https://6f95e4af.mjasion.pages.dev/tags/kubernetes" term="kubernetes" label="kubernetes"/><category scheme="https://6f95e4af.mjasion.pages.dev/tags/debugging" term="debugging" label="debugging"/><category scheme="https://6f95e4af.mjasion.pages.dev/tags/networking" term="networking" label="networking"/></entry></feed>