<?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>Forem: Suave Bajaj</title>
    <description>The latest articles on Forem by Suave Bajaj (@suavebajaj).</description>
    <link>https://forem.com/suavebajaj</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%2F674174%2Fe3017a98-6757-4565-aa95-ac35ac755def.jpeg</url>
      <title>Forem: Suave Bajaj</title>
      <link>https://forem.com/suavebajaj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/suavebajaj"/>
    <language>en</language>
    <item>
      <title>Stop Getting KeyError: '\ufeffName' When Reading CSVs in Python — Here’s the Fix</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Sun, 30 Nov 2025 12:27:05 +0000</pubDate>
      <link>https://forem.com/suavebajaj/stop-getting-keyerror-ufeffname-when-reading-csvs-in-python-heres-the-fix-5e0n</link>
      <guid>https://forem.com/suavebajaj/stop-getting-keyerror-ufeffname-when-reading-csvs-in-python-heres-the-fix-5e0n</guid>
      <description>&lt;p&gt;If you’ve ever tried reading a CSV file in Python and suddenly got this confusing error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\ufeff&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…you’re not alone.&lt;/p&gt;

&lt;p&gt;This problem happens even when the CSV looks perfectly fine, especially if it was exported from Windows or Excel.&lt;br&gt;
There’s an invisible character at the start of the file that Python reads — but you don’t.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let’s break down the issue and the one-line fix.
&lt;/h2&gt;
&lt;h2&gt;
  
  
  The Hidden Problem: BOM (\ufeff)
&lt;/h2&gt;

&lt;p&gt;Many CSV files created on Windows tools include a Byte Order Mark (BOM).&lt;/p&gt;

&lt;p&gt;It’s invisible, but Python treats it as part of the header.&lt;/p&gt;

&lt;p&gt;Example Problem:&lt;/p&gt;

&lt;p&gt;CSV file (data.csv):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name,Age,Email
Alice,25,alice@example.com
Bob,30,bob@example.com
Charlie,28,charlie@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this CSV has a BOM, Python might read the first header as &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;\ufeffName&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;instead of Name, causing key errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\ufeff&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The One-Line Fix: Use utf-8-sig
&lt;/h2&gt;

&lt;p&gt;Python has a specific encoding that automatically removes the BOM while reading:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;utf-8-sig&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just open your file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8-sig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Age&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. Problem solved.&lt;/p&gt;

&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Alice&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="nd"&gt;@example.com&lt;/span&gt;
&lt;span class="n"&gt;Bob&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="nd"&gt;@example.com&lt;/span&gt;
&lt;span class="n"&gt;Charlie&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt; &lt;span class="n"&gt;charlie&lt;/span&gt;&lt;span class="nd"&gt;@example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Works
&lt;/h2&gt;

&lt;p&gt;CSVs exported from Excel often include a BOM&lt;/p&gt;

&lt;p&gt;The BOM is invisible but breaks Python’s header parsing &lt;code&gt;utf-8-sig&lt;/code&gt; automatically removes the BOM before DictReader sees it&lt;/p&gt;

&lt;p&gt;Your script works with any CSV source — Linux, Windows, Mac&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should You Use utf-8-sig?
&lt;/h2&gt;

&lt;p&gt;Use it whenever your CSV comes from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excel&lt;/li&gt;
&lt;li&gt;Windows-based exports&lt;/li&gt;
&lt;li&gt;Enterprise systems&lt;/li&gt;
&lt;li&gt;Unknown or mixed data sources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a safe default and won’t break anything even if the file contains no BOM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you encounter weird CSV header issues or errors like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\ufeff&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;just open your CSV like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8-sig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one line removes BOM automatically and makes your CSV reading code clean, stable, and cross-platform.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>productivity</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Kubernetes Autoscaling with Custom Scaler: Event-Driven Scaling for Queues and Microservices – Part 2</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Fri, 26 Sep 2025 10:00:04 +0000</pubDate>
      <link>https://forem.com/suavebajaj/kubernetes-autoscaling-with-custom-scaler-event-driven-scaling-for-queues-and-microservices-part-180</link>
      <guid>https://forem.com/suavebajaj/kubernetes-autoscaling-with-custom-scaler-event-driven-scaling-for-queues-and-microservices-part-180</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/suavebajaj/kubernetes-autoscaling-with-keda-event-driven-scaling-for-queues-and-microservices-part-1-2bhp"&gt;Part 1&lt;/a&gt;, we explored &lt;a href="https://keda.sh" rel="noopener noreferrer"&gt;KEDA&lt;/a&gt; and how it scales your consumers based on queue depth.  &lt;/p&gt;

&lt;p&gt;But what if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have &lt;strong&gt;N queues → M consumers&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Each queue has &lt;strong&gt;different thresholds, min, and max replicas&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Each consumer has a &lt;strong&gt;different workflow / endpoint&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;KEDA alone can’t handle this. That’s where a &lt;strong&gt;custom autoscaler&lt;/strong&gt; comes in.&lt;/p&gt;




&lt;h3&gt;
  
  
  Problem Statement
&lt;/h3&gt;

&lt;p&gt;Example scenario:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Queue&lt;/th&gt;
&lt;th&gt;Consumer Deployment&lt;/th&gt;
&lt;th&gt;Threshold&lt;/th&gt;
&lt;th&gt;Min Pods&lt;/th&gt;
&lt;th&gt;Max Pods&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;x-queue-1&lt;/td&gt;
&lt;td&gt;consumer-x-1&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x-queue-2&lt;/td&gt;
&lt;td&gt;consumer-x-2&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;y-queue&lt;/td&gt;
&lt;td&gt;consumer-y&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Each queue has &lt;strong&gt;its own processing logic&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Scaling decisions must be &lt;strong&gt;independent&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Min/Max replicas can be &lt;strong&gt;defined dynamically in a database&lt;/strong&gt; for flexibility.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Architecture Overview
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────┐
│     Producers          │
│  (Apps push messages   │
│   to queues)           │
└─────────┬─────────────┘
          │
          ▼
 ┌─────────────────┐
 │  Message Broker  │
 │  (Kafka/Rabbit)  │
 └─────────┬────────┘
           │
┌──────────┴──────────┐
▼                     ▼
┌─────────────────────┐       ┌─────────────────────┐
│  Python Exporter    │       │ Prometheus Metrics  │
│ - Reads queue depth │◄─────►│ storage             │
│ - Reads min/max     │       └─────────────────────┘
│   from DB           │
│ - Applies scaling   │
│   logic per queue   │
│ - Calls Kubernetes  │
│   API to scale      │
└─────────┬───────────┘
          │
          ▼
┌─────────────────────────────┐
│ Consumer Deployments         │
│ - pod-deployment-1          │
│ - pod-deployment-2          │
│ - pod-deployment-y          │
└─────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Python Example: Custom Scaling with DB Min/Max
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;kubernetes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;  &lt;span class="c1"&gt;# Example DB; replace with your real DB
&lt;/span&gt;
&lt;span class="c1"&gt;# Load in-cluster config
&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_incluster_config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;apps_v1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AppsV1Api&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Connect to database containing min/max per consumer
&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumer_scaling.db&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Read scaling config for all consumers
&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT consumer_name, queue_name, threshold, min_pods, max_pods FROM scaling_config&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;scaling_rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Prometheus endpoint
&lt;/span&gt;&lt;span class="n"&gt;prometheus_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://prometheus:9090/api/v1/query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;consumer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queue_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_pods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_pods&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;queue_config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Query current queue depth
&lt;/span&gt;    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sum(queue_depth{{queue=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;queue_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;}})&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prometheus_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;queue_depth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# Calculate desired replicas using custom logic
&lt;/span&gt;    &lt;span class="n"&gt;desired_replicas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_pods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_pods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_depth&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="c1"&gt;# Scale Deployment
&lt;/span&gt;    &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;V1Scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;V1ScaleSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;desired_replicas&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;apps_v1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace_namespaced_deployment_scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;consumer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;consumer_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: queue=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;queue_depth&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, threshold=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, scaled to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;desired_replicas&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; pods&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;threshold&lt;/code&gt; is &lt;strong&gt;per queue&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;min_pods&lt;/code&gt; and &lt;code&gt;max_pods&lt;/code&gt; are read from a &lt;strong&gt;database&lt;/strong&gt;, making it dynamic.&lt;/li&gt;
&lt;li&gt;You can extend logic to include &lt;strong&gt;weighted scaling, multiple metrics&lt;/strong&gt;, or &lt;strong&gt;cooldown periods&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Advantages of Custom Autoscaler
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Independent scaling &lt;strong&gt;per queue&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic min/max replicas&lt;/strong&gt; from DB — no hardcoding&lt;/li&gt;
&lt;li&gt;Multi-metric decisions (queue depth, CPU, DB lag, etc.)&lt;/li&gt;
&lt;li&gt;Advanced logic (cooldowns, weighted scaling, prioritization)&lt;/li&gt;
&lt;li&gt;Can handle &lt;strong&gt;N queues → M consumers&lt;/strong&gt; mapping flexibly&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Trade-offs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;KEDA&lt;/th&gt;
&lt;th&gt;Custom Autoscaler&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Easy setup&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ (Python + DB + K8s API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Independent queue scaling&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-metric logic&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB-driven min/max&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;✅ Battle-tested&lt;/td&gt;
&lt;td&gt;⚠️ Managed by you&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  ✅ Takeaways
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;KEDA is great for &lt;strong&gt;simple queue scaling&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;complex microservices with multiple queues&lt;/strong&gt;, custom autoscaler gives &lt;strong&gt;full control&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Using a &lt;strong&gt;database for min/max replicas&lt;/strong&gt; allows dynamic, production-ready scaling policies.
&lt;/li&gt;
&lt;li&gt;Your custom autoscaler can evolve into a &lt;strong&gt;custom HPA/KEDA&lt;/strong&gt; tailored to your architecture.
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;💡 &lt;strong&gt;Pro Tip:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Start with KEDA for simple cases. Move to a &lt;strong&gt;custom autoscaler&lt;/strong&gt; with DB-defined min/max for multi-queue microservices with complex workflows.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>autoscaling</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Kubernetes Autoscaling with KEDA: Event-Driven Scaling for Queues and Microservices – Part 1</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Sat, 20 Sep 2025 09:23:33 +0000</pubDate>
      <link>https://forem.com/suavebajaj/kubernetes-autoscaling-with-keda-event-driven-scaling-for-queues-and-microservices-part-1-2bhp</link>
      <guid>https://forem.com/suavebajaj/kubernetes-autoscaling-with-keda-event-driven-scaling-for-queues-and-microservices-part-1-2bhp</guid>
      <description>&lt;h2&gt;
  
  
  KEDA &amp;amp; Event-Driven Autoscaling: Solving Queue Backlogs in Kubernetes
&lt;/h2&gt;

&lt;p&gt;If you've ever run Kafka or RabbitMQ consumers in Kubernetes, you know the pain: your consumers are either &lt;strong&gt;underutilized&lt;/strong&gt; or &lt;strong&gt;overloaded&lt;/strong&gt;, and CPU-based HPA just doesn’t cut it.  &lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;KEDA&lt;/strong&gt; — Kubernetes-based Event-Driven Autoscaling.&lt;br&gt;
&lt;a href="https://keda.sh/" rel="noopener noreferrer"&gt;KEDA&lt;/a&gt; &lt;a href="https://github.com/kedacore/keda" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  What is KEDA?
&lt;/h3&gt;

&lt;p&gt;KEDA is a &lt;strong&gt;lightweight autoscaler&lt;/strong&gt; that scales your Kubernetes workloads based on &lt;strong&gt;external events or metrics&lt;/strong&gt;, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Queue length in Kafka or RabbitMQ
&lt;/li&gt;
&lt;li&gt;Prometheus metrics
&lt;/li&gt;
&lt;li&gt;Cloud events (Azure, AWS, GCP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike HPA which scales on CPU/memory, &lt;strong&gt;KEDA lets your pods scale dynamically based on actual workload&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; KEDA itself runs as a &lt;strong&gt;Deployment in your Kubernetes cluster&lt;/strong&gt;.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s not a StatefulSet or a special Deployment of your app.
&lt;/li&gt;
&lt;li&gt;It consumes CPU/memory like any other Deployment depending on the number of ScaledObjects and triggers you define.
&lt;/li&gt;
&lt;li&gt;This means if you define many queues, KEDA’s own Deployment will grow in resource usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  How KEDA Works
&lt;/h3&gt;

&lt;p&gt;KEDA introduces a new Kubernetes object called a &lt;strong&gt;ScaledObject&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ScaledObject → Deployment&lt;/strong&gt; mapping: tells KEDA which workload to scale.&lt;/li&gt;
&lt;li&gt;Each ScaledObject can have &lt;strong&gt;one or more triggers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaling logic&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;OR logic across triggers (if &lt;em&gt;any trigger&lt;/em&gt; exceeds threshold → scale).
&lt;/li&gt;
&lt;li&gt;Cannot independently scale subsets of pods within the same Deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Example: RabbitMQ ScaledObject
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;keda.sh/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ScaledObject&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orders-consumer-scaler&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orders-consumer&lt;/span&gt;
  &lt;span class="na"&gt;minReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbitmq&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;orders-queue&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amqp://guest:guest@rabbitmq:5672/&lt;/span&gt;
      &lt;span class="na"&gt;queueLength&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explanation:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;orders-consumer&lt;/code&gt; Deployment will scale 1→10 pods depending on queue length.&lt;/li&gt;
&lt;li&gt;Scaling happens if the queue length &amp;gt; 100.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  KEDA &amp;amp; Event-Driven Autoscaling: Solving Queue Backlogs in Kubernetes
&lt;/h3&gt;

&lt;p&gt;If you've ever run Kafka or RabbitMQ consumers in Kubernetes, you know the pain: your consumers are either &lt;strong&gt;underutilized&lt;/strong&gt; or &lt;strong&gt;overloaded&lt;/strong&gt;, and CPU-based HPA just doesn’t cut it.  &lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;KEDA&lt;/strong&gt; — Kubernetes-based Event-Driven Autoscaling.&lt;/p&gt;


&lt;h3&gt;
  
  
  How KEDA Determines the Number of Pods
&lt;/h3&gt;

&lt;p&gt;KEDA computes &lt;strong&gt;desired replicas&lt;/strong&gt; based on the queue metric and thresholds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Threshold value (&lt;code&gt;queueLength&lt;/code&gt;)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The metric KEDA monitors (queue depth).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Min and Max Replicas&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;minReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;maxReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;**Desired replicas calculation (simplified):
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;desiredReplicas = ceil(currentQueueLength / queueLengthThreshold)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;**Scaling applied via HPA&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;KEDA updates the Deployment replicas between &lt;code&gt;minReplicaCount&lt;/code&gt; and &lt;code&gt;maxReplicaCount&lt;/code&gt;&lt;/p&gt;


&lt;h4&gt;
  
  
  Visual Example
&lt;/h4&gt;

&lt;p&gt;Imagine orders-queue has a threshold of 100 messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Queue Depth → Desired Replicas → Deployment Pods
------------------------------------------------
50          → 1                 → 1 pod (minReplicaCount)
120         → 2                 → 2 pods
250         → 3                 → 3 pods
1050        → 11                → 10 pods (maxReplicaCount)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diagram: Queue Depth → Desired Replicas → Deployment Scaling&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Queue Depth: 250]
        │
        ▼
[Threshold: 100 per pod]
        │
        ▼
[Desired Replicas: ceil(250/100) = 3]
        │
        ▼
[orders-consumer Deployment scales to 3 pods]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Limitations of KEDA
&lt;/h3&gt;

&lt;p&gt;While KEDA is powerful, it has some critical limitations:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;N queues → N consumers is not supported natively&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You cannot define multiple queues with different consumer Deployments in a single ScaledObject.&lt;/p&gt;

&lt;p&gt;Scaling logic is OR across triggers; all pods scale together.&lt;/p&gt;

&lt;p&gt;Not ideal for microservices with multiple queues and workflows&lt;/p&gt;

&lt;p&gt;Example: if you have 10 queues with different processing logic/endpoints, KEDA alone cannot scale them independently.&lt;/p&gt;

&lt;p&gt;You’d need multiple Deployments + multiple ScaledObjects, which becomes cumbersome.&lt;/p&gt;




&lt;h3&gt;
  
  
  Resource consumption
&lt;/h3&gt;

&lt;p&gt;KEDA itself is a Deployment; each ScaledObject adds CPU/memory usage.&lt;/p&gt;

&lt;p&gt;Scaling many queues can increase the resource footprint on the cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubectl Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After creating multiple ScaledObjects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get scaledobjects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                       SCALETARGETKIND      SCALETARGETNAME     MIN   MAX   TRIGGERS
orders-consumer-scaler     apps/v1.Deployment   orders-consumer      1    10    rabbitmq
payments-consumer-scaler   apps/v1.Deployment   payments-consumer    1     5    rabbitmq
kafka-consumer-scaler      apps/v1.Deployment   kafka-consumer       1    15    kafka
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;ScaledObject&lt;/code&gt; targets a single Deployment.&lt;/p&gt;

&lt;p&gt;Multiple triggers for the same Deployment scale all pods together (OR logic).&lt;/p&gt;




&lt;h3&gt;
  
  
  Takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;KEDA is great for simple event-driven scaling.&lt;/li&gt;
&lt;li&gt;Each ScaledObject → one Deployment.&lt;/li&gt;
&lt;li&gt;OR logic for multiple triggers → not suitable for microservices with multiple queues and workflows.&lt;/li&gt;
&lt;li&gt;KEDA computes replicas automatically using the metric and threshold, scaling Deployment pods between min and max.&lt;/li&gt;
&lt;li&gt;Resource footprint increases with more ScaledObjects and triggers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Part 2 will show how to build a custom autoscaler that can handle multiple queues, multiple consumers, and independent scaling logic for complex microservices.&lt;/p&gt;




&lt;p&gt;Pro Tip: Start with KEDA for simple queue scaling. For complex, multi-queue microservices, a custom HPA/KEDA solution is usually required.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>keda</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Docker Best Practices: Reduce Image Size + Common Interview Questions</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Wed, 10 Sep 2025 09:43:26 +0000</pubDate>
      <link>https://forem.com/suavebajaj/docker-best-practices-reduce-image-size-common-interview-questions-4hen</link>
      <guid>https://forem.com/suavebajaj/docker-best-practices-reduce-image-size-common-interview-questions-4hen</guid>
      <description>&lt;p&gt;When working with &lt;strong&gt;Docker images&lt;/strong&gt; in production, size matters a lot.&lt;br&gt;&lt;br&gt;
Large images mean &lt;strong&gt;longer build times&lt;/strong&gt;, &lt;strong&gt;slower deployments&lt;/strong&gt;, and even &lt;strong&gt;higher storage costs&lt;/strong&gt; in container registries like GCP Artifact Registry or Docker Hub.  &lt;/p&gt;

&lt;p&gt;In one of our projects, the image size grew beyond &lt;strong&gt;1.9 GB&lt;/strong&gt;, and we optimized it down to just &lt;strong&gt;495 MB&lt;/strong&gt; — a &lt;strong&gt;75% reduction&lt;/strong&gt;. Here’s how we did it.&lt;/p&gt;

&lt;p&gt;Bonus : Have shared common inteview prep questions and answers in the end.&lt;/p&gt;


&lt;h3&gt;
  
  
  🔹 Why Docker Image Size Matters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;⏱ Faster builds &amp;amp; CI/CD pipelines
&lt;/li&gt;
&lt;li&gt;📦 Less storage usage in registries
&lt;/li&gt;
&lt;li&gt;🚀 Faster deployments &amp;amp; scaling
&lt;/li&gt;
&lt;li&gt;💰 Lower cloud costs
&lt;/li&gt;
&lt;li&gt;🔒 Smaller attack surface
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  🔹 Our Starting Point
&lt;/h3&gt;

&lt;p&gt;We started with this &lt;strong&gt;basic Dockerfile&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; google/cloud-sdk:latest&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python3", "app.py"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ❌ Problems with this approach
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;google/cloud-sdk:latest&lt;/code&gt; is &lt;strong&gt;~3 GB&lt;/strong&gt; 😱
&lt;/li&gt;
&lt;li&gt;Copying everything at once invalidates Docker cache → slow builds
&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;.dockerignore&lt;/code&gt; → unnecessary files (e.g., &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;__pycache__&lt;/code&gt;, &lt;code&gt;.vscode/&lt;/code&gt;) got copied
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pip install&lt;/code&gt; cached dependencies → bloated layers
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔹 Optimized Approach
&lt;/h3&gt;

&lt;p&gt;We switched to a &lt;strong&gt;smaller base image&lt;/strong&gt; and installed only what we need.&lt;/p&gt;

&lt;h5&gt;
  
  
  ✅ Optimized Dockerfile
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Install gcloud SDK (instead of using 3GB google/cloud-sdk image)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; apt-transport-https ca-certificates gnupg curl &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/apt/sources.list.d/google-cloud-sdk.list &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /usr/share/keyrings/cloud.google.gpg &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; google-cloud-sdk &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;# Copy only requirements first (for caching)&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Copy application code&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python3", "app.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔹 Why This Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Slim Base Image&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;python:3.12-slim&lt;/code&gt; is just &lt;strong&gt;124 MB&lt;/strong&gt; vs &lt;code&gt;google/cloud-sdk:latest&lt;/code&gt; at &lt;strong&gt;~3 GB&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;We add only the &lt;code&gt;gcloud&lt;/code&gt; tools we need (&lt;code&gt;gsutil&lt;/code&gt;, &lt;code&gt;gcloud sql&lt;/code&gt;, etc.).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cache-Friendly Layering&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;COPY requirements.txt&lt;/code&gt; first → &lt;code&gt;pip install&lt;/code&gt; is cached until dependencies change.
&lt;/li&gt;
&lt;li&gt;App code changes don’t trigger dependency reinstall.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;.dockerignore&lt;/code&gt; Optimization&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A &lt;code&gt;.dockerignore&lt;/code&gt; file prevents unnecessary files from being copied into the image:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   __pycache__/
   *.pyc
   *.pyo
   *.pyd
   .Python
   .git
   .vscode
   .DS_Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps unnecessary files out of the image.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;No Pip Cache&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;pip install --no-cache-dir&lt;/code&gt; avoids leaving hundreds of MB in cached wheels.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;APT Cleanup&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rm -rf /var/lib/apt/lists/*&lt;/code&gt; keeps layers lean.  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  📊 Before vs After
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;testv1.5.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.96 GB&lt;/td&gt;
&lt;td&gt;Full &lt;code&gt;google/cloud-sdk&lt;/code&gt;, no cleanup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v1.6.9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.36 GB&lt;/td&gt;
&lt;td&gt;Slim base, partial optimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;testv1.4.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;495 MB&lt;/td&gt;
&lt;td&gt;Slim base + caching + &lt;code&gt;.dockerignore&lt;/code&gt; + cleanup&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;💡 &lt;strong&gt;Result&lt;/strong&gt;: 75% reduction in size 🚀  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;3x faster builds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster pushes/pulls from Artifact Registry&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower cloud storage costs&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔹 Common Interview Questions on Docker Image Optimization
&lt;/h3&gt;

&lt;p&gt;If you’re preparing for DevOps/SRE interviews, expect questions like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q1. How do you reduce Docker image size?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use slim base images.
&lt;/li&gt;
&lt;li&gt;Multi-stage builds.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.dockerignore&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Remove build-time dependencies.
&lt;/li&gt;
&lt;li&gt;Clean caches (&lt;code&gt;pip&lt;/code&gt;, &lt;code&gt;apt&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Q2. Why copy &lt;code&gt;requirements.txt&lt;/code&gt; separately before app code?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To leverage Docker’s layer caching → only reinstall deps when requirements change.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Q3. What’s the role of &lt;code&gt;.dockerignore&lt;/code&gt;?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevents unnecessary files (like &lt;code&gt;.git&lt;/code&gt;, logs, caches) from being copied → smaller, cleaner image.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Q4. When should you use multi-stage builds?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When compiling dependencies (Go, Java, C extensions).
&lt;/li&gt;
&lt;li&gt;First stage: build artifacts.
&lt;/li&gt;
&lt;li&gt;Second stage: copy only binaries/libs into a minimal runtime image.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Q5. Why not use &lt;code&gt;google/cloud-sdk:latest&lt;/code&gt; directly?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s &lt;strong&gt;huge (~3 GB)&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Installing only required gcloud components on &lt;code&gt;python:slim&lt;/code&gt; keeps image much smaller.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🚀 Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Optimizing Dockerfiles is not just about saving space — it impacts &lt;strong&gt;CI/CD speed&lt;/strong&gt;, &lt;strong&gt;developer productivity&lt;/strong&gt;, and &lt;strong&gt;cloud costs&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;By combining &lt;strong&gt;slim images&lt;/strong&gt;, &lt;strong&gt;layer caching&lt;/strong&gt;, &lt;strong&gt;.dockerignore&lt;/strong&gt;, and &lt;strong&gt;minimal installs&lt;/strong&gt;, you can cut image sizes dramatically.  &lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>interview</category>
      <category>cloud</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Sun, 20 Jul 2025 08:09:35 +0000</pubDate>
      <link>https://forem.com/suavebajaj/-24gc</link>
      <guid>https://forem.com/suavebajaj/-24gc</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/suavebajaj/authenticate-docker-with-google-artifact-registry-private-repo-using-a-service-account-158a" class="crayons-story__hidden-navigation-link"&gt;Authenticate Docker with Google Artifact Registry (Private Repo) Using a Service Account&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/suavebajaj" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F674174%2Fe3017a98-6757-4565-aa95-ac35ac755def.jpeg" alt="suavebajaj profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/suavebajaj" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Suave Bajaj
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Suave Bajaj
                
              
              &lt;div id="story-author-preview-content-2689580" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/suavebajaj" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F674174%2Fe3017a98-6757-4565-aa95-ac35ac755def.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Suave Bajaj&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/suavebajaj/authenticate-docker-with-google-artifact-registry-private-repo-using-a-service-account-158a" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/suavebajaj/authenticate-docker-with-google-artifact-registry-private-repo-using-a-service-account-158a" id="article-link-2689580"&gt;
          Authenticate Docker with Google Artifact Registry (Private Repo) Using a Service Account
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/docker"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;docker&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gcp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gcp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/suavebajaj/authenticate-docker-with-google-artifact-registry-private-repo-using-a-service-account-158a#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>docker</category>
      <category>gcp</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Authenticate Docker with Google Artifact Registry (Private Repo) Using a Service Account</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Tue, 15 Jul 2025 08:03:32 +0000</pubDate>
      <link>https://forem.com/suavebajaj/authenticate-docker-with-google-artifact-registry-private-repo-using-a-service-account-158a</link>
      <guid>https://forem.com/suavebajaj/authenticate-docker-with-google-artifact-registry-private-repo-using-a-service-account-158a</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;⚡ &lt;strong&gt;TL;DR&lt;/strong&gt;: Want to push/pull private Docker images from Google Artifact Registry? Use a Google Cloud service account with &lt;code&gt;docker login -u _json_key&lt;/code&gt;, then use the &lt;code&gt;.docker/config.json&lt;/code&gt; for Kubernetes integration.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  🧰 Prerequisites
&lt;/h3&gt;

&lt;p&gt;Make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker installed locally or in your CI/CD agent&lt;/li&gt;
&lt;li&gt;Google Cloud SDK (&lt;code&gt;gcloud&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;private Artifact Registry&lt;/strong&gt; (e.g. &lt;code&gt;us-central1-docker.pkg.dev/&amp;lt;project&amp;gt;/&amp;lt;repo&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A service account with &lt;code&gt;Artifact Registry Reader&lt;/code&gt; or &lt;code&gt;Writer&lt;/code&gt; permissions&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ⚙️ Step 1: Create a Service Account Key
&lt;/h3&gt;

&lt;p&gt;Create a key file to authenticate Docker later:&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="c"&gt;# Create a new key for your artifact registry service account&lt;/span&gt;
gcloud iam service-accounts keys create key.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--iam-account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gar-access@&amp;lt;PROJECT_ID&amp;gt;.iam.gserviceaccount.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This will download a key.json file locally.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  🔐 Step 2: Authenticate Docker with the Key
&lt;/h3&gt;

&lt;p&gt;Use the service account to log in to your private Artifact Registry:&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="c"&gt;# Replace the region with your registry's location&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;key.json | docker login &lt;span class="nt"&gt;-u&lt;/span&gt; _json_key &lt;span class="nt"&gt;--password-stdin&lt;/span&gt; https://us-central1-docker.pkg.dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This command updates your ~/.docker/config.json to include authentication for the private registry.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  📁 What the Docker Config File Looks Like
&lt;/h3&gt;

&lt;p&gt;After successful login, your ~/.docker/config.json will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"auths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"https://us-central1-docker.pkg.dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Base&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;token&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"currentContext"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"colima"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;per&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;client&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use this file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a Kubernetes image pull secret&lt;/li&gt;
&lt;li&gt;In CI/CD pipelines&lt;/li&gt;
&lt;li&gt;For temporary access without gcloud&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🚀 Use in CI/CD and Kubernetes
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;🧪 In CI/CD (GitHub Actions, GitLab, Jenkins, etc.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can use the same &lt;code&gt;docker login&lt;/code&gt; step using the service account key during your pipeline execution.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📦 In Kubernetes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To use this config as a Kubernetes secret:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic regcred &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.dockerconfigjson&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.docker/config.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;kubernetes.io/dockerconfigjson
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reference it in your Deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;private-reg&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;private-reg-container&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your-private-image&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regcred&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔍 Verify the Setup
&lt;/h3&gt;

&lt;p&gt;Once authenticated, verify the setup by building, tagging, and pushing an image to your private Artifact Registry.&lt;/p&gt;

&lt;h4&gt;
  
  
  🛠️ Build the Docker Image
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; myapp:latest &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;#Replace myapp with your actual app name, and ensure your Dockerfile is in the current directory.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  🏷️ Tag the Image
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker tag myapp:latest us-central1-docker.pkg.dev/&amp;lt;project&amp;gt;/&amp;lt;repo&amp;gt;/myapp:latest
&lt;span class="c"&gt;#Replace &amp;lt;project&amp;gt; and &amp;lt;repo&amp;gt; with your actual GCP project ID and Artifact Registry repository.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  📤 Push the Image
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker push us-central1-docker.pkg.dev/&amp;lt;project&amp;gt;/&amp;lt;repo&amp;gt;/myapp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  📥 Optionally, Pull to Confirm
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull us-central1-docker.pkg.dev/&amp;lt;project&amp;gt;/&amp;lt;repo&amp;gt;/myapp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If these steps complete without errors, your service account authentication and private registry access are working perfectly!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  ✅ Summary and References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use a Google Cloud service account with _json_key to securely access private Artifact Registry images.&lt;/li&gt;
&lt;li&gt;docker login will generate a valid config.json.&lt;/li&gt;
&lt;li&gt;Use that config for Kubernetes and CI/CD integration.&lt;/li&gt;
&lt;li&gt;No need for gcloud runtime dependencies in CI.&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;📘 &lt;a href="https://cloud.google.com/artifact-registry/docs/docker/authentication#json-key" rel="noopener noreferrer"&gt;Google Artifact Registry Authentication&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐳 &lt;a href="https://github.com/GoogleCloudPlatform/docker-credential-gcr" rel="noopener noreferrer"&gt;Docker Credential Helpers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;☸️ &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/" rel="noopener noreferrer"&gt;Kubernetes: Pull an Image from a Private Registry&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>gcp</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>🚀 My First Flask API – Lightweight Monitoring Data Server (with Deep Dive)</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Wed, 09 Jul 2025 07:11:28 +0000</pubDate>
      <link>https://forem.com/suavebajaj/my-first-flask-api-lightweight-monitoring-data-server-with-deep-dive-ok4</link>
      <guid>https://forem.com/suavebajaj/my-first-flask-api-lightweight-monitoring-data-server-with-deep-dive-ok4</guid>
      <description>&lt;p&gt;Hey folks! 👋&lt;/p&gt;

&lt;p&gt;I recently built my &lt;strong&gt;first API using Flask&lt;/strong&gt; and wanted to share the experience — not just the code, but also &lt;strong&gt;how it works&lt;/strong&gt;, &lt;strong&gt;what each part does&lt;/strong&gt;, and &lt;strong&gt;how you can run it yourself&lt;/strong&gt;. If you're learning Flask or curious about simple data-serving APIs, this might help!&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What This API Does
&lt;/h2&gt;

&lt;p&gt;This Flask API serves precomputed monitoring data for various backend services (like Kafka, RabbitMQ, etc.) using &lt;code&gt;.json&lt;/code&gt; files. Here's what it can do:&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ 1. Returns JSON Files Containing Health Data
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Data for each service is stored as JSON files in a structured directory.&lt;/li&gt;
&lt;li&gt;You can query the API with parameters like &lt;code&gt;stackname&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt;, and &lt;code&gt;time&lt;/code&gt; to get specific metrics.&lt;/li&gt;
&lt;li&gt;Example:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;/getdata?stackname=retail&amp;amp;service=kafka&amp;amp;time=20240708&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This returns the contents of:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;/data-files/retail/kafka_20240708.json&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ 2. Compares Two Time Periods for the Same Service
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can compare a service's performance between two timestamps:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;/getdata/comparison?stackname=retail&amp;amp;service=kafka&amp;amp;start_time=20240701&amp;amp;end_time=20240707&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This returns:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/data-files/retail/comparisons/kafka_20240701_vs_20240707.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Useful for catching trends, regressions, or improvements.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ 3. Displays a Landing Page with All Available Endpoints
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Visit the root &lt;code&gt;/&lt;/code&gt; to get a helpful summary:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"👋 Welcome to the API!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"available_endpoints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"/getdata/comparison"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET with params: stackname, service, start_time, end_time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"/getdata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET with params: stackname, service, time"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"available_services"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"elasticsearch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rabbitmq"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pods"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"responsetime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"logsearch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kafka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asciapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"consul"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"running"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔍 Code Walkthrough
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;app.py&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datahandler&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DataHandler&lt;/span&gt;

&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_url_rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/getdata/comparison&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;getcomparisondata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_comparison_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_url_rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/getdata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stackdata&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_stack_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_url_rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;landingpage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_landing_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;datahandler.py&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;send_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;BASE_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;files_file_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;..&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data-files&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;config_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;..&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data_config.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;valid_data_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;valid_data_paths&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_comparison_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;stackname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stackname&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;start_time&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;end_time&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;file_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stackname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_vs_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files_file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stackname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comparisons&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;send_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mimetype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_stack_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;stackname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stackname&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid_data_paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;file_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stackname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files_file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stackname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;send_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mimetype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid data type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_landing_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Welcome to the API!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;available_endpoints&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/getdata/comparison&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET with params: stackname, service, start_time, end_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/getdata&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET with params: stackname, service, time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;available_services&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid_data_paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;running&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mimetype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ▶️ How to Run It
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Install Flask:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Run the python code&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Open your browser and visit or use the POSTMAN tool to get the details&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8080/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  💡 What Does Each Line in app.run() Do?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Argument&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;debug=True&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-reloads the app on code changes and shows detailed error messages. Great for dev, &lt;strong&gt;not for prod&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;port=8080&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs the app on port 8080 instead of the default 5000.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;host='0.0.0.0'&lt;/code&gt; (optional)&lt;/td&gt;
&lt;td&gt;Allows access from any IP address (e.g., Docker or public cloud).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔗 Query Parameters in Flask
&lt;/h3&gt;

&lt;p&gt;You pass arguments like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;getdata&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="n"&gt;stackname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prod&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pods&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0708&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And extract them in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stackname&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also give default values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;default_service&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🛠️ Lessons I Learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;How to use Flask routing and send_file() for static JSON&lt;/li&gt;
&lt;li&gt;The importance of modular design (datahandler.py)&lt;/li&gt;
&lt;li&gt;Building an API without needing a full DB&lt;/li&gt;
&lt;li&gt;Making endpoints self-documenting for easy testing and consumption&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Capture the Magic: Mastering Star Trails with Your Galaxy S23 Ultra</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Mon, 24 Jun 2024 08:51:51 +0000</pubDate>
      <link>https://forem.com/suavebajaj/capture-the-magic-mastering-star-trails-with-your-galaxy-s23-ultra-3g03</link>
      <guid>https://forem.com/suavebajaj/capture-the-magic-mastering-star-trails-with-your-galaxy-s23-ultra-3g03</guid>
      <description>&lt;p&gt;Have you ever gazed up at a night sky teeming with stars and wished you could capture their mesmerizing movement? With the innovative camera features of the Galaxy S23 Ultra, transforming that starry expanse into a captivating image of star trails is within reach!&lt;/p&gt;

&lt;p&gt;This guide will unveil the secrets to capturing stunning star trails using your S23 Ultra, allowing you to immortalize the Earth's rotation on camera. &lt;a href="https://youtube.com/shorts/MjArEEphPT8?feature=share"&gt;Watch the youtube short of the star trails here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Gear Up for the Night:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Galaxy S23 Ultra: The star of the show, of course!&lt;/li&gt;
&lt;li&gt;Tripod: Essential for ensuring complete image stability during the long exposure required for star trails.&lt;/li&gt;
&lt;li&gt;Remote Shutter Release (Optional): Minimizes camera shake when triggering the capture.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Finding the Perfect Night Sky:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Escape Light Pollution: City lights wash out the faint starlight needed for star trails. Seek out a dark location, preferably far from urban areas. National parks and remote areas are ideal.&lt;/li&gt;
&lt;li&gt;Favor Clear Skies: Obstructions like clouds can significantly hinder your capture. Aim for a clear, starry night with minimal cloud cover.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Unleashing the Power of Hyperlapse:
&lt;/h2&gt;

&lt;p&gt;The Galaxy S23 Ultra's Hyperlapse mode is the key to creating stunning star trails. Here's how to use it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch the Camera App: Open the default camera application on your S23 Ultra.&lt;/li&gt;
&lt;li&gt;Switch to Hyperlapse Mode: Swipe through the shooting modes until you find "Hyperlapse."&lt;/li&gt;
&lt;li&gt;Maximize Resolution: Tap on the resolution icon and choose the highest option, ideally UHD (Ultra High Definition).&lt;/li&gt;
&lt;li&gt;Set the Speed: Select the recording speed. For capturing star trails, a speed of X300 is recommended.&lt;/li&gt;
&lt;li&gt;Activate Star Trails: Look for the "Star Trails" icon (it might resemble tiny stars) and tap on it to enable this specific capture mode within Hyperlapse.&lt;/li&gt;
&lt;li&gt;Frame Your Shot: Compose your desired shot. Consider including interesting foreground elements like mountains or trees to add depth to your final image.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Capturing the Night's Journey:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hit Record: Press the shutter button to begin recording the star trails. Remember, capturing good star trails requires a long exposure, so be prepared to let the camera record for at least 1 hour to 2 hours (or even longer) for a more dramatic effect. &lt;a href="https://youtube.com/shorts/MjArEEphPT8?feature=share"&gt;Watch the youtube short of the star trails here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Maintain Stability: Using a tripod is crucial. Even the slightest movement can blur your image. A remote shutter release can further minimize camera shake.&lt;/li&gt;
&lt;li&gt;Monitor Battery Life: Recording for extended periods can drain your battery. Ensure you have a power bank or a way to keep your phone charged throughout the capture.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Post-Capture Magic:&lt;/p&gt;

&lt;p&gt;Once the recording is complete, the S23 Ultra will process the Hyperlapse footage and create a stunning video showcasing the movement of the stars across the night sky. You can further enhance your Star Trails video using editing software, adjusting brightness, contrast, and saturation to taste.&lt;/p&gt;

&lt;p&gt;Bonus Tip: Download the Samsung Expert RAW app to unlock even more control over your astrophotography experience.&lt;/p&gt;

&lt;p&gt;With these steps and a touch of starry-eyed wonder, you'll be well on your way to capturing breathtaking star trails with your Galaxy S23 Ultra, transforming fleeting moments into mesmerizing celestial art!&lt;br&gt;
&lt;a href="https://youtube.com/shorts/MjArEEphPT8?feature=share"&gt;Watch the youtube short of the star trails here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>s23ultra</category>
      <category>photography</category>
      <category>startrails</category>
    </item>
    <item>
      <title>ZooKeeper Chronicles: Navigating EOFException and the Enigma of 0-Length Files</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Mon, 18 Dec 2023 18:55:58 +0000</pubDate>
      <link>https://forem.com/suavebajaj/zookeeper-chronicles-navigating-eofexception-and-the-enigma-of-0-length-files-1h24</link>
      <guid>https://forem.com/suavebajaj/zookeeper-chronicles-navigating-eofexception-and-the-enigma-of-0-length-files-1h24</guid>
      <description>&lt;p&gt;In the realm of technology, ZooKeeper plays a crucial role in maintaining order within distributed systems. However, much like any compelling narrative, I recently encountered a stumbling block marked by an unexpected challenge – an EOFException paired with an intriguing 0-length file.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;The Error:&lt;/em&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR [main:Util@214] - Last transaction was partial.
ERROR [main:ZooKeeperServerMain@66] - Unexpected exception, exiting abnormally
java.io.EOFException
    at java.io.DataInputStream.readInt(DataInputStream.java:392)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An EOFException occurred, causing our ZooKeeper server to crash.&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;em&gt;The Mysterious 0 Length File:&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Navigating through the ZooKeeper folder, I saw something strange:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-rw-rw-r-- 1 zookeeper zookeeper 1342177280 Sep 23 23:17 log.be45c2
-rw-rw-r-- 1 zookeeper zookeeper          0 Oct  1 14:31 log.be85e9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  &lt;em&gt;Digging Deeper:&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;The zero file hinted at trouble with our transaction logs. Looking into the logs, we found the last transaction was a bit messed up, triggering the EOFException. But why did it result in a zero file?&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;em&gt;Real Issue: Running Out of Space&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;There was a 0 Length File because the underlying disk utilization was full and no space was left on the device to write the logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Filesystem      Size  Used Avail Use% Mounted on
/dev/sde         25G   25G     0 100% /var/lib/zookeeper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As per the Zookeeper official documentation &lt;a href="https://zookeeper.apache.org/doc/r3.3.2/zookeeperAdmin.html#Ongoing+Data+Directory+Cleanup"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A ZooKeeper server will not remove old snapshots and log files, this is the responsibility of the operator. Every serving environment is different and therefore the requirements of managing these files may differ from install to install (backup for example).&lt;/p&gt;

&lt;p&gt;The PurgeTxnLog utility implements a simple retention policy that administrators can use. The API docs contains details on calling conventions (arguments, etc...).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  &lt;em&gt;Using the PurgeTxnLog utility&lt;/em&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zookeeper@zk-0:/bin$ zkCleanup.sh
Usage:
PurgeTxnLog dataLogDir [snapDir] -n count
    dataLogDir -- path to the txn log directory
    snapDir -- path to the snapshot directory
    count -- the number of old snaps/logs you want to keep, value should be greater than or equal to 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the latest 5 logs and snapshots&lt;br&gt;
&lt;code&gt;./zkCleanup.sh -n 5&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;em&gt;Conclusion:&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;In the dynamic landscape of distributed systems, unexpected errors often hint at underlying complexities. Our journey through the EOFException and zero file quandary emphasizes the importance of vigilant monitoring of logs and disk space. As tech custodians, we must be prepared to decode mysteries, address core issues, and ensure the seamless operation of systems like ZooKeeper.&lt;/p&gt;

&lt;p&gt;ZooKeeper, with its unique quirks and challenges, continues to be an exciting playground for tech enthusiasts eager to navigate the intricacies of system synchronization.&lt;/p&gt;

</description>
      <category>zookeeper</category>
      <category>kafka</category>
      <category>cloud</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Taint Like a Pro: Effortlessly Taint Multiple Nodes Using Node Labels in Kubernetes!</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Mon, 31 Jul 2023 07:58:32 +0000</pubDate>
      <link>https://forem.com/suavebajaj/taint-like-a-pro-effortlessly-taint-multiple-nodes-using-node-labels-in-kubernetes-2p0i</link>
      <guid>https://forem.com/suavebajaj/taint-like-a-pro-effortlessly-taint-multiple-nodes-using-node-labels-in-kubernetes-2p0i</guid>
      <description>&lt;h3&gt;
  
  
  Introduction:
&lt;/h3&gt;

&lt;p&gt;In Kubernetes, taints and tolerations offer a powerful mechanism for controlling pod placement on nodes. Taints enable nodes to repel pods, ensuring they only accept those with matching tolerations. However, manually tainting individual nodes can be time-consuming. In this guide, we’ll explore a more efficient approach by using node labels to taint multiple nodes simultaneously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Taints and Tolerations:
&lt;/h3&gt;

&lt;p&gt;Taints are used to mark nodes, indicating that they should not accept pods that lack specific tolerations. Tolerations, on the other hand, allow pods to be scheduled on tainted nodes. Together, they provide fine-grained control over pod placement based on node characteristics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tainting a Node:
&lt;/h3&gt;

&lt;p&gt;To taint a node, use the &lt;code&gt;kubectl taint&lt;/code&gt; command followed by the node name and the taint specification.&lt;/p&gt;

&lt;p&gt;For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl taint nodes node1 key1=value1:NoSchedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example taints the node named node1 with the key-value pair &lt;code&gt;key1=value1&lt;/code&gt; and the &lt;code&gt;NoSchedule&lt;/code&gt; effect. Consequently, no pod without a matching toleration will be scheduled onto node1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get the Tainted Nodes:
&lt;/h3&gt;

&lt;p&gt;To verify which nodes have taints, you can use the &lt;code&gt;kubectl get nodes&lt;/code&gt; command with the JSON output format and filter it using &lt;code&gt;jq&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get nodes -o json | jq ".items[] | {name:.metadata.name, taints:.spec.taints}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command provides a clear view of the nodes along with their corresponding taints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tainting Multiple Nodes with Node Labels:
&lt;/h2&gt;

&lt;p&gt;When you have a group of nodes with similar attributes (e.g., identical machine types or workloads), tainting them individually becomes impractical. Instead, you can utilize node labels to taint all nodes matching a specific criterion in one go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl taint nodes -l label_key=label_value tainting_key=tainting_value:NoSchedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl taint nodes -l machine-type=e2-small machine-type=e2-small:NoSchedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, all nodes labelled &lt;code&gt;machine-type=e2-small&lt;/code&gt; will be tainted with the &lt;code&gt;NoSchedule&lt;/code&gt; effect. Consequently, only pods with tolerations matching the specified taint will be scheduled on these nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages of Tainting with Node Labels:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Time-saving: By tainting multiple nodes simultaneously using labels, you avoid repetitive manual operations, reducing the time and effort required for node management.&lt;/li&gt;
&lt;li&gt;Workload migration: Node tainting with labels facilitates seamless workload migration from one group of nodes to another, based on specific criteria.&lt;/li&gt;
&lt;li&gt;Resource optimization: Efficiently balance workloads across different node specifications, ensuring optimal resource utilization throughout your Kubernetes cluster.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Conclusion:&lt;br&gt;
Using node labels to taint multiple nodes in Kubernetes is a powerful technique that simplifies node affinity management. By applying taints based on labels, you gain greater control over pod placement and workload distribution, streamlining operations and optimizing resource usage. Embrace this approach to efficiently manage your Kubernetes cluster and ensure smooth workload migration across nodes with diverse characteristics.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>kubernetes</category>
      <category>taintsandtolerations</category>
      <category>label</category>
    </item>
    <item>
      <title>Create Signed URLs using gsutil</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Thu, 24 Mar 2022 10:03:02 +0000</pubDate>
      <link>https://forem.com/suavebajaj/using-gsutil-signed-url-3pnj</link>
      <guid>https://forem.com/suavebajaj/using-gsutil-signed-url-3pnj</guid>
      <description>&lt;p&gt;A signed URL is a URL that provides limited permission and time to make a request. Signed URLs contain authentication information in their query string, allowing users without credentials to perform specific actions on a resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a signed URL
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;u&gt;What we will need&lt;/u&gt;:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;gsutil&lt;/li&gt;
&lt;li&gt;pyopenssl&lt;/li&gt;
&lt;li&gt;Service Account Key&lt;/li&gt;
&lt;li&gt;Path of the file/Object&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;u&gt;&lt;em&gt;Command&lt;/em&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;gsutil signurl -d 2d service-account-key.json gs://my-gcs-bucket/my-object&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;-d Specifies the duration that the signed url should be valid&lt;br&gt;
For, default duration is 1 hour.Times may be specified with no suffix (default hours), or with s = seconds, m = minutes, h = hours, d = days.&lt;br&gt;
This option may be specified multiple times, in which case&lt;br&gt;
the duration the link remains valid is the sum of all the duration options.&lt;br&gt;
The max duration allowed is 7 days when &lt;code&gt;private-key-file&lt;/code&gt;is used.&lt;br&gt;
Any service-account-key can be used to encrypt the url&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;u&gt;&lt;em&gt;Issues&lt;/em&gt;&lt;/u&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;CommandException: The signurl command requires the pyopenssl library (try pip install pyopenssl or easy_install pyopenssl)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Install pyopenssl using the pip as per the python version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;pip3 install pyopenssl&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even after installing pyopenssl if you are getting the same error, Check gcloud uses which python and python should point to a python interpreter used by gcloud&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;gcloud info --format="text(basic.python_location)"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;➜  Desktop git:(master) ✗ gcloud info --format="text(basic.python_location)"&lt;br&gt;
python_location: /Users/.config/gcloud/virtenv/bin/python3&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;u&gt;Add the Environment Variables as&lt;/u&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;export CLOUDSDK_PYTHON=python3&lt;/code&gt;&lt;br&gt;
&lt;code&gt;export CLOUDSDK_PYTHON_SITEPACKAGES=1&lt;/code&gt;&lt;/p&gt;

</description>
      <category>gcp</category>
      <category>python</category>
      <category>crypto</category>
      <category>gsutil</category>
    </item>
    <item>
      <title>Make Elasticsearch 6.x Cluster Writable from Readonly</title>
      <dc:creator>Suave Bajaj</dc:creator>
      <pubDate>Tue, 08 Mar 2022 10:35:18 +0000</pubDate>
      <link>https://forem.com/suavebajaj/make-elasticserach-6x-cluster-writable-from-readonly-35c5</link>
      <guid>https://forem.com/suavebajaj/make-elasticserach-6x-cluster-writable-from-readonly-35c5</guid>
      <description>&lt;p&gt;Sometimes you might get &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Error: disk usage exceeded flood-stage watermark, index has read-only-allow-delete block&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;or &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ClusterBlockException[blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This error indicates a data node is critically low on disk space and has reached the flood-stage disk usage watermark. To prevent a full disk, when a node reaches this watermark, Elasticsearch blocks writes to any index with a shard on the node. If the block affects related system indices, Kibana and other Elastic Stack features may become unavailable.&lt;/p&gt;

&lt;p&gt;This means you'll only be able to read the Indices, Delete the Indices but cannot write new Indices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get the Cluster Settings
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;curl elasticsearch-sc:9200/_settings?pretty&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You'll see the read_only_allow_delete following as true for the Indices that means the cluster is in read-only mode&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;"blocks" : {&lt;br&gt;
          "read_only_allow_delete" : "true"&lt;br&gt;
        },&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the Disk Cleanup, When you have deleted the non-required Indices or after adding more space to the cluster, The Cluster needs to be put back to the writable mode&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting Cluster back to Writable Mode
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;curl -XPUT -H "Content-Type: application/json" \&lt;br&gt;
     http://elasticsearch-sc:9200/_all/_settings \&lt;br&gt;
       -d '{"index.blocks.read_only_allow_delete": null}'&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can check the cluster settings again to confirm the change&lt;/p&gt;

</description>
      <category>elasticsearch</category>
      <category>cloud</category>
      <category>readonly</category>
      <category>cluster</category>
    </item>
  </channel>
</rss>
