<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Iresh's Blog]]></title><description><![CDATA[Explore expert tutorials, tech guides, and insights on DevOps, cloud computing, Kubernetes, and more. Learn, build, and grow your skills with easy-to-follow content.]]></description><link>https://blog.iresh.xyz</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 12:48:08 GMT</lastBuildDate><atom:link href="https://blog.iresh.xyz/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Azure Authentication Methods Explained: Managed Identity vs Federated Identity vs Certificate, Client Secret]]></title><description><![CDATA[When working with Azure, one of the first (and most confusing) topics you’ll face is authentication.
You’ll often see this priority order mentioned:




PriorityMethodAzure stance



🟢 1Managed IdentityStrongly recommended

🟢 2Federated IdentityMod...]]></description><link>https://blog.iresh.xyz/azure-authentication-methods-explained-managed-identity-vs-federated-identity-vs-certificate-client-secret</link><guid isPermaLink="true">https://blog.iresh.xyz/azure-authentication-methods-explained-managed-identity-vs-federated-identity-vs-certificate-client-secret</guid><category><![CDATA[Client Secret]]></category><category><![CDATA[ManagedIdentity ]]></category><category><![CDATA[Federated Identity]]></category><category><![CDATA[certificate]]></category><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Mon, 05 Jan 2026 11:36:51 GMT</pubDate><content:encoded><![CDATA[<p>When working with Azure, one of the first (and most confusing) topics you’ll face is <strong>authentication</strong>.</p>
<p>You’ll often see this priority order mentioned:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Priority</td><td>Method</td><td>Azure stance</td></tr>
</thead>
<tbody>
<tr>
<td>🟢 1</td><td>Managed Identity</td><td>Strongly recommended</td></tr>
<tr>
<td>🟢 2</td><td>Federated Identity</td><td>Modern &amp; preferred</td></tr>
<tr>
<td>🟡 3</td><td>Certificates</td><td>Acceptable</td></tr>
<tr>
<td>🔴 4</td><td>Client Secrets</td><td>Legacy / fallback</td></tr>
</tbody>
</table>
</div><p>But <strong>what do these actually mean?</strong><br />Why does Azure still support secrets if they’re considered bad?</p>
<p>This article explains each method <strong>clearly and practically</strong>, so anyone can understand and choose the right one.</p>
<hr />
<h2 id="heading-why-authentication-matters-in-azure">Why Authentication Matters in Azure</h2>
<p>Authentication answers one simple question:</p>
<blockquote>
<p><strong>“Who are you, and are you allowed to access this resource?”</strong></p>
</blockquote>
<p>In Azure, authentication is commonly used when:</p>
<ul>
<li><p>An app accesses <strong>Key Vault</strong></p>
</li>
<li><p>A Function App accesses <strong>Storage</strong></p>
</li>
<li><p>A CI/CD pipeline deploys infrastructure</p>
</li>
<li><p>A Kubernetes workload calls an API</p>
</li>
</ul>
<p>Azure supports multiple authentication methods because <strong>not all systems are equal</strong> — some are modern, some are legacy.</p>
<hr />
<h2 id="heading-1-managed-identity-strongly-recommended">🟢 1. Managed Identity (Strongly Recommended)</h2>
<h3 id="heading-what-is-managed-identity">What is Managed Identity?</h3>
<p>Managed Identity is an <strong>identity automatically managed by Azure</strong> for Azure resources.</p>
<p>No secrets.<br />No certificates.<br />No credentials to store.</p>
<p>Azure handles everything.</p>
<h3 id="heading-how-it-works-simple">How it works (simple)</h3>
<ol>
<li><p>You enable Managed Identity on an Azure resource (VM, Function App, App Service)</p>
</li>
<li><p>The resource asks Azure for a token</p>
</li>
<li><p>Azure verifies the resource and issues a token</p>
</li>
<li><p>The resource accesses another Azure service</p>
</li>
</ol>
<h3 id="heading-key-benefits">Key benefits</h3>
<ul>
<li><p>No credentials to leak</p>
</li>
<li><p>Automatic rotation</p>
</li>
<li><p>Zero configuration secrets</p>
</li>
<li><p>Deep Azure integration</p>
</li>
</ul>
<h3 id="heading-when-to-use-it">When to use it</h3>
<p>✅ Azure Function → Key Vault<br />✅ VM → Storage Account<br />✅ App Service → SQL Database</p>
<h3 id="heading-limitation">Limitation</h3>
<p>❌ Works <strong>only inside Azure</strong></p>
<blockquote>
<p><strong>If both the caller and target are in Azure, Managed Identity should be your first choice.</strong></p>
</blockquote>
<hr />
<h2 id="heading-2-federated-identity-modern-amp-preferred">🟢 2. Federated Identity (Modern &amp; Preferred)</h2>
<h3 id="heading-what-is-federated-identity">What is Federated Identity?</h3>
<p>Federated Identity allows Azure to <strong>trust an external identity provider</strong> using OIDC (OpenID Connect).</p>
<p>Still <strong>no secrets</strong>.</p>
<h3 id="heading-how-it-works">How it works</h3>
<ol>
<li><p>An external platform (GitHub Actions, AKS, Azure DevOps) authenticates itself</p>
</li>
<li><p>It receives a short-lived OIDC token</p>
</li>
<li><p>Azure validates the token (issuer, subject, audience)</p>
</li>
<li><p>Azure issues an access token</p>
</li>
</ol>
<h3 id="heading-common-use-cases">Common use cases</h3>
<ul>
<li><p>GitHub Actions deploying to Azure</p>
</li>
<li><p>Kubernetes workloads accessing Azure services</p>
</li>
<li><p>Cross-cloud automation</p>
</li>
</ul>
<h3 id="heading-key-benefits-1">Key benefits</h3>
<ul>
<li><p>Secretless authentication</p>
</li>
<li><p>Short-lived tokens</p>
</li>
<li><p>Ideal for CI/CD and automation</p>
</li>
</ul>
<h3 id="heading-limitation-1">Limitation</h3>
<p>❌ Requires an OIDC-capable platform</p>
<blockquote>
<p><strong>If your workload runs outside Azure but supports OIDC, use Federated Identity.</strong></p>
</blockquote>
<hr />
<h2 id="heading-3-certificate-based-authentication-acceptable">🟡 3. Certificate-Based Authentication (Acceptable)</h2>
<h3 id="heading-what-is-certificate-authentication">What is Certificate Authentication?</h3>
<p>Instead of a password (secret), the app authenticates using a <strong>private key and certificate</strong>.</p>
<p>This is still OAuth, but stronger than secrets.</p>
<h3 id="heading-how-it-works-1">How it works</h3>
<ol>
<li><p>A certificate is uploaded to an Azure App Registration</p>
</li>
<li><p>The app signs a request using the private key</p>
</li>
<li><p>Azure verifies the certificate</p>
</li>
<li><p>Azure issues a token</p>
</li>
</ol>
<h3 id="heading-why-it-still-exists">Why it still exists</h3>
<ul>
<li><p>Many enterprise systems can’t use OIDC</p>
</li>
<li><p>Certificates are more secure than secrets</p>
</li>
<li><p>Works well for long-running services</p>
</li>
</ul>
<h3 id="heading-downsides">Downsides</h3>
<ul>
<li><p>Certificates expire</p>
</li>
<li><p>Manual lifecycle management</p>
</li>
<li><p>Private key must be protected</p>
</li>
</ul>
<blockquote>
<p><strong>Certificates are a solid fallback when federation is not possible.</strong></p>
</blockquote>
<hr />
<h2 id="heading-4-client-secrets-legacy-fallback">🔴 4. Client Secrets (Legacy / Fallback)</h2>
<h3 id="heading-what-is-a-client-secret">What is a Client Secret?</h3>
<p>A client secret is essentially a <strong>password for an application</strong>.</p>
<h3 id="heading-how-it-works-2">How it works</h3>
<p>The app sends:</p>
<ul>
<li><p>client_id</p>
</li>
<li><p>client_secret</p>
</li>
<li><p>tenant_id</p>
</li>
</ul>
<p>Azure validates the secret and issues a token.</p>
<h3 id="heading-why-secrets-are-bad">Why secrets are bad</h3>
<ul>
<li><p>Easy to leak</p>
</li>
<li><p>Often hard-coded</p>
</li>
<li><p>Require manual rotation</p>
</li>
<li><p>High breach risk</p>
</li>
</ul>
<h3 id="heading-why-azure-still-supports-them">Why Azure still supports them</h3>
<ul>
<li><p>Legacy systems</p>
</li>
<li><p>Backward compatibility</p>
</li>
<li><p>Simple demos and temporary setups</p>
</li>
</ul>
<blockquote>
<p><strong>Secrets exist because the real world still has old systems — not because they’re recommended.</strong></p>
</blockquote>
<hr />
<h2 id="heading-security-comparison-at-a-glance">Security Comparison at a Glance</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Method</td><td>Stored credentials</td><td>Rotation</td><td>Risk level</td></tr>
</thead>
<tbody>
<tr>
<td>Managed Identity</td><td>None</td><td>Automatic</td><td>🟢 Very Low</td></tr>
<tr>
<td>Federated Identity</td><td>None</td><td>Automatic</td><td>🟢 Very Low</td></tr>
<tr>
<td>Certificate</td><td>Private key</td><td>Manual</td><td>🟡 Medium</td></tr>
<tr>
<td>Client Secret</td><td>Static secret</td><td>Manual</td><td>🔴 High</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-how-to-choose-the-right-method">How to Choose the Right Method</h2>
<p>Ask yourself two questions:</p>
<h3 id="heading-1-is-my-workload-running-inside-azure">1. Is my workload running inside Azure?</h3>
<ul>
<li><p><strong>Yes</strong> → Use <strong>Managed Identity</strong></p>
</li>
<li><p><strong>No</strong> → Go to question 2</p>
</li>
</ul>
<h3 id="heading-2-does-it-support-oidc">2. Does it support OIDC?</h3>
<ul>
<li><p><strong>Yes</strong> → Use <strong>Federated Identity</strong></p>
</li>
<li><p><strong>No</strong> → Use <strong>Certificate</strong></p>
</li>
<li><p><strong>Only legacy available</strong> → Use <strong>Client Secret (temporary)</strong></p>
</li>
</ul>
<hr />
<h2 id="heading-azures-real-direction">Azure’s Real Direction</h2>
<p>Azure’s message is clear:</p>
<blockquote>
<p><strong>Secrets are supported, but discouraged</strong></p>
</blockquote>
<p>You can see this in:</p>
<ul>
<li><p>Short secret expiry times</p>
</li>
<li><p>Security warnings</p>
</li>
<li><p>Defender recommendations</p>
</li>
<li><p>Strong push toward Managed &amp; Federated Identity</p>
</li>
</ul>
<hr />
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>If you remember just one thing, remember this:</p>
<blockquote>
<p><strong>The closer the identity is to the platform, the safer it is</strong></p>
</blockquote>
<ul>
<li><p>Azure-native → Managed Identity</p>
</li>
<li><p>Modern external → Federated Identity</p>
</li>
<li><p>Enterprise legacy → Certificates</p>
</li>
<li><p>Last resort → Client Secrets</p>
</li>
</ul>
<hr />
<p>If you’re migrating from <strong>client secrets to federated identity</strong> or want help applying this to <strong>Terraform, GitHub Actions, AKS, or Azure Functions</strong>, feel free to reach out or comment.</p>
<p>Happy building 🚀</p>
]]></content:encoded></item><item><title><![CDATA[🚀 Deploying Multiple Schedulers in Kubernetes (with Leader Election Explained)]]></title><description><![CDATA[Kubernetes ships with a default scheduler (default-scheduler) that is responsible for placing pods onto the most suitable nodes. It does this by considering resource availability, taints and tolerations, affinities, and more.
But what if your applica...]]></description><link>https://blog.iresh.xyz/deploying-multiple-schedulers-in-kubernetes-with-leader-election-explained</link><guid isPermaLink="true">https://blog.iresh.xyz/deploying-multiple-schedulers-in-kubernetes-with-leader-election-explained</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Mon, 05 Jan 2026 11:33:30 GMT</pubDate><content:encoded><![CDATA[<p>Kubernetes ships with a <strong>default scheduler</strong> (<code>default-scheduler</code>) that is responsible for placing pods onto the most suitable nodes. It does this by considering resource availability, taints and tolerations, affinities, and more.</p>
<p>But what if your application has <strong>special placement requirements</strong> that the default scheduler cannot handle?</p>
<p>👉 That’s where <strong>custom schedulers</strong> come in. Kubernetes allows you to run multiple schedulers within the same cluster and choose which scheduler should manage which pods.</p>
<p>In this blog, we’ll cover:</p>
<ul>
<li><p>Why multiple schedulers are useful</p>
</li>
<li><p>How schedulers are named and configured</p>
</li>
<li><p>Deploying custom schedulers (binary, pod, and deployment methods)</p>
</li>
<li><p>The <strong>leader election</strong> option for HA setups</p>
</li>
<li><p>How to use your custom scheduler in pods</p>
</li>
<li><p>How to verify scheduling decisions</p>
</li>
</ul>
<hr />
<h2 id="heading-why-multiple-schedulers">🔹 Why Multiple Schedulers?</h2>
<p>By default, every pod goes through <code>default-scheduler</code>. However:</p>
<ul>
<li><p>You may want an application to run <strong>only on GPU nodes</strong> with additional custom checks.</p>
</li>
<li><p>You may implement a <strong>domain-specific algorithm</strong> for data locality or cost optimization.</p>
</li>
<li><p>You may test experimental scheduling strategies without impacting the default scheduler.</p>
</li>
</ul>
<p>With multiple schedulers:</p>
<ul>
<li><p>Normal workloads → use the <strong>default scheduler</strong>.</p>
</li>
<li><p>Special workloads → use your <strong>custom scheduler</strong>.</p>
</li>
</ul>
<hr />
<h2 id="heading-scheduler-names">🔹 Scheduler Names</h2>
<p>Each scheduler must have a <strong>unique name</strong>.</p>
<ul>
<li><p>Default scheduler → <code>default-scheduler</code></p>
</li>
<li><p>Custom schedulers → you define names like <code>my-scheduler</code>, <code>gpu-scheduler</code>, etc.</p>
</li>
</ul>
<p>This name is set in the <strong>scheduler configuration file</strong>:</p>
<pre><code class="lang-plaintext">apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: my-scheduler
    leaderElection:
      leaderElect: false
</code></pre>
<p>If no name is specified, Kubernetes defaults to <code>default-scheduler</code>.</p>
<hr />
<h2 id="heading-methods-to-deploy-a-custom-scheduler">🔹 Methods to Deploy a Custom Scheduler</h2>
<h3 id="heading-1-running-scheduler-as-a-binary">1. <strong>Running Scheduler as a Binary</strong></h3>
<p>You can download the <code>kube-scheduler</code> binary and run it manually:</p>
<pre><code class="lang-plaintext">kube-scheduler \
  --config=/etc/kubernetes/my-scheduler-config.yaml \
  --kubeconfig=/etc/kubernetes/scheduler.kubeconfig
</code></pre>
<p>⚠️ Rarely used in modern kubeadm-based clusters since schedulers usually run as pods.</p>
<hr />
<h3 id="heading-2-scheduler-as-a-pod">2. <strong>Scheduler as a Pod</strong></h3>
<p>You can run the scheduler as a pod inside your cluster.</p>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Pod
metadata:
  name: my-scheduler
  namespace: kube-system
spec:
  containers:
    - name: kube-scheduler
      image: k8s.gcr.io/kube-scheduler:v1.28.0
      command:
        - kube-scheduler
        - --config=/etc/kubernetes/my-scheduler-config.yaml
      volumeMounts:
        - name: config
          mountPath: /etc/kubernetes/
  volumes:
    - name: config
      configMap:
        name: my-scheduler-config
</code></pre>
<p>Here, the <strong>ConfigMap</strong> contains your custom scheduler config.</p>
<hr />
<h3 id="heading-3-scheduler-as-a-deployment">3. <strong>Scheduler as a Deployment</strong></h3>
<p>A more scalable and recommended approach is to run the scheduler as a <strong>deployment</strong>.</p>
<pre><code class="lang-plaintext">apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-scheduler
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      component: my-scheduler
  template:
    metadata:
      labels:
        component: my-scheduler
    spec:
      serviceAccountName: scheduler-sa
      containers:
        - name: kube-scheduler
          image: k8s.gcr.io/kube-scheduler:v1.28.0
          command:
            - kube-scheduler
            - --config=/etc/kubernetes/my-scheduler-config.yaml
          volumeMounts:
            - name: config
              mountPath: /etc/kubernetes/
      volumes:
        - name: config
          configMap:
            name: my-scheduler-config
</code></pre>
<p>This way, Kubernetes ensures HA and restart capabilities.</p>
<hr />
<h2 id="heading-the-leaderelect-option-explained">🔹 The <code>leaderElect</code> Option Explained</h2>
<p>When running schedulers in <strong>HA setups</strong> (multiple control-plane nodes):</p>
<ul>
<li><p>Multiple copies of the same scheduler might be running.</p>
</li>
<li><p>Only <strong>one scheduler instance should be active at a time</strong>.</p>
</li>
<li><p>The <code>leaderElect: true</code> setting ensures that a leader is elected among them.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-plaintext">leaderElection:
  leaderElect: true
  resourceName: my-scheduler-lock
</code></pre>
<p>Here:</p>
<ul>
<li><p>If you run <strong>3 replicas of</strong> <code>my-scheduler</code>, only <strong>one</strong> will be leader.</p>
</li>
<li><p>Others will stay passive until the leader fails.</p>
</li>
</ul>
<p>👉 Always enable <code>leaderElect</code> in production HA clusters.</p>
<hr />
<h2 id="heading-using-the-custom-scheduler-in-a-pod">🔹 Using the Custom Scheduler in a Pod</h2>
<p>Once deployed, tell Kubernetes which scheduler to use by adding <code>schedulerName</code> to your pod spec.</p>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Pod
metadata:
  name: my-custom-pod
spec:
  schedulerName: my-scheduler
  containers:
    - name: busybox
      image: busybox
      command: ["sleep", "3600"]
</code></pre>
<p>Now, this pod will bypass the default scheduler and use <code>my-scheduler</code>.</p>
<hr />
<h2 id="heading-verifying-which-scheduler-picked-the-pod">🔹 Verifying Which Scheduler Picked the Pod</h2>
<p>To confirm scheduling:</p>
<ol>
<li><strong>Check pod events</strong>:</li>
</ol>
<pre><code class="lang-plaintext">kubectl get events --sort-by=.metadata.creationTimestamp -o wide
</code></pre>
<p>You’ll see events like:</p>
<pre><code class="lang-plaintext">Successfully assigned default/my-custom-pod to node1
Source: my-scheduler
</code></pre>
<ol start="2">
<li><strong>Check scheduler logs</strong>:</li>
</ol>
<pre><code class="lang-plaintext">kubectl logs -n kube-system &lt;my-scheduler-pod-name&gt;
</code></pre>
<p>If your pod stays in <code>Pending</code>, likely the scheduler is misconfigured.</p>
<hr />
<h2 id="heading-summary">✅ Summary</h2>
<ul>
<li><p>Kubernetes supports <strong>multiple schedulers</strong>.</p>
</li>
<li><p>Each scheduler must have a <strong>unique name</strong>.</p>
</li>
<li><p>You can deploy schedulers as a <strong>binary, pod, or deployment</strong>.</p>
</li>
<li><p>Use <code>leaderElect: true</code> in HA setups.</p>
</li>
<li><p>Pods can be scheduled by a custom scheduler using <code>schedulerName</code>.</p>
</li>
<li><p>Verify scheduling decisions with <strong>events and logs</strong>.</p>
</li>
</ul>
<p>By using multiple schedulers, you can extend Kubernetes to meet specialized workload placement needs while keeping the default scheduler for general workloads.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Static Pods in Kubernetes]]></title><description><![CDATA[In this blog, we’ll explore Static Pods in Kubernetes, their use cases, and how to configure and inspect them.

What Are Static Pods?
Normally, the kubelet relies on the kube-apiserver to get instructions about which pods to run on a node. The API se...]]></description><link>https://blog.iresh.xyz/understanding-static-pods-in-kubernetes</link><guid isPermaLink="true">https://blog.iresh.xyz/understanding-static-pods-in-kubernetes</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Sun, 21 Sep 2025 08:18:57 GMT</pubDate><content:encoded><![CDATA[<p>In this blog, we’ll explore <strong>Static Pods</strong> in Kubernetes, their use cases, and how to configure and inspect them.</p>
<hr />
<h2 id="heading-what-are-static-pods">What Are Static Pods?</h2>
<p>Normally, the <strong>kubelet</strong> relies on the <strong>kube-apiserver</strong> to get instructions about which pods to run on a node. The API server receives scheduling decisions from the <strong>kube-scheduler</strong>, and stores the cluster state in <strong>ETCD</strong>.</p>
<p>But what happens if there’s <strong>no API server, no scheduler, no controllers, and no ETCD</strong>—in other words, no Kubernetes master at all?</p>
<p>Even in this scenario, the kubelet can still manage pods <strong>independently</strong>. These pods, created and managed by the kubelet <strong>without any control plane components</strong>, are called <strong>Static Pods</strong>.</p>
<hr />
<h2 id="heading-how-static-pods-work">How Static Pods Work</h2>
<ul>
<li><p>The kubelet periodically checks a <strong>designated directory</strong> on the node for pod definition files (manifests).</p>
</li>
<li><p>When it finds a manifest, it creates the pod on the node.</p>
</li>
<li><p>If the pod crashes, the kubelet automatically restarts it.</p>
</li>
<li><p>If the manifest file changes, the kubelet recreates the pod to apply updates.</p>
</li>
<li><p>If the manifest is removed, the pod is automatically deleted.</p>
</li>
</ul>
<blockquote>
<p><strong>Important:</strong> Static pods only exist at the pod level. You cannot create <strong>ReplicaSets</strong>, <strong>Deployments</strong>, or <strong>Services</strong> using static pod manifests. These objects require other control plane components.</p>
</blockquote>
<hr />
<h2 id="heading-where-are-static-pods-stored">Where Are Static Pods Stored?</h2>
<p>The kubelet needs to know the path to the directory containing static pod manifests. There are <strong>two ways</strong> to locate this:</p>
<h3 id="heading-1-check-in-the-kubeletservice-file">1. Check in the <code>kubelet.service</code> file</h3>
<p>The static pod path may be specified directly as the <code>--pod-manifest-path</code> option. To check:</p>
<pre><code class="lang-plaintext">systemctl cat kubelet | grep pod-manifest-path
</code></pre>
<p>Example output:</p>
<pre><code class="lang-plaintext">--pod-manifest-path=/etc/kubernetes/manifests
</code></pre>
<p>This directory is where you place your pod manifest files.</p>
<hr />
<h3 id="heading-2-check-in-the-kubelet-config-file-configyaml-or-kubeconfigyaml">2. Check in the kubelet config file (<code>config.yaml</code> or <code>kubeconfig.yaml</code>)</h3>
<p>Sometimes the kubelet is configured to use a config file via the <code>--config</code> option. In this file, the path is specified as:</p>
<pre><code class="lang-plaintext">staticPodPath: "/etc/kubernetes/manifests"
</code></pre>
<ul>
<li><p>Either method will give you the <strong>correct directory</strong> for placing static pod manifests.</p>
</li>
<li><p>If both exist, the kubelet config file usually takes precedence.</p>
</li>
</ul>
<hr />
<h2 id="heading-viewing-static-pods">Viewing Static Pods</h2>
<p>Once static pods are created, <strong>you cannot use</strong> <code>kubectl</code> to view them if the kube-apiserver is not running. This is because:</p>
<ul>
<li><p><code>kubectl</code> communicates with the <strong>kube-apiserver</strong>.</p>
</li>
<li><p>If the cluster has no API server (e.g., in a standalone kubelet scenario), <code>kubectl</code> has no source of truth.</p>
</li>
</ul>
<p>Instead, use <strong>Docker</strong> (or the container runtime directly) to inspect the running static pods:</p>
<pre><code class="lang-plaintext">docker ps
</code></pre>
<p>If the node is part of a cluster with a running kube-apiserver, static pods are mirrored as <strong>read-only pods</strong>, and you can view them via:</p>
<pre><code class="lang-plaintext">kubectl get pods -n kube-system
</code></pre>
<blockquote>
<p>You <strong>cannot edit or delete</strong> static pods via <code>kubectl</code>; changes must be made in the manifest files.</p>
</blockquote>
<hr />
<h2 id="heading-static-pods-vs-daemonsets">Static Pods vs DaemonSets</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Feature</td><td>Static Pods</td><td>DaemonSets</td></tr>
</thead>
<tbody>
<tr>
<td>Managed by</td><td>Kubelet directly</td><td>DaemonSet controller via API server</td></tr>
<tr>
<td>Cluster scheduler</td><td>Ignored</td><td>Ignored</td></tr>
<tr>
<td>Use case</td><td>Deploy control plane components</td><td>Run a copy of a pod on all nodes</td></tr>
<tr>
<td>Editing</td><td>Modify manifest files only</td><td>Can edit via <code>kubectl</code></td></tr>
</tbody>
</table>
</div><blockquote>
<p>Both static pods and DaemonSet pods are <strong>ignored by the kube-scheduler</strong>.</p>
</blockquote>
<hr />
<h2 id="heading-use-cases-for-static-pods">Use Cases for Static Pods</h2>
<p>Static pods are ideal for:</p>
<ul>
<li><p><strong>Bootstrapping the Kubernetes control plane</strong> itself as pods (e.g., API server, Controller Manager, ETCD).</p>
</li>
<li><p>Running critical node-level services that must exist independently of the control plane.</p>
</li>
</ul>
<p>When using tools like <strong>kubeadm</strong>, static pods are used to deploy the cluster's control plane. The kubelet monitors these pods, automatically restarting them if they crash.</p>
<hr />
<h2 id="heading-summary">Summary</h2>
<ul>
<li><p><strong>Static Pods</strong> are created and managed directly by the kubelet.</p>
</li>
<li><p>They are <strong>independent of the Kubernetes control plane</strong>.</p>
</li>
<li><p>You can find the <strong>static pod manifest directory</strong> in either the <code>kubelet.service</code> file (<code>--pod-manifest-path</code>) or the kubelet config file (<code>staticPodPath</code>).</p>
</li>
<li><p>Use Docker to inspect static pods if no API server is present.</p>
</li>
<li><p>Use static pods to deploy the Kubernetes control plane itself or critical node-level services.</p>
</li>
</ul>
<p>Static pods provide a simple, reliable way to run essential pods even when the full Kubernetes control plane is not available.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding DaemonSets in Kubernetes: A Beginner-Friendly Guide]]></title><description><![CDATA[When learning Kubernetes, you often work with Deployments and ReplicaSets to ensure your applications run reliably across your cluster. But what if you need one pod per node instead of multiple replicas? That’s where DaemonSets come in.
Let’s break i...]]></description><link>https://blog.iresh.xyz/understanding-daemonsets-in-kubernetes-a-beginner-friendly-guide</link><guid isPermaLink="true">https://blog.iresh.xyz/understanding-daemonsets-in-kubernetes-a-beginner-friendly-guide</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Sat, 20 Sep 2025 10:53:31 GMT</pubDate><content:encoded><![CDATA[<p>When learning Kubernetes, you often work with <strong>Deployments</strong> and <strong>ReplicaSets</strong> to ensure your applications run reliably across your cluster. But what if you need <strong>one pod per node</strong> instead of multiple replicas? That’s where <strong>DaemonSets</strong> come in.</p>
<p>Let’s break it down.</p>
<h2 id="heading-what-is-a-daemonset">What is a DaemonSet?</h2>
<p>A <strong>DaemonSet</strong> is a Kubernetes object that ensures <strong>exactly one copy of a pod runs on every node</strong> in your cluster.</p>
<ul>
<li><p>When a new node joins the cluster, the DaemonSet automatically deploys a pod on it.</p>
</li>
<li><p>When a node is removed, the pod running on it is also deleted.</p>
</li>
</ul>
<p>Think of it as a <strong>“one pod per node manager.”</strong></p>
<p><strong>Key difference from ReplicaSet:</strong></p>
<ul>
<li><p>ReplicaSets focus on <strong>running a specified number of pod replicas</strong> across the cluster.</p>
</li>
<li><p>DaemonSets focus on <strong>ensuring every node has one copy</strong> of a pod.</p>
</li>
</ul>
<hr />
<h2 id="heading-why-use-a-daemonset">Why Use a DaemonSet?</h2>
<p>DaemonSets are perfect for workloads that need to <strong>run on every node</strong>, such as:</p>
<ol>
<li><p><strong>Monitoring agents</strong></p>
<ul>
<li><p>Example: You want to deploy a pod that collects logs or metrics from every node.</p>
</li>
<li><p>DaemonSet ensures each node automatically gets the monitoring pod.</p>
</li>
</ul>
</li>
<li><p><strong>Cluster networking components</strong></p>
<ul>
<li>Example: Solutions like <strong>Weave Net</strong> require an agent pod on every node to manage network traffic.</li>
</ul>
</li>
<li><p><strong>Node-level system components</strong></p>
<ul>
<li>Example: The <strong>kube-proxy</strong> component, which handles network rules, can run as a DaemonSet on all nodes.</li>
</ul>
</li>
</ol>
<blockquote>
<p>✅ Tip: DaemonSets save you the trouble of manually adding or removing pods as nodes are added or removed.</p>
</blockquote>
<hr />
<h2 id="heading-how-does-a-daemonset-work">How Does a DaemonSet Work?</h2>
<h3 id="heading-before-kubernetes-v112">Before Kubernetes v1.12</h3>
<ul>
<li><p>Pods were scheduled manually on nodes by setting the <code>nodeName</code> property in the pod specification.</p>
</li>
<li><p>Each pod was “pinned” to a specific node.</p>
</li>
</ul>
<h3 id="heading-from-kubernetes-v112-onwards">From Kubernetes v1.12 Onwards</h3>
<ul>
<li><p>DaemonSets use the <strong>default scheduler</strong> along with <strong>node affinity rules</strong>.</p>
</li>
<li><p>The scheduler automatically decides which pod goes to which node.</p>
</li>
<li><p>You no longer need to manually specify nodes; Kubernetes takes care of it.</p>
</li>
</ul>
<hr />
<h2 id="heading-creating-a-daemonset">Creating a DaemonSet</h2>
<p>Creating a DaemonSet is very similar to creating a ReplicaSet. The main difference is the <code>kind</code>:</p>
<pre><code class="lang-plaintext">apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: monitoring-daemon
spec:
  selector:
    matchLabels:
      app: monitoring
  template:
    metadata:
      labels:
        app: monitoring
    spec:
      containers:
      - name: monitoring-agent
        image: monitoring-agent:lates
</code></pre>
<p><strong>Steps to create and manage DaemonSets:</strong></p>
<ol>
<li><strong>Create the DaemonSet:</strong></li>
</ol>
<pre><code class="lang-plaintext">kubectl create -f monitoring-daemon.yaml
</code></pre>
<ol start="2">
<li><strong>View all DaemonSets:</strong></li>
</ol>
<pre><code class="lang-plaintext">kubectl get daemonset
</code></pre>
<ol start="3">
<li><strong>View detailed info about a DaemonSet:</strong></li>
</ol>
<pre><code class="lang-plaintext">kubectl describe daemonset monitoring-daemon
</code></pre>
<blockquote>
<p>⚠️ Tip: Ensure the labels in the <code>selector</code> match the labels in the pod template. Otherwise, the DaemonSet won’t manage the pods properly.</p>
</blockquote>
<h2 id="heading-summary-why-daemonsets-matter">Summary: Why DaemonSets Matter</h2>
<ul>
<li><p><strong>Automatic deployment:</strong> Ensures one pod per node without manual intervention.</p>
</li>
<li><p><strong>Perfect for node-level tasks:</strong> Monitoring, logging, networking, or system agents.</p>
</li>
<li><p><strong>Integrates with Kubernetes scheduler:</strong> Modern DaemonSets use affinity rules to schedule pods efficiently.</p>
</li>
</ul>
<hr />
<h2 id="heading-key-takeaways-for-learners">Key Takeaways for Learners</h2>
<ol>
<li><p><strong>DaemonSets = One pod per node</strong></p>
</li>
<li><p><strong>Use cases:</strong> kube-proxy, monitoring agents, network agents</p>
</li>
<li><p><strong>Modern scheduling:</strong> Uses default scheduler + node affinity</p>
</li>
<li><p><strong>Management commands:</strong> <code>kubectl create</code>, <code>kubectl get daemonset</code>, <code>kubectl describe daemonset</code></p>
</li>
</ol>
<hr />
<p>DaemonSets may seem like just another Kubernetes object, but they are <strong>crucial for maintaining cluster-wide consistency</strong> for essential services. Understanding how to deploy and manage them is a key step in mastering Kubernetes.</p>
]]></content:encoded></item><item><title><![CDATA[⚖️ Kubernetes Resource Requests and Limits Explained (with Best Practices)]]></title><description><![CDATA[When running workloads in Kubernetes, one of the most important things to configure is how much CPU and memory a pod can use. Without proper settings, a single greedy pod can starve others, or your nodes may crash under heavy load.
This is where requ...]]></description><link>https://blog.iresh.xyz/kubernetes-resource-requests-and-limits-explained-with-best-practices</link><guid isPermaLink="true">https://blog.iresh.xyz/kubernetes-resource-requests-and-limits-explained-with-best-practices</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Sat, 20 Sep 2025 10:06:49 GMT</pubDate><content:encoded><![CDATA[<p>When running workloads in Kubernetes, one of the most important things to configure is <strong>how much CPU and memory a pod can use</strong>. Without proper settings, a single greedy pod can starve others, or your nodes may crash under heavy load.</p>
<p>This is where <strong>requests</strong> and <strong>limits</strong> come in. Let’s break it down step by step.</p>
<hr />
<h2 id="heading-what-are-requests-and-limits">🟢 What Are Requests and Limits?</h2>
<h3 id="heading-resource-requests">Resource Requests</h3>
<ul>
<li><p>The <strong>minimum amount of CPU and memory</strong> a container is guaranteed.</p>
</li>
<li><p>The <strong>scheduler uses these values</strong> to decide on which node to place the pod.</p>
</li>
<li><p>Example:</p>
<pre><code class="lang-plaintext">  resources:
    requests:
      cpu: "500m"
      memory: "512Mi"
</code></pre>
<p>  ➝ Pod gets <strong>at least 0.5 CPU and 512Mi RAM</strong>.</p>
</li>
</ul>
<hr />
<h3 id="heading-resource-limits">Resource Limits</h3>
<ul>
<li><p>The <strong>maximum resources</strong> a container can consume.</p>
</li>
<li><p>Prevents one pod from hogging all resources.</p>
</li>
<li><p>Example:</p>
<pre><code class="lang-plaintext">  resources:
    limits:
      cpu: "1"
      memory: "1Gi"
</code></pre>
<p>  ➝ Pod can’t use more than <strong>1 CPU and 1Gi RAM</strong>.</p>
</li>
</ul>
<hr />
<h2 id="heading-cpu-vs-memory">🖥️ CPU vs 💾 Memory</h2>
<h3 id="heading-cpu">CPU</h3>
<ul>
<li><p><code>1 CPU</code> = 1 vCPU (AWS), 1 core (Azure/GCP), or 1 hyperthread.</p>
</li>
<li><p>Can specify fractions:</p>
<ul>
<li><code>100m</code> = 0.1 CPU.</li>
</ul>
</li>
<li><p>If pod exceeds its <strong>CPU limit</strong>, it gets <strong>throttled</strong> (slowed down).</p>
</li>
</ul>
<h3 id="heading-memory">Memory</h3>
<ul>
<li><p>Units: <code>Mi</code> (Mebibytes), <code>Gi</code> (Gibibytes).</p>
</li>
<li><p>If pod exceeds its <strong>memory limit</strong>, it is <strong>killed (OOMKilled)</strong>.</p>
</li>
<li><p>Memory cannot be throttled like CPU.</p>
</li>
</ul>
<hr />
<h2 id="heading-scenarios-to-know">⚖️ Scenarios to Know</h2>
<ol>
<li><p><strong>No requests, no limits</strong></p>
<ul>
<li>Pod can take everything → others may starve. ❌ Not safe.</li>
</ul>
</li>
<li><p><strong>Limits only (no requests)</strong></p>
<ul>
<li><p>Kubernetes treats request = limit.</p>
</li>
<li><p>Pod is guaranteed exactly that much.</p>
</li>
<li><p>Safe, but not flexible.</p>
</li>
</ul>
</li>
<li><p><strong>Requests + Limits set</strong></p>
<ul>
<li><p>Pod always gets its request.</p>
</li>
<li><p>Can burst up to the limit.</p>
</li>
<li><p>Balanced, but unused limits may waste resources.</p>
</li>
</ul>
</li>
<li><p><strong>Requests only (no limits)</strong> ✅</p>
<ul>
<li><p>Pod guaranteed its request.</p>
</li>
<li><p>Can use more if node has free capacity.</p>
</li>
<li><p>Best for most cases, but requires discipline (all pods should set requests).</p>
</li>
</ul>
</li>
</ol>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758360872558/54a0d5c3-9c42-4d85-83e0-15e8ce07a0a0.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-memory-scenarios-to-know">⚖️ Memory Scenarios to Know</h2>
<h3 id="heading-1-no-requests-no-limits">1. No requests, no limits</h3>
<ul>
<li>Pod can take <strong>all memory on the node</strong> if available → may cause <strong>other pods or system processes to OOM</strong>. ❌ Not safe.</li>
</ul>
<h3 id="heading-2-limits-only-no-requests">2. Limits only (no requests)</h3>
<ul>
<li><p>Kubernetes treats <strong>request = limit</strong>.</p>
</li>
<li><p>Pod is <strong>guaranteed exactly that much memory</strong>.</p>
</li>
<li><p><strong>Safe</strong>, but can waste memory if pod doesn’t need the full limit.</p>
</li>
<li><p>If pod exceeds limit → <strong>killed (OOMKilled)</strong>.</p>
</li>
</ul>
<h3 id="heading-3-requests-limits-set">3. Requests + Limits set</h3>
<ul>
<li><p>Pod <strong>guaranteed its request</strong>.</p>
</li>
<li><p>Can use memory <strong>up to the limit</strong>.</p>
</li>
<li><p>Balanced, but if pod uses more than limit → <strong>killed</strong>.</p>
</li>
<li><p>Best practice for workloads with <strong>predictable memory usage</strong>.</p>
</li>
</ul>
<h3 id="heading-4-requests-only-no-limits">4. Requests only (no limits) ✅</h3>
<ul>
<li><p>Pod guaranteed <strong>its request</strong>.</p>
</li>
<li><p>Can use <strong>more memory if node has free capacity</strong>, but <strong>if it grows too much → node might run out of memory</strong>, and pod or others may be OOMKilled.</p>
</li>
<li><p>Safer than no requests, but <strong>requires careful monitoring and discipline</strong>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758361052723/de38a887-1b3a-4568-a9bc-4b534dd09f9e.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-cpu-1">✅ CPU</h3>
<ul>
<li><p>Pod is <strong>guaranteed its request</strong> (minimum CPU it needs).</p>
</li>
<li><p>Can use <strong>more CPU if node has spare capacity</strong>.</p>
</li>
<li><p>CPU is <strong>throttled</strong>, so even if a pod uses more, it won’t crash others.</p>
</li>
<li><p><strong>Pros:</strong> Flexible, efficient, lets pods burst when resources are available.</p>
</li>
<li><p><strong>Cons:</strong> If a pod consumes too much CPU, it may slow down other pods sharing the same node.</p>
</li>
</ul>
<hr />
<h3 id="heading-memory-1">⚠️ Memory</h3>
<ul>
<li><p>Pod is <strong>guaranteed its request</strong> (minimum memory).</p>
</li>
<li><p>Can use <strong>more memory if node has free capacity</strong>, but <strong>no limit means it can potentially use all memory on the node</strong>.</p>
</li>
<li><p>Memory <strong>cannot be throttled</strong>, so if it grows too much → <strong>pod or other pods may be OOMKilled</strong>.</p>
</li>
<li><p><strong>Pros:</strong> Flexible if memory usage is predictable and you trust all pods to behave.</p>
</li>
<li><p><strong>Cons:</strong> Risky if some pods may have memory leaks or high spikes.</p>
</li>
</ul>
<hr />
<h3 id="heading-best-practice">💡 Best Practice</h3>
<ol>
<li><p><strong>Always set requests</strong> — ensures pods get guaranteed resources.</p>
</li>
<li><p><strong>Set limits for memory if workload can spike</strong> — prevents a single pod from crashing the node.</p>
</li>
<li><p><strong>CPU limits are optional</strong> — only needed if you want to prevent noisy neighbors or enforce strict resource isolation.</p>
</li>
</ol>
<hr />
<p>In short:</p>
<ul>
<li><p>✅ CPU: requests only is safe and flexible. ⚠️ <strong>Set limits only when necessary</strong> → e.g., in multi-tenant clusters or public labs.</p>
</li>
<li><p>⚠️ Memory: requests only is flexible but can be risky → consider setting a reasonable limit.</p>
</li>
</ul>
<hr />
<ul>
<li>✅ Use <strong>LimitRange</strong> at the namespace level to enforce defaults:</li>
</ul>
<pre><code class="lang-plaintext">apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-mem-defaults
  namespace: dev
spec:
  limits:
  - default:
      cpu: "1"
      memory: "512Mi"
    defaultRequest:
      cpu: "0.5"
      memory: "256Mi"
    type: Container
</code></pre>
<p>This ensures every pod has a baseline, even if developers forget to specify resources.</p>
<hr />
<h2 id="heading-visual-flow-how-scheduling-works">📊 Visual Flow: How Scheduling Works</h2>
<ol>
<li><p>Pod created → Scheduler checks <strong>requests</strong>.</p>
</li>
<li><p>Scheduler finds a node with enough free resources.</p>
</li>
<li><p>Pod is scheduled onto that node.</p>
</li>
<li><p>At runtime:</p>
<ul>
<li><p>If pod exceeds <strong>CPU limit</strong> → throttled.</p>
</li>
<li><p>If pod exceeds <strong>memory limit</strong> → killed.</p>
</li>
<li><p>If pod stays within requests → always guaranteed that much.</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">🚀 Conclusion</h2>
<ul>
<li><p><strong>Requests = Minimum guarantee</strong></p>
</li>
<li><p><strong>Limits = Maximum cap</strong></p>
</li>
<li><p><strong>Always set requests</strong> to prevent resource starvation.</p>
</li>
<li><p><strong>Use limits carefully</strong>, only when you need strict isolation.</p>
</li>
</ul>
<p>With the right balance, you’ll keep your Kubernetes cluster <strong>fair, efficient, and stable</strong>.</p>
<hr />
<hr />
<h2 id="heading-limitrange-amp-resourcequota"><strong><mark>LimitRange &amp; ResourceQuota</mark></strong></h2>
<h3 id="heading-limitrange-cpu-amp-memory"><strong>LimitRange (CPU &amp; Memory)</strong></h3>
<p>A <strong>LimitRange</strong> is a <strong>namespace-level policy</strong> that defines <strong>default resource requests and limits</strong> for pods and containers <strong>if they are not explicitly set</strong>. It ensures that no pod in the namespace runs without some resource constraints.</p>
<h3 id="heading-key-points">Key points:</h3>
<ul>
<li><p><strong>Applies at namespace level</strong>.</p>
</li>
<li><p>Can define <strong>default requests and limits</strong> for CPU and memory.</p>
</li>
<li><p>Can define <strong>minimum and maximum allowed values</strong> for requests and limits.</p>
</li>
<li><p>Only affects <strong>new pods</strong> created <strong>after the LimitRange is applied</strong>. Existing pods are not affected.</p>
</li>
</ul>
<h3 id="heading-example">Example:</h3>
<pre><code class="lang-plaintext">apiVersion: v1
kind: LimitRange
metadata:
  name: example-limitrange
  namespace: my-namespace
spec:
  limits:
  - type: Container
    default:
      cpu: 500m
      memory: 512Mi
    defaultRequest:
      cpu: 250m
      memory: 256Mi
    max:
      cpu: 1
      memory: 1Gi
    min:
      cpu: 100m
      memory: 128Mi
</code></pre>
<ul>
<li><p><strong>defaultRequest</strong> → scheduler guaranteed resources if pod doesn’t specify.</p>
</li>
<li><p><strong>default</strong> → runtime limit if pod doesn’t specify.</p>
</li>
<li><p><strong>max</strong> → maximum allowed resource (ceiling).</p>
</li>
<li><p><strong>min</strong> → minimum allowed resource (floor).</p>
</li>
</ul>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>If a pod does <strong>not specify requests/limits</strong>, it gets <code>defaultRequest</code> and <code>default</code>.</p>
</li>
<li><p>Pods <strong>cannot request more than</strong> <code>max</code> or less than <code>min</code>.</p>
</li>
</ul>
<p>✅ Ensures <strong>fair resource usage</strong> and prevents runaway pods.</p>
<hr />
<h3 id="heading-resourcequota"><strong>ResourceQuota</strong></h3>
<p>A <strong>ResourceQuota</strong> is a <strong>namespace-level limit on the total resources</strong> that <strong>all pods/containers together</strong> can consume.</p>
<h3 id="heading-key-points-1">Key points:</h3>
<ul>
<li><p>Limits the <strong>sum of resources</strong> used by all pods in the namespace.</p>
</li>
<li><p>Can limit <strong>CPU, memory, number of pods, services, persistent volumes</strong>, etc.</p>
</li>
<li><p>Prevents a single namespace from consuming <strong>all cluster resources</strong>.</p>
</li>
</ul>
<h3 id="heading-example-1">Example:</h3>
<pre><code class="lang-plaintext">apiVersion: v1
kind: ResourceQuota
metadata:
  name: example-quota
  namespace: my-namespace
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 4Gi
    limits.cpu: "10"
    limits.memory: 10Gi
    pods: "10"
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p>The <strong>sum of CPU requests</strong> across all pods ≤ 4 CPU.</p>
</li>
<li><p>The <strong>sum of memory requests</strong> across all pods ≤ 4 GiB.</p>
</li>
<li><p>The <strong>sum of limits</strong> across all pods ≤ 10 CPU and 10 GiB memory.</p>
</li>
<li><p>Max 10 pods in this namespace.</p>
</li>
</ul>
<p>✅ Ensures <strong>overall resource governance</strong> at the namespace level.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758362878483/8f4ab90e-f270-44d2-be4d-bcec1435f00d.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-summary">⚖️ Summary</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Object</td><td>Scope</td><td>What it controls</td><td>Notes</td></tr>
</thead>
<tbody>
<tr>
<td><strong>LimitRange</strong></td><td>Namespace</td><td>Default requests &amp; limits, min/max</td><td>Applied to <strong>new pods</strong> only</td></tr>
<tr>
<td><strong>ResourceQuota</strong></td><td>Namespace</td><td>Total resource usage by <strong>all pods</strong></td><td>Controls aggregate CPU, memory, pod count, etc.</td></tr>
</tbody>
</table>
</div><hr />
<p>💡 <strong>Tip:</strong></p>
<ul>
<li><p>Use <strong>LimitRange</strong> to ensure each pod has same defaults and prevents very small/huge pods.</p>
</li>
<li><p>Use <strong>ResourceQuota</strong> to prevent a namespace from consuming all cluster resources.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Kubernetes Scheduling: A Complete Guide for Learners]]></title><description><![CDATA[Scheduling in Kubernetes determines which node a Pod will run on. Proper scheduling ensures workloads are efficiently distributed, critical Pods run on dedicated nodes, and cluster resources are optimally used.
Kubernetes provides multiple mechanisms...]]></description><link>https://blog.iresh.xyz/kubernetes-scheduling-a-complete-guide-for-learners</link><guid isPermaLink="true">https://blog.iresh.xyz/kubernetes-scheduling-a-complete-guide-for-learners</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Sat, 20 Sep 2025 07:27:32 GMT</pubDate><content:encoded><![CDATA[<p><strong>Scheduling in Kubernetes</strong> determines which node a Pod will run on. Proper scheduling ensures workloads are efficiently distributed, critical Pods run on dedicated nodes, and cluster resources are optimally used.</p>
<p>Kubernetes provides multiple mechanisms to control Pod placement, from <strong>direct assignment</strong> to <strong>advanced affinity rules and taints</strong>. In this guide, we’ll cover everything you need to understand scheduling and how to dedicate nodes for specific Pods.</p>
<hr />
<h2 id="heading-1-nodename-direct-scheduling">1. <mark>nodeName (Direct Scheduling)</mark></h2>
<p>The simplest way to assign a Pod to a node is using the <code>nodeName</code> field.</p>
<ul>
<li><p><strong>If nodeName is set:</strong> Kubernetes bypasses the scheduler and assigns the Pod directly.</p>
</li>
<li><p><strong>If nodeName is not set:</strong> The Pod goes to the scheduler for placement.</p>
</li>
</ul>
<p><strong>Example:</strong></p>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Pod
metadata:
  name: fixed-node-pod
spec:
  nodeName: node01
  containers:
  - name: nginx
    image: nginx
</code></pre>
<blockquote>
<p>⚠️ If <code>node01</code> is unavailable, the Pod stays in <strong>Pending</strong> state.</p>
</blockquote>
<p>Limitations of nodeName</p>
<ul>
<li><p><strong>Hard binding</strong>: Pod is tied to a single node.</p>
</li>
<li><p><strong>No flexibility</strong>: If <code>node01</code> is down or out of resources, Pod stays <strong>Pending</strong>.</p>
</li>
<li><p><strong>Not scalable</strong>: In dynamic clusters (nodes added/removed), <code>nodeName</code> creates operational headaches.</p>
</li>
</ul>
<p>⚠️ Because of these drawbacks, <code>nodeName</code> is <strong>rarely used in production</strong> (only for testing/debugging).<br />Instead, we use <strong>labels + selectors</strong> for flexible scheduling.</p>
<hr />
<h2 id="heading-2-scheduler-amp-binding">2. <mark>Scheduler &amp; Binding</mark></h2>
<p>When <code>nodeName</code> is <strong>not set</strong>, the Kubernetes scheduler:</p>
<ol>
<li><p>Checks available nodes.</p>
</li>
<li><p>Considers resources, labels, taints, and affinity rules.</p>
</li>
<li><p>Creates a <strong>Binding object</strong> linking the Pod to a node.</p>
</li>
</ol>
<p>You can inspect the binding:</p>
<pre><code class="lang-plaintext">kubectl get pod fixed-node-pod -o yaml
</code></pre>
<blockquote>
<p>The <code>spec.nodeName</code> field will appear after scheduling, even if not set manually.</p>
</blockquote>
<hr />
<h2 id="heading-3-labels-amp-selectors">3. <mark>Labels &amp; Selectors</mark></h2>
<ul>
<li><p><strong>Labels:</strong> Key-value metadata attached to Kubernetes objects (Pods, Nodes).</p>
</li>
<li><p><strong>Selectors:</strong> Queries that match labels.</p>
</li>
</ul>
<p>Used by the scheduler to decide Pod placement.</p>
<p><strong>Example: Node Label</strong></p>
<pre><code class="lang-plaintext">kubectl label nodes node01 disktype=ssd
</code></pre>
<p><strong>Example: Pod with nodeSelector</strong></p>
<pre><code class="lang-plaintext">spec:
  nodeSelector:
    disktype: ssd
  containers:
  - name: nginx
    image: nginx
</code></pre>
<blockquote>
<p>Pod will schedule <strong>only on nodes labeled</strong> <code>disktype=ssd</code>.</p>
</blockquote>
<hr />
<h2 id="heading-4-annotations">4. <mark>Annotations</mark></h2>
<ul>
<li><p>Key-value metadata that <strong>do not affect scheduling</strong>.</p>
</li>
<li><p>Useful for storing additional information like URLs, team info, or build data.</p>
</li>
</ul>
<p><strong>Example:</strong></p>
<pre><code class="lang-plaintext">metadata:
  annotations:
    team: devops
    description: "This Pod is for testing purposes"
</code></pre>
<hr />
<h2 id="heading-5-nodeselector-scheduling-with-labels"><mark>5. nodeSelector (Scheduling with Labels)</mark></h2>
<p><code>nodeSelector</code> is the simplest way to schedule Pods based on node labels.</p>
<ul>
<li><p>You <strong>label nodes</strong> with key-value pairs.</p>
</li>
<li><p>Pods with <code>nodeSelector</code> can run only on nodes with matching labels.</p>
</li>
</ul>
<h3 id="heading-example-label-a-node">Example: Label a node</h3>
<pre><code class="lang-plaintext">kubectl label nodes node01 disktype=ssd
</code></pre>
<h3 id="heading-example-pod-with-nodeselector">Example: Pod with nodeSelector</h3>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Pod
metadata:
  name: ssd-pod
spec:
  nodeSelector:
    disktype: ssd
  containers:
  - name: nginx
    image: nginx
</code></pre>
<p>✅ This Pod will only run on nodes labeled <code>disktype=ssd</code>.</p>
<hr />
<h3 id="heading-limitations-of-nodeselector">Limitations of nodeSelector</h3>
<ul>
<li><p>Only supports <strong>exact matches</strong> (<code>key=value</code>).</p>
</li>
<li><p>Cannot use advanced operators (<code>In</code>, <code>NotIn</code>, <code>Exists</code>).</p>
</li>
<li><p>No way to express <strong>preferences</strong> (e.g., “prefer SSD nodes but allow others”).</p>
</li>
<li><p>Too basic for complex production use cases.</p>
</li>
</ul>
<p>👉 That’s why Kubernetes introduced <strong>Node Affinity</strong>, which builds on <code>nodeSelector</code> and adds more powerful scheduling rules.</p>
<hr />
<h2 id="heading-6-node-affinity-amp-anti-affinity"><mark>6. Node Affinity &amp; Anti-Affinity</mark></h2>
<p>Node Affinity is an <strong>advanced version of Node Selector</strong>. It allows:</p>
<ul>
<li><p>Logical operators (<code>In</code>, <code>NotIn</code>, <code>Exists</code>)</p>
</li>
<li><p>Soft (preferred) or hard (required) scheduling rules</p>
</li>
<li><p>Anti-affinity to avoid scheduling Pods on nodes already running certain workloads</p>
</li>
</ul>
<h3 id="heading-node-affinity-rules">Node Affinity Rules</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Rule</td><td>Type</td><td>Scheduling Behavior</td><td>Execution Behavior</td></tr>
</thead>
<tbody>
<tr>
<td>RequiredDuringSchedulingIgnoredDuringExecution</td><td>Hard</td><td>Pod must schedule on matching node</td><td>Ignores node changes after scheduling</td></tr>
<tr>
<td>PreferredDuringSchedulingIgnoredDuringExecution</td><td>Soft</td><td>Pod prefers matching node</td><td>Ignores node changes after scheduling</td></tr>
<tr>
<td>RequiredDuringSchedulingRequiredDuringExecution</td><td>Hard</td><td>Pod must schedule on matching node</td><td>Pod is evicted if node stops matching</td></tr>
<tr>
<td>PreferredDuringSchedulingRequiredDuringExecution</td><td>Soft</td><td>Pod prefers matching node</td><td>Pod is evicted if node stops matching</td></tr>
</tbody>
</table>
</div><hr />
<h3 id="heading-example-requiredduringschedulingignoredduringexecution">Example: RequiredDuringSchedulingIgnoredDuringExecution</h3>
<pre><code class="lang-plaintext">affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: disktype
          operator: In
          values:
          - ssd
</code></pre>
<blockquote>
<p>Pod must schedule on nodes with <code>disktype=ssd</code>.</p>
</blockquote>
<hr />
<h3 id="heading-example-preferredduringschedulingignoredduringexecution">Example: PreferredDuringSchedulingIgnoredDuringExecution</h3>
<pre><code class="lang-plaintext">affinity:
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 1
      preference:
        matchExpressions:
        - key: disktype
          operator: In
          values:
          - ssd
</code></pre>
<blockquote>
<p>Pod prefers SSD nodes but can schedule elsewhere if no SSD node is available.</p>
</blockquote>
<hr />
<h3 id="heading-example-requiredduringschedulingrequiredduringexecution">Example: RequiredDuringSchedulingRequiredDuringExecution</h3>
<ul>
<li><p>Hard rule: Pod must be on a matching node.</p>
</li>
<li><p>Evicted if node stops matching.</p>
</li>
</ul>
<pre><code class="lang-plaintext">affinity:
  nodeAffinity:
    requiredDuringSchedulingRequiredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: dedicated
          operator: In
          values:
          - true
</code></pre>
<hr />
<h3 id="heading-example-preferredduringschedulingrequiredduringexecution">Example: PreferredDuringSchedulingRequiredDuringExecution</h3>
<ul>
<li>Soft rule during scheduling, but Pod is evicted if the node stops matching later.</li>
</ul>
<pre><code class="lang-plaintext">affinity:
  nodeAffinity:
    preferredDuringSchedulingRequiredDuringExecution:
    - weight: 1
      preference:
        matchExpressions:
        - key: dedicated
          operator: In
          values:
          - true
</code></pre>
<hr />
<h3 id="heading-pod-anti-affinity">Pod Anti-Affinity</h3>
<p>Avoid scheduling Pods on nodes already running certain Pods.</p>
<pre><code class="lang-plaintext">affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchExpressions:
        - key: app
          operator: In
          values:
          - frontend
      topologyKey: "kubernetes.io/hostname"
</code></pre>
<blockquote>
<p>Ensures Pods are <strong>spread across nodes</strong>, avoiding co-location.</p>
</blockquote>
<hr />
<h2 id="heading-7-taints-amp-tolerations"><mark>7. Taints &amp; Tolerations</mark></h2>
<ul>
<li><p><strong>Taints</strong> on nodes restrict which Pods can run there.</p>
</li>
<li><p><strong>Tolerations</strong> on Pods allow them to ignore taints.</p>
</li>
</ul>
<p><strong>Taint Effects</strong></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Effect</td><td>New non-tolerating Pods</td><td>Existing non-tolerating Pods</td><td>Example Use</td></tr>
</thead>
<tbody>
<tr>
<td>NoSchedule</td><td>❌ Never scheduled</td><td>✅ Can keep running</td><td>Protect nodes</td></tr>
<tr>
<td>PreferNoSchedule</td><td>⚠️ Avoid scheduling</td><td>✅ Can keep running</td><td>Prefer other nodes</td></tr>
<tr>
<td>NoExecute</td><td>❌ Never scheduled</td><td>❌ Evicted</td><td>Critical workloads</td></tr>
</tbody>
</table>
</div><p><strong>Example:</strong></p>
<pre><code class="lang-plaintext">kubectl taint nodes node01 dedicated=teamA:NoSchedule
</code></pre>
<p>Pod toleration:</p>
<pre><code class="lang-plaintext">tolerations:
- key: "dedicated"
  operator: "Equal"
  value: "teamA"
  effect: "NoSchedule"
</code></pre>
<blockquote>
<p>Alone, this <strong>does not dedicate</strong> the node — Pod can still schedule on untainted nodes.</p>
</blockquote>
<hr />
<h2 id="heading-8-dedicating-nodes-combining-node-affinity-taints"><mark>8. Dedicating Nodes: Combining Node Affinity + Taints</mark></h2>
<p>Sometimes in Kubernetes, you want to <strong>reserve certain nodes for specific workloads</strong>, for example:</p>
<ul>
<li><p>GPU nodes for ML workloads</p>
</li>
<li><p>High-memory nodes for database Pods</p>
</li>
<li><p>Critical services that should not compete with general workloads</p>
</li>
</ul>
<p>Using <strong>only one mechanism</strong> (like taints or node affinity) is often <strong>not enough</strong>:</p>
<ol>
<li><p><strong>Taints &amp; Tolerations alone</strong></p>
<ul>
<li><p>A taint marks a node so that only Pods with a matching toleration can be scheduled there.</p>
</li>
<li><p><strong>Limitation:</strong> Pods with that toleration can still be scheduled on other untainted nodes.</p>
</li>
</ul>
</li>
</ol>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758350408375/195acc4c-91ae-4244-bdcb-22314f4689e0.png" alt class="image--center mx-auto" /></p>
<ul>
<li>✅ Protects nodes from unwanted Pods, but does <strong>not guarantee exclusivity</strong>.</li>
</ul>
<ol start="2">
<li><p><strong>Node Affinity alone</strong></p>
<ul>
<li><p>Node Affinity guides the scheduler to place Pods on nodes with matching labels.</p>
</li>
<li><p><strong>Limitation:</strong> Other Pods without affinity rules can still be scheduled on those nodes.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758350599592/9f86c99b-3f1f-49b7-ab15-f75c0eb0d6f5.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>✅ Useful for preference or required placement, but cannot block others.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-the-combined-approach-recommended">The Combined Approach (Recommended)</h3>
<p>To truly <strong>dedicate a node exclusively</strong>:</p>
<ol>
<li><p><strong>Taint the node</strong> → blocks unwanted Pods.</p>
</li>
<li><p><strong>Add Node Affinity to the Pod</strong> → ensures only the intended Pods are scheduled there.</p>
</li>
</ol>
<p>This combination ensures:</p>
<ul>
<li><p>Only Pods with the <strong>correct toleration + affinity</strong> can be scheduled.</p>
</li>
<li><p>All other Pods are <strong>prevented</strong> from using that node.</p>
</li>
<li><p>Dedicated nodes are reserved for special workloads.</p>
</li>
</ul>
<h3 id="heading-step-by-step-example">Step-by-Step Example</h3>
<h4 id="heading-step-1-taint-the-node">Step 1: Taint the Node</h4>
<pre><code class="lang-plaintext">kubectl taint nodes node01 dedicated=true:NoSchedule
</code></pre>
<ul>
<li>Node <code>node01</code> now rejects any Pod <strong>without</strong> the <code>dedicated=true</code> toleration.</li>
</ul>
<h4 id="heading-step-2-pod-yaml-with-toleration-node-affinity">Step 2: Pod YAML with Toleration + Node Affinity</h4>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Pod
metadata:
  name: dedicated-pod
spec:
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: dedicated
            operator: In
            values:
            - "true"
  containers:
  - name: nginx
    image: nginx
</code></pre>
<p>✅ Behavior:</p>
<ul>
<li><p>Pod <strong>can only schedule</strong> on <code>node01</code>.</p>
</li>
<li><p>Other Pods <strong>cannot</strong> use <code>node01</code>.</p>
</li>
<li><p>Node is effectively <strong>dedicated</strong> to this workload.</p>
</li>
</ul>
<h3 id="heading-why-use-both">Why Use Both?</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Mechanism</td><td>What it Controls</td><td>Limitation</td></tr>
</thead>
<tbody>
<tr>
<td>Taints + Tolerations</td><td>Blocks unwanted Pods</td><td>Pods with matching tolerations can still go to other nodes</td></tr>
<tr>
<td>Node Affinity</td><td>Guides Pods to specific nodes</td><td>Other Pods can still land on the node</td></tr>
<tr>
<td><strong>Combined</strong></td><td>Dedicate nodes exclusively</td><td>Ensures only the intended Pods run on that node</td></tr>
</tbody>
</table>
</div><h3 id="heading-use-cases">Use Cases</h3>
<ul>
<li><p><strong>GPU Nodes:</strong> Only ML workloads with GPU toleration + affinity can schedule there.</p>
</li>
<li><p><strong>High-Memory Nodes:</strong> Critical databases get dedicated memory nodes.</p>
</li>
<li><p><strong>Master/Control Nodes:</strong> Prevent regular workloads from running there while allowing special system Pods.</p>
</li>
</ul>
<p>This approach is <strong>widely used in production clusters</strong> where resource isolation and workload predictability are important.</p>
<hr />
<p>Summery</p>
<hr />
<h1 id="heading-kubernetes-pod-scheduling-from-basics-to-dedicated-nodes">🧭 Kubernetes Pod Scheduling: From Basics to Dedicated Nodes</h1>
<p>In Kubernetes, scheduling decides <strong>which node a Pod will run on</strong>. By default, the scheduler spreads Pods across the cluster. But in real-world scenarios, we often want more control — for example:</p>
<ul>
<li><p>Running database workloads only on SSD-backed nodes.</p>
</li>
<li><p>Ensuring GPU workloads only land on GPU nodes.</p>
</li>
<li><p>Keeping monitoring agents separate from application Pods.</p>
</li>
</ul>
<p>Kubernetes gives us several tools to influence scheduling. Let’s walk through them step by step — starting from the simplest (<code>nodeName</code>) to the most powerful combination (<strong>Node Affinity + Taints</strong>).</p>
<hr />
<h2 id="heading-1-nodename">1. 🔹 <code>nodeName</code></h2>
<p>The most direct scheduling method. You tell Kubernetes exactly which node to run on.</p>
<pre><code class="lang-plaintext">spec:
  nodeName: worker-1
</code></pre>
<h3 id="heading-advantages">✅ Advantages</h3>
<ul>
<li><p>Simple and explicit — Pod always runs on the named node.</p>
</li>
<li><p>Bypasses the scheduler (fast).</p>
</li>
</ul>
<h3 id="heading-limitations">⚠️ Limitations</h3>
<ul>
<li><p><strong>Hard-coded</strong> — tied to a single node.</p>
</li>
<li><p><strong>No flexibility</strong> — if that node is down or full, Pod won’t run.</p>
</li>
<li><p>Doesn’t scale in production.</p>
</li>
</ul>
<p>👉 Useful only for debugging or extreme edge cases.</p>
<hr />
<h2 id="heading-2-nodeselector">2. 🔹 <code>nodeSelector</code></h2>
<p>A more flexible alternative. Instead of hardcoding nodes, you use labels.</p>
<pre><code class="lang-plaintext">spec:
  nodeSelector:
    disktype: ssd
</code></pre>
<h3 id="heading-advantages-1">✅ Advantages</h3>
<ul>
<li><p>Easy to target groups of nodes by label.</p>
</li>
<li><p>Scheduler still chooses the best fit within that group.</p>
</li>
<li><p>Simple to set up.</p>
</li>
</ul>
<h3 id="heading-limitations-1">⚠️ Limitations</h3>
<ul>
<li><p>Only supports <strong>exact match</strong> (<code>=</code>).</p>
</li>
<li><p>No advanced expressions (OR, NOT, ranges).</p>
</li>
<li><p>Still rigid for complex workloads.</p>
</li>
</ul>
<p>👉 Better than <code>nodeName</code>, but limited for real-world scenarios.</p>
<hr />
<h2 id="heading-3-node-affinity-amp-anti-affinity">3. 🔹 Node Affinity &amp; Anti-Affinity</h2>
<p>Node affinity is a more <strong>expressive version of</strong> <code>nodeSelector</code>. It allows rules with operators and conditions.</p>
<pre><code class="lang-plaintext">affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: disktype
          operator: In
          values: ["ssd", "nvme"]
</code></pre>
<h3 id="heading-advantages-2">✅ Advantages</h3>
<ul>
<li><p>Rich operators: <code>In</code>, <code>NotIn</code>, <code>Exists</code>, <code>Gt</code>, <code>Lt</code>.</p>
</li>
<li><p>Supports <strong>hard</strong> rules (<code>requiredDuringScheduling…</code>) and <strong>soft</strong> preferences (<code>preferredDuringScheduling…</code>).</p>
</li>
<li><p><strong>Anti-affinity</strong> helps avoid placing Pods together (e.g., keep replicas apart).</p>
</li>
</ul>
<h3 id="heading-limitations-2">⚠️ Limitations</h3>
<ul>
<li><p><strong>Only works at scheduling time</strong> → once scheduled, Pods don’t move if nodes change.</p>
</li>
<li><p><strong>Not exclusive</strong> → other Pods without affinity can still land on those nodes.</p>
</li>
<li><p><strong>No eviction</strong> → scheduler won’t reshuffle Pods later.</p>
</li>
</ul>
<p>👉 Great for <strong>preferences and constraints</strong>, but not for <strong>isolation</strong>.</p>
<hr />
<h2 id="heading-4-taints-and-tolerations">4. 🔹 Taints and Tolerations</h2>
<p>While affinity attracts Pods to nodes, taints <strong>repel Pods</strong> unless they tolerate it.</p>
<pre><code class="lang-plaintext">kubectl taint nodes worker-2 dedicated=db:NoSchedule
</code></pre>
<p>Pod toleration:</p>
<pre><code class="lang-plaintext">tolerations:
- key: "dedicated"
  operator: "Equal"
  value: "db"
  effect: "NoSchedule"
</code></pre>
<h3 id="heading-advantages-3">✅ Advantages</h3>
<ul>
<li><p>Protects reserved nodes from general workloads.</p>
</li>
<li><p>Fine-grained control:</p>
<ul>
<li><p><code>NoSchedule</code> → don’t place Pods.</p>
</li>
<li><p><code>PreferNoSchedule</code> → try to avoid.</p>
</li>
<li><p><code>NoExecute</code> → evict existing Pods.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-limitations-3">⚠️ Limitations</h3>
<ul>
<li><p><strong>Too permissive</strong> — any Pod with the same toleration can run there.</p>
</li>
<li><p><strong>No attraction mechanism</strong> — only prevents, doesn’t guide Pods.</p>
</li>
<li><p><strong>Risk of idle nodes</strong> if no Pods have tolerations.</p>
</li>
<li><p><strong>Team drift</strong> → multiple workloads might add tolerations and unintentionally overload special nodes.</p>
</li>
</ul>
<p>👉 Great for <strong>blocking unwanted Pods</strong>, but not enough to guarantee <strong>dedicated use</strong>.</p>
<hr />
<h2 id="heading-5-dedicating-nodes-combining-node-affinity-taints">5. 🔹 Dedicating Nodes: Combining Node Affinity + Taints</h2>
<p>The best practice for <strong>exclusive node usage</strong> is to combine both:</p>
<ul>
<li><p><strong>Node Affinity</strong> → attracts the right Pods.</p>
</li>
<li><p><strong>Taints</strong> → repels everything else.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-plaintext">affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: workload
          operator: In
          values: ["gpu"]
tolerations:
- key: "workload"
  operator: "Equal"
  value: "gpu"
  effect: "NoSchedule"
</code></pre>
<h3 id="heading-result">🎯 Result</h3>
<ul>
<li><p>GPU workloads land only on GPU nodes.</p>
</li>
<li><p>No other Pods can run there accidentally.</p>
</li>
<li><p>Guarantees <strong>dedicated scheduling</strong>.</p>
</li>
</ul>
<hr />
<h1 id="heading-scheduling-evolution-flow">🚀 Scheduling Evolution Flow</h1>
<ol>
<li><p><code>nodeName</code> → too rigid.</p>
</li>
<li><p><code>nodeSelector</code> → basic labels, limited.</p>
</li>
<li><p><strong>Node Affinity</strong> → flexible rules, but still shared.</p>
</li>
<li><p><strong>Taints &amp; Tolerations</strong> → node-level protection, but not exclusive.</p>
</li>
<li><p><strong>Affinity + Taints</strong> → full control, dedicated nodes.</p>
</li>
</ol>
<hr />
<h1 id="heading-conclusion">📝 Conclusion</h1>
<p>Kubernetes scheduling evolved from <strong>hardcoding</strong> to <strong>flexible rules</strong> to <strong>node protection</strong>. Each method builds on the previous:</p>
<ul>
<li><p>Start with <strong>labels</strong> for organization (<code>nodeSelector</code>).</p>
</li>
<li><p>Use <strong>affinity/anti-affinity</strong> for advanced rules.</p>
</li>
<li><p>Apply <strong>taints/tolerations</strong> to protect nodes.</p>
</li>
<li><p>Combine both for <strong>dedicated, isolated workloads</strong>.</p>
</li>
</ul>
<p>👉 This layered approach gives you <strong>fine-grained control</strong> over Pod placement while keeping the cluster efficient and reliable.</p>
<hr />
<p>💡 Pro tip: For production environments, always prefer <strong>Affinity + Taints</strong> when you want guaranteed workload isolation.</p>
]]></content:encoded></item><item><title><![CDATA[From Waterfall to DevOps: A Beginner’s Guide to Modern Software Delivery]]></title><description><![CDATA[1. Why DevOps Exists
Before we can understand DevOps, we need to know how software development used to work - and why it needed to change.
In the early days, teams often used the Waterfall Model - a structured, phase-by-phase approach where each stag...]]></description><link>https://blog.iresh.xyz/from-waterfall-to-devops-a-beginners-guide-to-modern-software-delivery</link><guid isPermaLink="true">https://blog.iresh.xyz/from-waterfall-to-devops-a-beginners-guide-to-modern-software-delivery</guid><category><![CDATA[Development Methodologies]]></category><category><![CDATA[Devops]]></category><category><![CDATA[agile]]></category><category><![CDATA[Scrum]]></category><category><![CDATA[Waterfall Model]]></category><category><![CDATA[software development]]></category><category><![CDATA[project management]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[continuous delivery]]></category><category><![CDATA[Software Engineering]]></category><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Fri, 15 Aug 2025 09:23:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755249150028/f2dc4d6e-8c71-4ac5-a938-9adc844617e1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-1-why-devops-exists"><strong>1. Why DevOps Exists</strong></h2>
<p>Before we can understand <em>DevOps</em>, we need to know how software development used to work - and why it needed to change.</p>
<p>In the early days, teams often used the <strong>Waterfall Model</strong> - a structured, phase-by-phase approach where each stage had to be completed before moving to the next.</p>
<h2 id="heading-2-the-waterfall-model"><strong>2. The Waterfall Model</strong></h2>
<p><strong>How it works:</strong></p>
<ol>
<li><p><strong>Project Planning</strong> – Define objectives and timelines.</p>
</li>
<li><p><strong>Requirements Gathering</strong> – Collect all the features from users.</p>
</li>
<li><p><strong>Analysis &amp; Design</strong> – Plan the system’s structure and appearance.</p>
</li>
<li><p><strong>Development</strong> – Write the code.</p>
</li>
<li><p><strong>Testing</strong> – Verify the system works.</p>
</li>
<li><p><strong>Deployment</strong> – Release the final product.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755248284006/bcfa6e7b-cbc0-4e56-9abc-30cfee9fbc31.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p><strong>Advantages:</strong></p>
<ul>
<li><p>Clear separation of phases.</p>
</li>
<li><p>Easy to estimate cost and timelines.</p>
</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li><p>Users only see the product at the very end.</p>
</li>
<li><p>Changes are hard to manage once a phase is complete.</p>
</li>
<li><p>Bugs found late can cause massive rework.</p>
</li>
<li><p>Long timelines mean business needs may change before release.</p>
</li>
</ul>
<h2 id="heading-3-the-agile-shift"><strong>3. The Agile Shift</strong></h2>
<p>In <strong>2001</strong>, 17 software developers created the <strong>Agile Manifesto</strong>, introducing a faster and more flexible way to deliver software.</p>
<p><strong>How Agile works:</strong></p>
<ul>
<li><p>Break projects into <strong>small, manageable pieces</strong>.</p>
</li>
<li><p>Deliver working features in <strong>short increments</strong>.</p>
</li>
<li><p>Use <strong>cross-functional teams</strong> (development, testing, operations, product).</p>
</li>
<li><p>Maintain <strong>continuous collaboration</strong> with customers.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755248881533/7b31e52e-2b72-47d7-990a-e0bd36b5b82e.png" alt class="image--center mx-auto" /></p>
<p><strong>Benefits:</strong></p>
<ul>
<li><p>Faster delivery of usable features.</p>
</li>
<li><p>Easier to adapt to changing requirements.</p>
</li>
<li><p>Constant feedback from end-users.</p>
</li>
</ul>
<h2 id="heading-4-scrum-an-agile-framework"><strong>4. Scrum - An Agile Framework</strong></h2>
<p>Scrum is one of the most popular ways to apply Agile principles.</p>
<p><strong>Key concepts:</strong></p>
<ul>
<li><p><strong>User Stories</strong> – Simple, user-focused requirements.</p>
</li>
<li><p><strong>Product Backlog</strong> – All desired features in one list.</p>
</li>
<li><p><strong>Sprints</strong> – Short development cycles (2–4 weeks).</p>
</li>
<li><p><strong>Sprint Backlog</strong> – Items chosen for the current sprint.</p>
</li>
<li><p><strong>Review &amp; Retrospective</strong> – Showcase progress and improve for the next sprint.</p>
</li>
</ul>
<p><strong>Why it works:</strong></p>
<ul>
<li><p>Regular delivery of value.</p>
</li>
<li><p>Continuous improvement.</p>
</li>
<li><p>Works well for ongoing feature updates after release.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755248780642/de35a91c-fa17-4063-b092-7ed676f2ebcc.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-5-the-gap-between-development-and-operations"><strong>5. The Gap Between Development and Operations</strong></h2>
<p>Even with Agile, a major problem remained:</p>
<ul>
<li><p><strong>Developers</strong> want to release new features quickly.</p>
</li>
<li><p><strong>Operations</strong> teams focus on stability and uptime.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755249428786/aa425d0c-7469-43b8-8d04-215caa0dd3db.jpeg" alt class="image--center mx-auto" /></p>
<p>This caused:</p>
<ul>
<li><p>Delays from long approval processes.</p>
</li>
<li><p>Hesitation to deploy changes.</p>
</li>
<li><p>Risks of security or performance issues.</p>
</li>
</ul>
<h2 id="heading-6-devops-closing-the-gap"><strong>6. DevOps - Closing the Gap</strong></h2>
<p><strong>DevOps</strong> is both a culture and a set of practices that bridges Development and Operations.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755248938029/7d37e916-f165-4f8b-b8fd-8e569c99e360.webp" alt class="image--center mx-auto" /></p>
<p><strong>Core ideas:</strong></p>
<ul>
<li><p><strong>Collaboration from Day 1</strong> – Developers and Ops work together from planning through deployment.</p>
</li>
<li><p><strong>Automation</strong> – Continuous Integration and Continuous Deployment (CI/CD) to deliver changes faster.</p>
</li>
<li><p><strong>Shared Responsibility</strong> – Everyone is accountable for quality, security, and uptime.</p>
</li>
</ul>
<p><strong>Challenges in adopting DevOps:</strong></p>
<ul>
<li><p>Requires a <strong>mindset shift</strong> across teams.</p>
</li>
<li><p>Traditional approval-heavy processes slow automation.</p>
</li>
<li><p>Tools are important, but culture change matters more.</p>
</li>
</ul>
<h2 id="heading-7-the-big-picture"><strong>7. The Big Picture</strong></h2>
<p>The journey looks like this:<br /><strong>Waterfall → Agile → Scrum → DevOps</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755249646134/b5a80aeb-bd1a-45a7-8093-efc55f32ff32.png" alt class="image--center mx-auto" /></p>
<p>We moved to DevOps because:</p>
<ul>
<li><p>Software must be delivered faster.</p>
</li>
<li><p>Quality must be maintained (or improved).</p>
</li>
<li><p>Teams must collaborate instead of working in silos.</p>
</li>
</ul>
<p><strong>DevOps is not a tool - it’s a way of working.</strong></p>
<p>💡 <strong>Key Takeaway:</strong><br />DevOps combines speed, collaboration, and continuous improvement. By breaking down barriers between development and operations, teams can deliver value to users faster - without sacrificing quality or stability.</p>
]]></content:encoded></item><item><title><![CDATA[L4. Understanding Terraform State: Remote Backend and State Locking – A Beginner’s Guide]]></title><description><![CDATA[Terraform is a powerful tool for automating infrastructure as code, but to use it effectively, it's important to understand how it manages the infrastructure it creates - through Terraform state.
This guide explains what a Terraform state file is, wh...]]></description><link>https://blog.iresh.xyz/l4-understanding-terraform-state-remote-backend-and-state-locking-a-beginners-guide</link><guid isPermaLink="true">https://blog.iresh.xyz/l4-understanding-terraform-state-remote-backend-and-state-locking-a-beginners-guide</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Fri, 15 Aug 2025 08:45:22 GMT</pubDate><content:encoded><![CDATA[<p>Terraform is a powerful tool for automating infrastructure as code, but to use it effectively, it's important to understand how it manages the infrastructure it creates - through <strong>Terraform state</strong>.</p>
<p>This guide explains what a Terraform state file is, why it matters, the challenges of local state management, how to use a remote backend like AWS S3, and how to implement state locking using DynamoDB - all tailored for beginners and students.</p>
<hr />
<h2 id="heading-what-is-terraform-state">🌱 What is Terraform State?</h2>
<p>Terraform keeps track of your real-world infrastructure using a file called <code>terraform.tfstate</code>.</p>
<p>Whenever you apply a Terraform configuration, Terraform:</p>
<ol>
<li><p>Provisions the resources you defined (e.g., EC2 instances, VPCs, etc.)</p>
</li>
<li><p>Saves metadata about those resources in the <strong>state file</strong>.</p>
</li>
</ol>
<p>This file is the <strong>single source of truth</strong> for Terraform. Without it, Terraform wouldn’t know what has already been created, updated, or deleted.</p>
<hr />
<h2 id="heading-why-is-terraform-state-important">🧠 Why is Terraform State Important?</h2>
<p>Imagine this: You create an EC2 instance using Terraform. Later, you want to add a tag. If Terraform doesn't know the instance already exists (because there’s no state file), it will try to create a <strong>new instance</strong> instead of updating the existing one. ❌</p>
<p>With the state file, Terraform can:</p>
<ul>
<li><p>Compare your current config with the real infrastructure.</p>
</li>
<li><p>Determine what to <strong>add</strong>, <strong>change</strong>, or <strong>delete</strong>.</p>
</li>
<li><p>Safely manage updates and ensure <strong>idempotency</strong> (the ability to run the same script multiple times without unintended changes).</p>
</li>
</ul>
<hr />
<h2 id="heading-the-drawbacks-of-local-state-files">⚠️ The Drawbacks of Local State Files</h2>
<p>While the local state file works, it comes with serious issues:</p>
<h3 id="heading-1-sensitive-data-exposure">1. <strong>Sensitive Data Exposure</strong></h3>
<p>The state file can include <strong>secrets</strong>, such as API keys, passwords, and sensitive resource details. If it's stored on a local machine or pushed to a Git repository, anyone with access can read them.</p>
<h3 id="heading-2-team-collaboration-challenges">2. <strong>Team Collaboration Challenges</strong></h3>
<p>If multiple people are working on the same Terraform project:</p>
<ul>
<li><p>Everyone must <strong>remember to share or sync</strong> the updated state file.</p>
</li>
<li><p>Forgetting to do so causes <strong>drift</strong> between actual infrastructure and Terraform’s understanding.</p>
</li>
<li><p>Multiple versions of the state file can lead to resource conflicts or duplication.</p>
</li>
</ul>
<hr />
<h2 id="heading-solution-using-remote-backends">☁️ Solution: Using Remote Backends</h2>
<p>Terraform offers <strong>remote backends</strong> to solve these problems. One of the most popular backends is <strong>AWS S3</strong>.</p>
<h3 id="heading-how-does-it-help">🔧 How Does It Help?</h3>
<ul>
<li><p>Your state file is stored in <strong>S3</strong>, not on your local machine.</p>
</li>
<li><p>It’s always <strong>up-to-date</strong> since Terraform writes to S3 directly when changes are applied.</p>
</li>
<li><p>You can <strong>restrict access</strong> to the S3 bucket using IAM policies.</p>
</li>
</ul>
<hr />
<h3 id="heading-setting-up-s3-as-a-remote-backend">✅ Setting Up S3 as a Remote Backend</h3>
<ol>
<li><strong>Create an S3 bucket</strong> (manually or using Terraform):</li>
</ol>
<pre><code class="lang-bash">resource <span class="hljs-string">"aws_s3_bucket"</span> <span class="hljs-string">"tf_backend"</span> {
  bucket = <span class="hljs-string">"my-unique-terraform-backend-bucket"</span>
}
</code></pre>
<ol start="2">
<li><strong>Configure your backend in</strong> <code>backend.tf</code>:</li>
</ol>
<pre><code class="lang-bash">terraform {
  backend <span class="hljs-string">"s3"</span> {
    bucket = <span class="hljs-string">"my-unique-terraform-backend-bucket"</span>
    key    = <span class="hljs-string">"statefiles/terraform.tfstate"</span>
    region = <span class="hljs-string">"us-east-1"</span>
  }
}
</code></pre>
<ol start="3">
<li><strong>Initialize the backend</strong>:</li>
</ol>
<pre><code class="lang-bash">terraform init
</code></pre>
<p>Terraform will now store the state file in S3 instead of your local disk. 🎉</p>
<hr />
<h2 id="heading-what-about-state-locking">🔒 What About State Locking?</h2>
<p>Here’s a new concern:</p>
<blockquote>
<p>What if two people run <code>terraform apply</code> at the same time?</p>
</blockquote>
<p>That could cause a race condition, where both changes conflict or overwrite each other.</p>
<h3 id="heading-enter-state-locking-with-dynamodb">🚪 Enter State Locking with DynamoDB</h3>
<p>Terraform can <strong>lock</strong> the state file using <strong>AWS DynamoDB</strong>, ensuring that only one person can modify infrastructure at a time.</p>
<hr />
<h3 id="heading-setting-up-dynamodb-for-locking">🔐 Setting Up DynamoDB for Locking</h3>
<ol>
<li><strong>Create a DynamoDB Table</strong>:</li>
</ol>
<pre><code class="lang-bash">resource <span class="hljs-string">"aws_dynamodb_table"</span> <span class="hljs-string">"tf_locks"</span> {
  name         = <span class="hljs-string">"terraform-locks"</span>
  billing_mode = <span class="hljs-string">"PAY_PER_REQUEST"</span>
  hash_key     = <span class="hljs-string">"LockID"</span>

  attribute {
    name = <span class="hljs-string">"LockID"</span>
    <span class="hljs-built_in">type</span> = <span class="hljs-string">"S"</span>
  }
}
</code></pre>
<ol start="2">
<li><strong>Update your</strong> <code>backend.tf</code> to include locking configuration:</li>
</ol>
<pre><code class="lang-bash">terraform {
  backend <span class="hljs-string">"s3"</span> {
    bucket         = <span class="hljs-string">"my-unique-terraform-backend-bucket"</span>
    key            = <span class="hljs-string">"statefiles/terraform.tfstate"</span>
    region         = <span class="hljs-string">"us-east-1"</span>
    dynamodb_table = <span class="hljs-string">"terraform-locks"</span>
  }
}
</code></pre>
<ol start="3">
<li><strong>Re-initialize</strong> to apply backend changes:</li>
</ol>
<pre><code class="lang-bash">terraform init
</code></pre>
<p>Now, Terraform uses the DynamoDB table to <strong>lock and unlock</strong> the state file safely. Only one <code>terraform apply</code> can run at a time.</p>
<hr />
<h2 id="heading-testing-it-out">🧪 Testing It Out</h2>
<p>You can test your setup like this:</p>
<ol>
<li><p>Write a simple EC2 instance configuration in <code>main.tf</code>.</p>
</li>
<li><p>Run:</p>
</li>
</ol>
<pre><code class="lang-bash">terraform init
terraform apply
</code></pre>
<ol start="3">
<li><p>Observe that your state is <strong>no longer stored locally</strong>, but in <strong>S3</strong>.</p>
</li>
<li><p>Terraform now uses <strong>DynamoDB</strong> to lock the state during apply operations.</p>
</li>
</ol>
<hr />
<h2 id="heading-summary">🚀 Summary</h2>
<p>Here’s what we’ve covered:</p>
<ul>
<li><p>✅ <strong>Terraform State</strong> tracks your infrastructure.</p>
</li>
<li><p>❌ <strong>Local state files</strong> pose risks: sensitive data exposure and sync issues.</p>
</li>
<li><p>☁️ <strong>Remote backends (like S3)</strong> solve these problems.</p>
</li>
<li><p>🔒 <strong>State locking with DynamoDB</strong> prevents conflicting changes.</p>
</li>
</ul>
<p>This setup is <strong>production-grade</strong> and a <strong>must-know</strong> for anyone planning to work in a team or manage infrastructure securely using Terraform.</p>
<hr />
<h2 id="heading-bonus-useful-terraform-commands">🧰 Bonus: Useful Terraform Commands</h2>
<pre><code class="lang-bash">terraform init       <span class="hljs-comment"># Initializes the backend and providers</span>
terraform plan       <span class="hljs-comment"># Shows what changes will be made</span>
terraform apply      <span class="hljs-comment"># Applies the changes</span>
terraform show       <span class="hljs-comment"># Displays the current state</span>
terraform destroy    <span class="hljs-comment"># Destroys the resources</span>
</code></pre>
<hr />
<p>Got questions or need help? Leave a comment or explore the official Terraform Backend Docs for more.</p>
<p>Happy coding! 🌍⚙️</p>
]]></content:encoded></item><item><title><![CDATA[🛑 Kubernetes Graceful Shutdown: PreStop Hooks, Probes, and Termination Lifecycle Explained]]></title><description><![CDATA[When deploying applications in Kubernetes, it's not just about running a container and calling it a day. Kubernetes manages the entire pod lifecycle - from startup to health checks to shutdown - and that includes graceful termination.
Whether it's du...]]></description><link>https://blog.iresh.xyz/kubernetes-graceful-shutdown-prestop-hooks-probes-and-termination-lifecycle-explained</link><guid isPermaLink="true">https://blog.iresh.xyz/kubernetes-graceful-shutdown-prestop-hooks-probes-and-termination-lifecycle-explained</guid><category><![CDATA[#K8sLifecycle]]></category><category><![CDATA[#GracefulShutdown]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Devops]]></category><category><![CDATA[probes]]></category><category><![CDATA[cloud native]]></category><category><![CDATA[#SiteReliabilityEngineering]]></category><category><![CDATA[RollingUpdates]]></category><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Thu, 31 Jul 2025 19:40:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753990616400/5764fc55-35c3-4493-9f78-d39b218ee4ad.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When deploying applications in Kubernetes, it's not just about running a container and calling it a day. Kubernetes manages the <strong>entire pod lifecycle</strong> - from startup to health checks to shutdown - and that includes <strong>graceful termination</strong>.</p>
<p>Whether it's due to a <strong>rolling update</strong>, <strong>node scaling</strong>, <strong>OOM crash</strong>, or even a <strong>manual</strong> <code>kubectl delete</code>, Kubernetes gives us the tools to shut down pods <strong>gracefully</strong>-without losing traffic or corrupting data.</p>
<p>In this post, we’ll break down:</p>
<ul>
<li><p>What happens during a pod termination</p>
</li>
<li><p>How lifecycle hooks like <code>preStop</code> work</p>
</li>
<li><p>The role of probes in shutdown</p>
</li>
<li><p>How to avoid dropped traffic or forced shutdowns</p>
</li>
</ul>
<h2 id="heading-when-does-kubernetes-terminate-pods">📌 When Does Kubernetes Terminate Pods?</h2>
<p>Pod termination can happen for several reasons:</p>
<ul>
<li><p>🚀 Rolling updates</p>
</li>
<li><p>⚖️ Node scaling or maintenance</p>
</li>
<li><p>💥 Crashes or Out-Of-Memory (OOM) errors</p>
</li>
<li><p>🔧 Manual deletion (e.g., <code>kubectl delete pod</code>)</p>
</li>
<li><p>❌ Failing <code>livenessProbe</code></p>
</li>
</ul>
<p>If your app is still handling requests or doing important work, an <strong>instant kill</strong> could cause problems. Instead, Kubernetes provides a <strong>graceful shutdown</strong> mechanism.</p>
<hr />
<h2 id="heading-quick-glossary">🧠 Quick Glossary</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Concept</td><td>Meaning</td></tr>
</thead>
<tbody>
<tr>
<td><code>preStop</code> hook</td><td>A lifecycle hook that runs just before the container is stopped</td></tr>
<tr>
<td><code>terminationGracePeriodSeconds</code></td><td>How long Kubernetes waits before forcefully killing the pod</td></tr>
<tr>
<td><code>readinessProbe</code></td><td>Marks pod as "ready" to receive traffic</td></tr>
<tr>
<td><code>livenessProbe</code></td><td>Checks if pod is healthy/alive</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-what-happens-when-you-delete-a-pod">🛑 What Happens When You Delete a Pod?</h2>
<p>Let's say you run:</p>
<pre><code class="lang-bash">kubectl delete pod my-app
</code></pre>
<p>Here’s what Kubernetes does <strong>step-by-step</strong>:</p>
<ol>
<li><p><strong>Marks pod as "Terminating"</strong></p>
</li>
<li><p>Removes pod from Service <strong>via readiness probe failure</strong> - Not Ready (so no new traffic is sent to the pod).</p>
</li>
<li><p><strong>Runs the</strong> <code>preStop</code> hook (if defined)</p>
</li>
<li><p><strong>Sends SIGTERM to the container</strong>.</p>
</li>
<li><p><strong>Waits for</strong> <code>terminationGracePeriodSeconds</code></p>
</li>
<li><p>If the container is still running after the grace period, sends <strong>SIGKILL</strong> to force kill.</p>
</li>
<li><p><strong>Deletes the pod</strong></p>
</li>
</ol>
<p><img src="https://drek4537l1klr.cloudfront.net/luksa/Figures/17fig05_alt.jpg" alt class="image--center mx-auto" /></p>
<p>25 (terminationGracePeriodSeconds) = 5 (preStop) + 15 (app shutdown) + 5 (buffer)</p>
<h2 id="heading-kubernetes-pod-termination-flow-step-by-step">🔄 Kubernetes Pod Termination Flow (Step-by-Step)</h2>
<h3 id="heading-step-1-termination-is-triggered">🔹 Step 1: Termination is Triggered</h3>
<p>Termination is initiated by:</p>
<ul>
<li><p><code>kubectl delete pod</code></p>
</li>
<li><p>Rolling update (Deployment, StatefulSet)</p>
</li>
<li><p>Node scaling or eviction</p>
</li>
<li><p>Failing <code>livenessProbe</code></p>
</li>
</ul>
<p>📍 The API server receives the delete request and sets <code>deletionTimestamp</code> on the pod.</p>
<hr />
<h3 id="heading-step-2-pod-is-marked-as-terminating">🔹 Step 2: Pod is Marked as Terminating</h3>
<p>The pod <strong>is not deleted immediately</strong>.</p>
<ul>
<li><p>It's marked as <code>Terminating</code></p>
</li>
<li><p>The controller (e.g., ReplicaSet) may spin up a <strong>replacement pod</strong></p>
</li>
</ul>
<hr />
<h3 id="heading-step-3-kubelet-detects-termination">🔹 Step 3: Kubelet Detects Termination</h3>
<ul>
<li><p>The <strong>Kubelet</strong> on the node watches the API server.</p>
</li>
<li><p>It sees the pod is terminating and starts <strong>graceful shutdown</strong>.</p>
</li>
</ul>
<hr />
<h3 id="heading-step-4-prestop-hook-executes">🔹 Step 4: <code>preStop</code> Hook Executes</h3>
<p>If you’ve defined a <code>preStop</code> hook in your pod spec:</p>
<pre><code class="lang-bash">lifecycle:
  preStop:
    <span class="hljs-built_in">exec</span>:
      <span class="hljs-built_in">command</span>: [<span class="hljs-string">"/usr/bin/save-state.sh"</span>]
</code></pre>
<p>Kubelet executes it using:</p>
<ul>
<li><p><code>exec</code> (run a command in the container)</p>
</li>
<li><p><code>httpGet</code> (make HTTP call to internal endpoint)</p>
</li>
<li><p><code>tcpSocket</code> (deprecated)</p>
</li>
</ul>
<p>🕒 The hook <strong>must complete</strong> before SIGTERM is sent.</p>
<hr />
<h3 id="heading-step-5-sigterm-is-sent">🔹 Step 5: SIGTERM Is Sent</h3>
<p>After <code>preStop</code> finishes, Kubelet sends a <strong>SIGTERM</strong> signal to the container.</p>
<p>This gives your app a chance to shut down politely - like:</p>
<ul>
<li><p>Closing DB connections</p>
</li>
<li><p>Draining message queues</p>
</li>
<li><p>Finishing current request</p>
</li>
</ul>
<blockquote>
<p>⚠️ If your app <strong>doesn’t handle SIGTERM</strong>, it may be killed before completing shutdown.</p>
</blockquote>
<hr />
<h3 id="heading-step-6-termination-grace-period-countdown">🔹 Step 6: Termination Grace Period Countdown</h3>
<p>The clock starts ticking based on:</p>
<pre><code class="lang-bash">spec:
  terminationGracePeriodSeconds: 30
</code></pre>
<ul>
<li><p>The total time includes <strong>preStop + app shutdown</strong></p>
</li>
<li><p>Default is 30 seconds</p>
</li>
</ul>
<hr />
<h3 id="heading-step-7-sigkill-if-timeout-expires">🔹 Step 7: SIGKILL If Timeout Expires</h3>
<p>If the container is still running after the grace period, Kubernetes sends:</p>
<pre><code class="lang-bash">SIGKILL
</code></pre>
<p>At this point, the container is forcefully stopped - even if it's still working.</p>
<hr />
<h3 id="heading-step-8-pod-is-deleted">🔹 Step 8: Pod Is Deleted</h3>
<p>Once the container stops:</p>
<ul>
<li><p>The Kubelet deletes the pod from the node</p>
</li>
<li><p>The API server removes the pod from the cluster state</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753989040635/85ca2819-5a19-4e6c-85dd-a8bd25159b73.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-wrapping-up">📣 Wrapping Up</h2>
<p>Kubernetes gives you the <strong>tools to shut down pods cleanly</strong>-but it's up to you to use them right.</p>
<p>By defining a <code>preStop</code> hook, setting a realistic <code>terminationGracePeriodSeconds</code>, and properly using probes, you can:</p>
<ul>
<li><p>Avoid dropped connections</p>
</li>
<li><p>Prevent data corruption</p>
</li>
<li><p>Ensure smoother rolling updates</p>
</li>
</ul>
<hr />
<h1 id="heading-understanding-kubernetes-pod-lifecycle-with-restaurant-analogy">🚀 Understanding Kubernetes Pod Lifecycle with Restaurant Analogy 🍽️</h1>
<p>From Startup to Shutdown - Explained Visually with Liveness, Readiness, PreStop &amp; Termination Grace</p>
<h2 id="heading-1-pod-starts-restaurant-opening">🏁 1. Pod Starts = Restaurant Opening</h2>
<h3 id="heading-restaurant-analogy">🍽️ Restaurant Analogy:</h3>
<ul>
<li><p><strong>Staff arrives.</strong></p>
</li>
<li><p><strong>Kitchen is being prepped.</strong></p>
</li>
<li><p><strong>The "Open" sign is still OFF.</strong></p>
</li>
<li><p>Customers are NOT allowed in yet.</p>
</li>
</ul>
<blockquote>
<p>🔍 Readiness Probe returns ❌</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753982871182/04cc06df-9f57-43d0-95b6-a00eb6e1bef3.png" alt="A restaurant with a &quot;Closed&quot; sign, staff inside cooking/prepping." class="image--center mx-auto" /></p>
<p>A restaurant with a "Closed" sign, staff inside cooking/prepping.</p>
<h3 id="heading-kubernetes-explanation">⚙️ Kubernetes Explanation:</h3>
<ul>
<li><p>Pod is created.</p>
</li>
<li><p>Containers inside start.</p>
</li>
<li><p>Kubernetes starts checking the <code>readinessProbe</code>.</p>
</li>
<li><p>If <code>readinessProbe</code> fails → <strong>Pod is NOT added to Service LoadBalancer.</strong></p>
</li>
</ul>
<hr />
<h2 id="heading-2-pod-is-ready-open-to-customers">✅ 2. Pod is Ready = Open to Customers</h2>
<h3 id="heading-restaurant-analogy-1">🍽️ Restaurant Analogy:</h3>
<ul>
<li><p>Kitchen is ready.</p>
</li>
<li><p>Staff says: "We’re good to go!"</p>
</li>
<li><p>"Open" sign is ON.</p>
</li>
<li><p>Google Maps starts showing your restaurant.</p>
</li>
<li><p>Customers (traffic) start coming in.</p>
</li>
</ul>
<blockquote>
<p>✅ Readiness Probe passes</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753982999341/36e386ad-f94c-42b8-b4c4-4ed83e1f33b3.png" alt class="image--center mx-auto" /></p>
<p>A restaurant with customers entering, kitchen in action.</p>
<h3 id="heading-kubernetes-explanation-1">⚙️ Kubernetes Explanation:</h3>
<ul>
<li><p><code>readinessProbe</code> starts returning success.</p>
</li>
<li><p>Pod is added to Service endpoints.</p>
</li>
<li><p>Kubernetes sends traffic to the pod.</p>
</li>
<li><p>The pod is now <strong>Ready</strong>.</p>
</li>
</ul>
<hr />
<h2 id="heading-3-staying-healthy-passing-health-inspections">❤️ 3. Staying Healthy = Passing Health Inspections</h2>
<h3 id="heading-restaurant-analogy-2">🍽️ Restaurant Analogy:</h3>
<ul>
<li><p>Health inspector comes in <strong>every 10 minutes</strong>.</p>
</li>
<li><p>Checks kitchen, staff, environment.</p>
</li>
<li><p>If staff fainted, kitchen on fire - 🚫 you fail.</p>
</li>
</ul>
<blockquote>
<p>Liveness Probe checks every interval</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753983053594/62fa0e5f-0ee7-426a-8156-115cf3df4d3a.png" alt class="image--center mx-auto" /></p>
<p>Health inspector checking kitchen hygiene.</p>
<h3 id="heading-kubernetes-explanation-2">⚙️ Kubernetes Explanation:</h3>
<ul>
<li><p><code>livenessProbe</code> runs periodically.</p>
</li>
<li><p>If the liveness probe fails:</p>
<ul>
<li><p>Kubernetes kills and restarts the container.</p>
</li>
<li><p>Useful when your app hangs but doesn’t crash.</p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-4-shutdown-begins-landlord-gives-notice">🛑 4. Shutdown Begins = Landlord Gives Notice</h2>
<h3 id="heading-restaurant-analogy-3">🍽️ Restaurant Analogy:</h3>
<p>Landlord (Kubernetes) says:<br /><strong>"You're shutting down in 60 seconds."</strong></p>
<ul>
<li><p>You lock the front door → 🛑 No more new customers.</p>
</li>
<li><p>Waiters finish serving ongoing orders.</p>
</li>
<li><p>Kitchen finishes cooking.</p>
</li>
<li><p>Staff exits gracefully.</p>
</li>
</ul>
<blockquote>
<p>This 60s is your <code>terminationGracePeriodSeconds</code></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753987724115/8e10a66d-b807-49d0-bc89-e296fa3d2c3a.png" alt class="image--center mx-auto" /></p>
<p>Restaurant putting up “Closing soon” sign, waiters finishing orders.</p>
<h3 id="heading-kubernetes-explanation-3">⚙️ Kubernetes Explanation:</h3>
<ul>
<li><p>Kubernetes initiates pod shutdown (e.g., due to <code>kubectl delete pod</code>).</p>
</li>
<li><p>Kubernetes updates the <strong>readiness probe</strong> status (Not Ready/Terminating).</p>
</li>
<li><p>Waits for <code>terminationGracePeriodSeconds</code> (default: 30s).</p>
</li>
<li><p>Meanwhile:</p>
<ul>
<li><p>Executes <code>preStop</code> hook.</p>
</li>
<li><p>Stops sending traffic by failing readiness.</p>
</li>
<li><p>Allows app to clean up (e.g., finish jobs, close DB).</p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-5-prestop-hook-locking-the-door">🔒 5. PreStop Hook = Locking the Door</h2>
<h3 id="heading-restaurant-analogy-4">🍽️ Restaurant Analogy:</h3>
<ul>
<li><p>You run a command: "Lock the front door."</p>
</li>
<li><p>Sign flips to “Closed.”</p>
</li>
<li><p>Waiters: “No new customers allowed.”</p>
</li>
</ul>
<blockquote>
<p>preStop is a lifecycle hook that runs BEFORE SIGTERM</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753987799496/c64fe3ed-c096-4de7-a042-39f373b80783.png" alt class="image--center mx-auto" /></p>
<p>Staff removing restaurant from food delivery app before closing.</p>
<h3 id="heading-kubernetes-explanation-4">⚙️ Kubernetes Explanation:</h3>
<ul>
<li><p><code>preStop</code> runs BEFORE SIGTERM.</p>
</li>
<li><p>Often used to:</p>
<ul>
<li><p>Unregister from a service discovery system.</p>
</li>
<li><p>Drain ongoing traffic.</p>
</li>
<li><p>Notify other systems.</p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-6-graceful-exit-wrap-up">🔚 6. Graceful Exit = Wrap-up</h2>
<h3 id="heading-restaurant-analogy-5">🍽️ Restaurant Analogy:</h3>
<ul>
<li><p>No new customers.</p>
</li>
<li><p>Kitchen finishes pending dishes.</p>
</li>
<li><p>Staff exits.</p>
</li>
<li><p>Everyone goes home. No force needed.</p>
</li>
</ul>
<blockquote>
<p>All done within terminationGracePeriodSeconds ✅</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753987843315/43bd1187-87ab-4366-a4d1-12cae890cbf8.png" alt class="image--center mx-auto" /></p>
<p>Restaurant empty, lights off, sign = "Closed".</p>
<h3 id="heading-kubernetes-explanation-5">⚙️ Kubernetes Explanation:</h3>
<ul>
<li><p>Your app finishes cleanup before the grace period ends.</p>
</li>
<li><p>Container exits.</p>
</li>
<li><p>Pod gets removed cleanly.</p>
</li>
<li><p>No data loss. No corruption.</p>
</li>
</ul>
<hr />
<h2 id="heading-7-forced-shutdown-bouncer-kicks-you-out">💀 7. Forced Shutdown = Bouncer Kicks You Out</h2>
<h3 id="heading-restaurant-analogy-6">🍽️ Restaurant Analogy:</h3>
<ul>
<li><p>You took too long to close.</p>
</li>
<li><p>Landlord sends security (SIGKILL).</p>
</li>
<li><p>Everyone kicked out.</p>
</li>
<li><p>Food wasted, customers angry.</p>
</li>
</ul>
<blockquote>
<p>❗ SIGKILL is sent when terminationGracePeriodSeconds is exceeded</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753987893554/eba2175a-b5ee-4a4a-afba-0a164dbc84b8.png" alt class="image--center mx-auto" /></p>
<p>Angry landlord dragging staff out, customers confused.</p>
<h3 id="heading-kubernetes-explanation-6">⚙️ Kubernetes Explanation:</h3>
<ul>
<li><p>If your app doesn’t terminate within the grace period:</p>
<ul>
<li><p>Kubernetes sends <strong>SIGKILL</strong>.</p>
</li>
<li><p>Immediate stop.</p>
</li>
<li><p>You can't recover anything.</p>
</li>
<li><p>This may cause <strong>data loss</strong> (e.g., half-written files).</p>
</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[L3. Mastering Terraform Modules: Clean, Reusable Infrastructure for DevOps Beginners]]></title><description><![CDATA[One of the most powerful yet underused features of Terraform is the concept of modules.
If you’re a beginner, student, or new DevOps engineer, you’ve probably written Terraform code in one big file. But what happens when your infrastructure grows? Wh...]]></description><link>https://blog.iresh.xyz/l3-mastering-terraform-modules-clean-reusable-infrastructure-for-devops-beginners</link><guid isPermaLink="true">https://blog.iresh.xyz/l3-mastering-terraform-modules-clean-reusable-infrastructure-for-devops-beginners</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Wed, 14 May 2025 17:55:49 GMT</pubDate><content:encoded><![CDATA[<p>One of the most powerful yet underused features of Terraform is the concept of <strong>modules</strong>.</p>
<p>If you’re a beginner, student, or new DevOps engineer, you’ve probably written Terraform code in one big file. But what happens when your infrastructure grows? What if your team wants to reuse the same code across environments or projects?</p>
<p>Welcome to the world of <strong>Terraform modules</strong> - a structured, maintainable, and reusable way to write your infrastructure as code.</p>
<p>Let’s explore this in-depth.</p>
<hr />
<h2 id="heading-what-is-a-terraform-module">📦 What is a Terraform Module?</h2>
<p>A <strong>module</strong> in Terraform is simply a folder that contains <code>.tf</code> files - your Terraform configurations - which can be reused across projects.</p>
<blockquote>
<p>A module is to Terraform what a function is to programming.</p>
</blockquote>
<h3 id="heading-why-use-modules">Why Use Modules?</h3>
<ul>
<li><p>✅ <strong>Avoid code duplication</strong></p>
</li>
<li><p>✅ <strong>Increase reusability</strong> across teams and environments</p>
</li>
<li><p>✅ <strong>Enable better testing and debugging</strong></p>
</li>
<li><p>✅ <strong>Enforce standards</strong> across infrastructure</p>
</li>
<li><p>✅ <strong>Encourage team collaboration</strong> with ownership and modular thinking</p>
</li>
</ul>
<hr />
<h2 id="heading-real-world-analogy">🔧 Real-World Analogy</h2>
<p>Imagine you're working at a company like <a target="_blank" href="http://amazon.com"><code>amazon.com</code></a> and the app is a <strong>monolithic Java codebase</strong> with 1 million+ lines of code. When there's a bug, it's hard to know who wrote what, where to fix it, and how to test it without deploying the entire app.</p>
<p>The fix? <strong>Microservices</strong> - smaller, decoupled, maintainable codebases.</p>
<h3 id="heading-similarly-in-terraform">Similarly in Terraform:</h3>
<p>Without modules, your <code>.tf</code> file will grow with:</p>
<ul>
<li><p>EC2 Instances</p>
</li>
<li><p>S3 Buckets</p>
</li>
<li><p>VPCs</p>
</li>
<li><p>Lambda Functions</p>
</li>
<li><p>Load Balancers</p>
</li>
<li><p>EKS clusters<br />  ...and more.</p>
</li>
</ul>
<p>It becomes <strong>impossible to maintain</strong> or collaborate on.</p>
<p>That’s why we adopt a <strong>modular approach</strong> in Terraform - breaking things into small, logical, reusable units.</p>
<hr />
<h2 id="heading-creating-a-basic-terraform-module-step-by-step">🛠 Creating a Basic Terraform Module (Step-by-Step)</h2>
<p>Let’s build a reusable <strong>EC2 instance module</strong>.</p>
<h3 id="heading-folder-structure">📁 Folder Structure</h3>
<pre><code class="lang-bash">terraform-project/
├── main.tf
├── modules/
│   └── ec2_instance/
│       ├── main.tf
│       ├── variables.tf
│       ├── outputs.tf
</code></pre>
<hr />
<h3 id="heading-step-1-inside-modulesec2instancemaintfhttpmaintf">🔨 Step 1: Inside <code>modules/ec2_instance/</code><a target="_blank" href="http://main.tf"><code>main.tf</code></a></h3>
<pre><code class="lang-bash">resource <span class="hljs-string">"aws_instance"</span> <span class="hljs-string">"example"</span> {
  ami           = var.ami_value
  instance_type = var.instance_type_value
  subnet_id     = var.subnet_id_value
}
</code></pre>
<hr />
<h3 id="heading-step-2-define-variables-in-modulesec2instancevariablestfhttpvariablestf">📥 Step 2: Define Variables in <code>modules/ec2_instance/</code><a target="_blank" href="http://variables.tf"><code>variables.tf</code></a></h3>
<pre><code class="lang-bash">variable <span class="hljs-string">"ami_value"</span> {
  description = <span class="hljs-string">"AMI ID for the EC2 instance"</span>
}

variable <span class="hljs-string">"instance_type_value"</span> {
  description = <span class="hljs-string">"EC2 instance type"</span>
}

variable <span class="hljs-string">"subnet_id_value"</span> {
  description = <span class="hljs-string">"Subnet ID for the instance"</span>
}
</code></pre>
<hr />
<h3 id="heading-step-3-output-public-ip-in-modulesec2instanceoutputstfhttpoutputstf">📤 Step 3: Output Public IP in <code>modules/ec2_instance/</code><a target="_blank" href="http://outputs.tf"><code>outputs.tf</code></a></h3>
<pre><code class="lang-bash">output <span class="hljs-string">"public_ip"</span> {
  value = aws_instance.example.public_ip
}
</code></pre>
<hr />
<h3 id="heading-step-4-consume-the-module-in-root-maintfhttpmaintf">🧪 Step 4: Consume the Module in Root <a target="_blank" href="http://main.tf"><code>main.tf</code></a></h3>
<pre><code class="lang-bash">provider <span class="hljs-string">"aws"</span> {
  region = <span class="hljs-string">"us-east-1"</span>
}

module <span class="hljs-string">"ec2_instance"</span> {
  <span class="hljs-built_in">source</span>              = <span class="hljs-string">"./modules/ec2_instance"</span>
  ami_value           = <span class="hljs-string">"ami-0c55b159cbfafe1f0"</span>
  instance_type_value = <span class="hljs-string">"t2.micro"</span>
  subnet_id_value     = <span class="hljs-string">"subnet-0123456789abcdef0"</span>
}
</code></pre>
<hr />
<h2 id="heading-how-it-works">📌 How It Works</h2>
<p>When you run:</p>
<pre><code class="lang-bash">terraform init
terraform apply
</code></pre>
<p>Terraform will:</p>
<ul>
<li><p>Load the <code>ec2_instance</code> module</p>
</li>
<li><p>Inject the variables you passed</p>
</li>
<li><p>Create the EC2 instance</p>
</li>
<li><p>Output the public IP</p>
</li>
</ul>
<hr />
<h2 id="heading-why-this-is-so-powerful">🔁 Why This Is So Powerful</h2>
<h3 id="heading-imagine-this-scenario">Imagine this scenario:</h3>
<p>You have 3 dev teams, each needing EC2 instances with different configurations.</p>
<p>With modules:</p>
<ul>
<li><p>You reuse the same module</p>
</li>
<li><p>Just pass different <code>ami</code>, <code>instance_type</code>, and <code>subnet_id</code></p>
</li>
<li><p>No duplicated code</p>
</li>
</ul>
<h3 id="heading-additional-benefits">Additional Benefits:</h3>
<ul>
<li><p>🧱 <strong>Modularity</strong> – Break infrastructure into building blocks</p>
</li>
<li><p>🔄 <strong>Reusability</strong> – Use the same logic across teams</p>
</li>
<li><p>🧪 <strong>Testability</strong> – Test modules in isolation</p>
</li>
<li><p>🔐 <strong>Security</strong> – Keep secrets in <code>terraform.tfvars</code> (not in code)</p>
</li>
<li><p>📚 <strong>Documentation &amp; Ownership</strong> – Clear inputs and outputs make team collaboration easier</p>
</li>
</ul>
<hr />
<h2 id="heading-optional-use-terraformtfvars-to-supply-values">🔐 Optional: Use <code>terraform.tfvars</code> to Supply Values</h2>
<p>Create a <code>terraform.tfvars</code> file in your root directory:</p>
<pre><code class="lang-bash">ami_value           = <span class="hljs-string">"ami-0c55b159cbfafe1f0"</span>
instance_type_value = <span class="hljs-string">"t2.micro"</span>
subnet_id_value     = <span class="hljs-string">"subnet-0123456789abcdef0"</span>
</code></pre>
<p>Then just run:</p>
<pre><code class="lang-bash">terraform apply
</code></pre>
<p>Terraform will automatically pick up values from this file.</p>
<hr />
<h2 id="heading-where-should-you-store-modules">🗃️ Where Should You Store Modules?</h2>
<ul>
<li><p>In the same repo (like above)</p>
</li>
<li><p>In a <strong>separate GitHub repo</strong> (shared across projects)</p>
</li>
<li><p>Use <strong>Terraform Registry</strong> (like DockerHub for modules)</p>
</li>
</ul>
<blockquote>
<p>❗ In production, avoid unknown public modules unless you trust the source.<br />Companies usually create <strong>private module registries</strong> in GitHub or Terraform Cloud.</p>
</blockquote>
<hr />
<h2 id="heading-pro-tip-modules-scale-with-your-org">🚀 Pro Tip: Modules Scale With Your Org</h2>
<p>Let’s say your team writes modules for:</p>
<ul>
<li><p><code>ec2_instance</code></p>
</li>
<li><p><code>s3_bucket</code></p>
</li>
<li><p><code>eks_cluster</code></p>
</li>
<li><p><code>vpc</code></p>
</li>
<li><p><code>alb</code></p>
</li>
</ul>
<p>Now, internal developers can simply consume those like building blocks - without writing full configurations.</p>
<pre><code class="lang-bash">module <span class="hljs-string">"s3_bucket"</span> {
  <span class="hljs-built_in">source</span> = <span class="hljs-string">"git::https://github.com/org/modules.git//s3"</span>
  bucket_name = <span class="hljs-string">"my-app-logs"</span>
}
</code></pre>
<hr />
<h2 id="heading-summary">✅ Summary</h2>
<p>Terraform modules are the <strong>secret weapon</strong> for writing production-grade infrastructure:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Benefit</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>Modularity</td><td>Smaller, manageable components</td></tr>
<tr>
<td>Reusability</td><td>Use same code across environments/teams</td></tr>
<tr>
<td>Security</td><td>Keep sensitive data out of source control</td></tr>
<tr>
<td>Collaboration</td><td>Clear ownership and shared modules</td></tr>
<tr>
<td>Scalability</td><td>Codebase stays clean as infra grows</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-final-thoughts">🔚 Final Thoughts</h2>
<p>If you’re serious about mastering Terraform, start thinking in <strong>modules</strong> today.</p>
<p>Instead of managing huge <code>.tf</code> files, break your infrastructure into clean, reusable, and testable units - just like developers do with microservices.</p>
<blockquote>
<p>"Good DevOps is modular. Great DevOps is reusable."</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[L2. Terraform Providers, Variables, and Project Structuring - A Practical Beginner’s Guide]]></title><description><![CDATA[Learning Terraform opens the door to managing cloud infrastructure using Infrastructure as Code (IaC). In this guide, we’ll dive into providers, variables, multi-cloud setups, and how to structure a professional Terraform project.
This blog is especi...]]></description><link>https://blog.iresh.xyz/terraform-providers-variables-and-project-structuring-a-practical-beginners-guide-part-02</link><guid isPermaLink="true">https://blog.iresh.xyz/terraform-providers-variables-and-project-structuring-a-practical-beginners-guide-part-02</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Wed, 14 May 2025 15:58:22 GMT</pubDate><content:encoded><![CDATA[<p>Learning <strong>Terraform</strong> opens the door to managing cloud infrastructure using <strong>Infrastructure as Code (IaC)</strong>. In this guide, we’ll dive into <strong>providers</strong>, <strong>variables</strong>, <strong>multi-cloud setups</strong>, and how to structure a professional Terraform project.</p>
<p>This blog is especially for <strong>students, new learners</strong>, and <strong>junior DevOps engineers</strong> who want to build a solid foundation in Terraform - without getting overwhelmed.</p>
<hr />
<h2 id="heading-what-is-a-provider-in-terraform">🔌 What Is a Provider in Terraform?</h2>
<p>A <strong>provider</strong> in Terraform is a plugin that connects Terraform to your cloud platform (like AWS, Azure, GCP, etc.).</p>
<blockquote>
<p>Think of it as the <em>bridge</em> between your Terraform code and the cloud infrastructure you're trying to automate.</p>
</blockquote>
<h3 id="heading-example-aws-provider">🔧 Example: AWS Provider</h3>
<pre><code class="lang-bash">provider <span class="hljs-string">"aws"</span> {
  region = <span class="hljs-string">"us-east-1"</span>
}
</code></pre>
<p>This block tells Terraform:</p>
<ul>
<li><p>Use the AWS provider</p>
</li>
<li><p>Target the <code>us-east-1</code> region</p>
</li>
</ul>
<p>Terraform will then use this configuration to authenticate and create resources in AWS.</p>
<h3 id="heading-tip">🧠 Tip:</h3>
<p>Without a provider block, Terraform <strong>won’t know</strong>:</p>
<ul>
<li><p>Which cloud to talk to</p>
</li>
<li><p>How to authenticate</p>
</li>
<li><p>Where to create infrastructure</p>
</li>
</ul>
<hr />
<h2 id="heading-official-partner-amp-community-providers">☁️ Official, Partner &amp; Community Providers</h2>
<p>Terraform supports <strong>hundreds of providers</strong>, categorized as:</p>
<ol>
<li><p><strong>Official Providers</strong> – Maintained by HashiCorp<br /> e.g., AWS, Azure, GCP, Kubernetes</p>
</li>
<li><p><strong>Partner Providers</strong> – Maintained by vendors (e.g., Oracle, Alibaba)</p>
</li>
<li><p><strong>Community Providers</strong> – Maintained by the community (less reliable)</p>
</li>
</ol>
<blockquote>
<p>✅ Always check provider activity and documentation at: registry.terraform.io</p>
</blockquote>
<hr />
<h2 id="heading-multi-region-and-multi-cloud-configuration">🌐 Multi-Region and Multi-Cloud Configuration</h2>
<h3 id="heading-multi-region-setup-single-cloud-multiple-regions">🔁 Multi-Region Setup (Single Cloud, Multiple Regions)</h3>
<p>To deploy resources in multiple AWS regions:</p>
<pre><code class="lang-bash">provider <span class="hljs-string">"aws"</span> {
  <span class="hljs-built_in">alias</span>  = <span class="hljs-string">"use1"</span>
  region = <span class="hljs-string">"us-east-1"</span>
}

provider <span class="hljs-string">"aws"</span> {
  <span class="hljs-built_in">alias</span>  = <span class="hljs-string">"usw2"</span>
  region = <span class="hljs-string">"us-west-2"</span>
}

resource <span class="hljs-string">"aws_instance"</span> <span class="hljs-string">"east"</span> {
  provider      = aws.use1
  ami           = <span class="hljs-string">"ami-east"</span>
  instance_type = <span class="hljs-string">"t2.micro"</span>
}

resource <span class="hljs-string">"aws_instance"</span> <span class="hljs-string">"west"</span> {
  provider      = aws.usw2
  ami           = <span class="hljs-string">"ami-west"</span>
  instance_type = <span class="hljs-string">"t2.micro"</span>
}
</code></pre>
<h3 id="heading-multi-cloud-setup-eg-aws-azure">🌐 Multi-Cloud Setup (e.g., AWS + Azure)</h3>
<pre><code class="lang-bash">provider <span class="hljs-string">"aws"</span> {
  region = <span class="hljs-string">"us-east-1"</span>
}

provider <span class="hljs-string">"azurerm"</span> {
  features = {}
  subscription_id = <span class="hljs-string">"your-subscription-id"</span>
  client_id       = <span class="hljs-string">"your-client-id"</span>
  client_secret   = <span class="hljs-string">"your-secret"</span>
  tenant_id       = <span class="hljs-string">"your-tenant-id"</span>
}
</code></pre>
<blockquote>
<p>⚠️ Each provider has a unique name and authentication mechanism. Use the official docs to get syntax and examples.</p>
</blockquote>
<hr />
<h2 id="heading-terraform-resources">🧱 Terraform Resources</h2>
<p>A <strong>resource</strong> represents a piece of infrastructure - like an EC2 instance, an S3 bucket, or a virtual machine.</p>
<h3 id="heading-example-aws-ec2-instance">🧩 Example (AWS EC2 Instance):</h3>
<pre><code class="lang-bash">resource <span class="hljs-string">"aws_instance"</span> <span class="hljs-string">"example"</span> {
  ami           = var.ami_id
  instance_type = var.instance_type
}
</code></pre>
<blockquote>
<p>Use documentation to find the correct syntax and resource names (e.g., <code>aws_instance</code>, <code>azurerm_virtual_machine</code>).</p>
</blockquote>
<hr />
<h2 id="heading-variables-in-terraform">💡 Variables in Terraform</h2>
<p>Hardcoding values (like AMI IDs, instance types) is <strong>bad practice</strong>. Use <strong>variables</strong> to make your Terraform configuration reusable.</p>
<h3 id="heading-input-variables-defined-in-variablestf">🔽 Input Variables (Defined in <code>variables.tf</code>)</h3>
<pre><code class="lang-bash">variable <span class="hljs-string">"ami_id"</span> {
  description = <span class="hljs-string">"AMI for EC2"</span>
  <span class="hljs-built_in">type</span>        = string
  default     = <span class="hljs-string">"ami-0abcd1234"</span>
}

variable <span class="hljs-string">"instance_type"</span> {
  description = <span class="hljs-string">"Instance type"</span>
  <span class="hljs-built_in">type</span>        = string
  default     = <span class="hljs-string">"t2.micro"</span>
}
</code></pre>
<h3 id="heading-output-variables-defined-in-outputstf">🔼 Output Variables (Defined in <code>outputs.tf</code>)</h3>
<pre><code class="lang-bash">output <span class="hljs-string">"instance_ip"</span> {
  description = <span class="hljs-string">"Public IP of the instance"</span>
  value       = aws_instance.example.public_ip
}
</code></pre>
<hr />
<h2 id="heading-tfvars-dynamic-value-management">🧾 TFVARS: Dynamic Value Management</h2>
<p>To <strong>dynamically pass values</strong> instead of hardcoding them in <code>.tf</code> files, use a <code>terraform.tfvars</code> file:</p>
<pre><code class="lang-bash">ami_id        = <span class="hljs-string">"ami-07a5b1a7"</span>
instance_type = <span class="hljs-string">"t2.medium"</span>
</code></pre>
<p>Terraform will automatically load this file during <code>terraform apply</code>. For custom files:</p>
<pre><code class="lang-bash">terraform apply -var-file=<span class="hljs-string">"prod.tfvars"</span>
</code></pre>
<hr />
<h2 id="heading-conditional-expressions-in-terraform">🧠 Conditional Expressions in Terraform</h2>
<p>Use <strong>conditionals</strong> when you want to assign values based on a variable (like environment type):</p>
<h3 id="heading-example-conditional-cidr-block">🔐 Example: Conditional CIDR Block</h3>
<pre><code class="lang-bash">cidr_blocks = var.environment == <span class="hljs-string">"prod"</span> ? [<span class="hljs-string">"10.0.1.0/24"</span>] : [<span class="hljs-string">"10.0.2.0/24"</span>]
</code></pre>
<p>This logic:</p>
<ul>
<li><p>Assigns one subnet range in production</p>
</li>
<li><p>Assigns another for development</p>
</li>
</ul>
<p>✅ Use it for:</p>
<ul>
<li><p>Public access controls</p>
</li>
<li><p>Instance types</p>
</li>
<li><p>Resource counts</p>
</li>
<li><p>Tags and naming conventions</p>
</li>
</ul>
<hr />
<h2 id="heading-built-in-functions-in-terraform">🔧 Built-in Functions in Terraform</h2>
<p>Terraform provides useful <strong>built-in functions</strong> to manipulate data:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Function</td><td>Description</td><td>Example</td></tr>
</thead>
<tbody>
<tr>
<td><code>length()</code></td><td>Get the length of a list</td><td><code>length(var.subnet_ids)</code></td></tr>
<tr>
<td><code>upper()</code></td><td>Convert to uppercase</td><td><code>upper(var.env)</code></td></tr>
<tr>
<td><code>map()</code></td><td>Create a map from key/value pairs</td><td><code>map("env", "dev", "tier", "web")</code></td></tr>
</tbody>
</table>
</div><p>More at Terraform Function Docs</p>
<hr />
<h2 id="heading-recommended-project-structure">📁 Recommended Project Structure</h2>
<p>To keep things clean and scalable, organize files like this:</p>
<pre><code class="lang-bash">terraform-project/
├── main.tf            <span class="hljs-comment"># Core logic</span>
├── variables.tf       <span class="hljs-comment"># Input variables</span>
├── outputs.tf         <span class="hljs-comment"># Output variables</span>
├── provider.tf        <span class="hljs-comment"># Provider blocks</span>
├── terraform.tfvars   <span class="hljs-comment"># Variable values</span>
</code></pre>
<p>This modular structure:</p>
<ul>
<li><p>Improves readability</p>
</li>
<li><p>Makes collaboration easier</p>
</li>
<li><p>Encourages reuse across environments🧪 Key Takeaways</p>
</li>
</ul>
<p>✅ Providers connect Terraform to your cloud<br />✅ Use aliases for multi-region or multi-cloud setups<br />✅ Resources define what to deploy<br />✅ Variables and TFVARS make code reusable<br />✅ Conditionals and functions make configurations smarter<br />✅ Project structure matters for maintainability</p>
<hr />
<p>🎯 Start writing small modules using providers and variables.<br />🔍 Read official provider docs.<br />🛠 Practice customizing configurations for different environments.</p>
]]></content:encoded></item><item><title><![CDATA[L1. A Complete Beginner’s Guide to Infrastructure as Code]]></title><description><![CDATA[🧠 What You'll Learn in This Guide
✅ Understand what Infrastructure as Code (IaC) really means✅ Learn why Terraform is the top tool in the DevOps toolbox✅ Install Terraform (even if you can't install software on your laptop!)✅ Set up AWS authenticati...]]></description><link>https://blog.iresh.xyz/a-complete-beginners-guide-to-infrastructure-as-code</link><guid isPermaLink="true">https://blog.iresh.xyz/a-complete-beginners-guide-to-infrastructure-as-code</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Wed, 14 May 2025 13:55:38 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-what-youll-learn-in-this-guide">🧠 What You'll Learn in This Guide</h2>
<p>✅ Understand what <strong>Infrastructure as Code (IaC)</strong> really means<br />✅ Learn why <strong>Terraform</strong> is the top tool in the DevOps toolbox<br />✅ Install Terraform (even if you can't install software on your laptop!)<br />✅ Set up <strong>AWS authentication</strong><br />✅ Write your first <strong>Terraform script</strong><br />✅ Deploy your first <strong>EC2 instance</strong><br />✅ Learn about <strong>Terraform’s lifecycle commands</strong>: <code>init</code>, <code>plan</code>, <code>apply</code>, <code>destroy</code><br />✅ Understand <strong>Terraform's state file</strong> and its importance</p>
<h2 id="heading-infrastructure-as-code-iac-explained-simply">🌐 Infrastructure as Code (IaC) – Explained Simply</h2>
<p>Instead of manually creating cloud resources using the AWS Console, you <strong>write code</strong> to define and manage your infrastructure. This code can be versioned, reused, and shared - just like software code.</p>
<h3 id="heading-example">Example:</h3>
<ul>
<li><p>Creating 1 S3 bucket? Easy via the AWS console.</p>
</li>
<li><p>Creating 100 S3 buckets? IaC makes it fast, repeatable, and error-free.</p>
</li>
</ul>
<h3 id="heading-traditional-methods">Traditional Methods:</h3>
<ul>
<li><p>❌ Manual creation using the AWS Console - error-prone and repetitive</p>
</li>
<li><p>❌ AWS CLI or SDKs like Python + Boto3 - requires programming knowledge</p>
</li>
<li><p>❌ CloudFormation or ARM Templates - tied to specific cloud providers</p>
</li>
</ul>
<hr />
<h2 id="heading-so-why-terraform">💡 So Why Terraform?</h2>
<p>Terraform gives us a <strong>universal language</strong> to define and manage infrastructure across <strong>multiple cloud providers</strong> - AWS, Azure, GCP, and more - using its own syntax called <strong>HCL (HashiCorp Configuration Language)</strong>.</p>
<h3 id="heading-key-benefits">🔥 Key Benefits:</h3>
<ul>
<li><p>💥 Multi-cloud support with one tool</p>
</li>
<li><p>🧾 Readable and declarative syntax</p>
</li>
<li><p>🚀 Reusable modules and configurations</p>
</li>
<li><p>📦 Massive community and ecosystem</p>
</li>
<li><p>⚙️ No deep programming knowledge required</p>
</li>
<li><p>🔁 Version-controlled infrastructure (just like Git)</p>
</li>
</ul>
<p>Instead of learning multiple tools like:</p>
<ul>
<li><p>AWS CloudFormation</p>
</li>
<li><p>Azure ARM Templates</p>
</li>
<li><p>OpenStack Heat Templates</p>
</li>
</ul>
<p>...just learn <strong>Terraform</strong>, and it works for all of them.</p>
<hr />
<h2 id="heading-installing-terraform">🛠️ Installing Terraform</h2>
<p>You can install Terraform in <strong>two ways</strong>:</p>
<h3 id="heading-method-1-local-installation">🔹 Method 1: Local Installation</h3>
<h4 id="heading-for-windows">For <strong>Windows</strong>:</h4>
<ul>
<li><p>Download the binary from terraform.io</p>
</li>
<li><p>Add it to your system <code>PATH</code></p>
</li>
<li><p>Use <strong>Git Bash</strong> or <strong>PowerShell</strong> (not CMD)</p>
</li>
</ul>
<h4 id="heading-for-macos">For <strong>macOS</strong>:</h4>
<pre><code class="lang-bash">brew tap hashicorp/tap
brew install hashicorp/tap/terraform
</code></pre>
<h4 id="heading-for-ubuntulinux">For <strong>Ubuntu/Linux</strong>:</h4>
<pre><code class="lang-bash">sudo apt-get update &amp;&amp; sudo apt-get install -y gnupg software-properties-common
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
<span class="hljs-built_in">echo</span> <span class="hljs-string">"deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com <span class="hljs-subst">$(lsb_release -cs)</span> main"</span> | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
sudo apt install terraform
</code></pre>
<hr />
<h3 id="heading-method-2-github-codespaces-recommended-for-beginners">🔹 Method 2: GitHub Codespaces (Recommended for Beginners)</h3>
<p>Don’t have admin access or using a restricted office laptop?</p>
<p>Use <strong>GitHub Codespaces</strong> - your browser becomes your Dev environment.</p>
<ul>
<li><p>✅ Free: 60 hours/month</p>
</li>
<li><p>🖥️ Environment: 2 CPUs, 4GB RAM</p>
</li>
<li><p>💻 Built-in Visual Studio Code</p>
</li>
<li><p>🌍 Access from any device with a browser</p>
</li>
</ul>
<h3 id="heading-to-set-it-up">To set it up:</h3>
<ol>
<li><p>Fork the Repo</p>
</li>
<li><p>Click <strong>Code &gt; Codespaces &gt; Create codespace</strong></p>
</li>
<li><p>Add Dev Container Configs for:</p>
<ul>
<li><p><code>Terraform</code></p>
</li>
<li><p><code>AWS CLI</code></p>
</li>
</ul>
</li>
<li><p>Rebuild the container - now you’re ready to use Terraform in-browser!</p>
</li>
</ol>
<hr />
<h2 id="heading-setting-up-aws-authentication">🔐 Setting Up AWS Authentication</h2>
<p>Once the AWS CLI is installed, run:</p>
<pre><code class="lang-bash">aws configure
</code></pre>
<p>You’ll be prompted to enter:</p>
<ul>
<li><p><strong>Access Key ID</strong></p>
</li>
<li><p><strong>Secret Access Key</strong></p>
</li>
<li><p><strong>Default region</strong> (e.g., <code>us-east-1</code>)</p>
</li>
<li><p><strong>Output format</strong> (<code>json</code>, <code>table</code>, or <code>text</code>)</p>
</li>
</ul>
<blockquote>
<p>🔒 Tip: Use <strong>IAM Users</strong> instead of root accounts for better security. You can generate access keys from the AWS IAM Console.</p>
<p>🔑 <strong>Important Note:</strong> This only allows <strong>your terminal (shell)</strong> to interact with AWS using the AWS CLI. It <strong>does not</strong> automatically grant access to Terraform.</p>
</blockquote>
<p>The AWS CLI saves credentials in this location:</p>
<pre><code class="lang-bash">~/.aws/credentials
</code></pre>
<hr />
<h3 id="heading-giving-terraform-access-to-aws">Giving Terraform Access to AWS</h3>
<p>Once AWS CLI is configured, <strong>Terraform can also use those same credentials</strong> - <strong>if</strong> the provider block is correctly written in your <code>.tf</code> file.</p>
<p>Here's the minimal provider configuration:</p>
<pre><code class="lang-bash">provider <span class="hljs-string">"aws"</span> {
  region = <span class="hljs-string">"us-east-1"</span>
}
</code></pre>
<hr />
<h2 id="heading-writing-your-first-terraform-script">📝 Writing Your First Terraform Script</h2>
<p>Let’s write a basic Terraform configuration to launch an <strong>EC2 instance</strong>.</p>
<h3 id="heading-step-1-create-a-file-called-maintf">Step 1: Create a file called <code>main.tf</code></h3>
<pre><code class="lang-bash">provider <span class="hljs-string">"aws"</span> {
  region = <span class="hljs-string">"us-east-1"</span>
}

resource <span class="hljs-string">"aws_instance"</span> <span class="hljs-string">"example"</span> {
  ami           = <span class="hljs-string">"ami-xxxxxxxxxxxxxxxxx"</span> <span class="hljs-comment"># Replace with valid AMI ID</span>
  instance_type = <span class="hljs-string">"t2.micro"</span>
  subnet_id     = <span class="hljs-string">"subnet-xxxxxxxxxxxxx"</span>  <span class="hljs-comment"># Replace with your Subnet ID</span>
  key_name      = <span class="hljs-string">"your-key-name"</span>         <span class="hljs-comment"># Replace with your key pair name</span>
}
</code></pre>
<p>💡 <strong>Where to find values:</strong></p>
<ul>
<li><p><strong>AMI ID</strong>: Launch an EC2 instance manually and copy the AMI ID</p>
</li>
<li><p><strong>Subnet ID</strong>: Use your default VPC subnet or create a new one</p>
</li>
<li><p><strong>Key Name</strong>: Use an existing EC2 key pair or create a new one from the AWS console</p>
</li>
</ul>
<hr />
<h2 id="heading-terraform-lifecycle-commands">🔄 Terraform Lifecycle Commands</h2>
<p>Follow these commands in order:</p>
<h3 id="heading-1-terraform-init">1️⃣ <code>terraform init</code></h3>
<p>Initializes the working directory and downloads provider plugins.</p>
<pre><code class="lang-bash">terraform init
</code></pre>
<h3 id="heading-2-terraform-plan">2️⃣ <code>terraform plan</code></h3>
<p>Shows what changes Terraform will make. Think of this as a <strong>dry run</strong>.</p>
<pre><code class="lang-bash">terraform plan
</code></pre>
<h3 id="heading-3-terraform-apply">3️⃣ <code>terraform apply</code></h3>
<p>Applies the configuration and <strong>creates real infrastructure</strong> on AWS.</p>
<pre><code class="lang-bash">terraform apply
</code></pre>
<p>Terraform will ask for confirmation - type <code>yes</code>.</p>
<h3 id="heading-4-terraform-destroy">4️⃣ <code>terraform destroy</code></h3>
<p>Destroys the infrastructure and avoids incurring AWS charges.</p>
<pre><code class="lang-bash">terraform destroy
</code></pre>
<h2 id="heading-what-is-the-terraform-state-file">📂 What is the Terraform State File?</h2>
<p>Terraform creates a file called:</p>
<pre><code class="lang-bash">terraform.tfstate
</code></pre>
<h3 id="heading-this-file">This file:</h3>
<ul>
<li><p>Records all the resources that Terraform created</p>
</li>
<li><p>Tracks the <strong>current state</strong> of your infrastructure</p>
</li>
<li><p>Is used internally to understand what changes need to be made</p>
</li>
</ul>
<p>🔐 <strong>Important:</strong><br />Manage this file securely - it may contain sensitive information like resource IDs and IPs.</p>
<p>In future guides, you’ll learn:</p>
<ul>
<li><p>How to use <strong>remote state storage</strong> (S3 + DynamoDB)</p>
</li>
<li><p>How to <strong>secure and lock state files</strong> in team environments</p>
</li>
<li><p>How state integrates with <strong>CI/CD pipelines</strong></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[🔀 Git Branching Strategies Explained]]></title><description><![CDATA[🚀 Introduction
When you're working on a software project - especially in a team - managing your code effectively is critical. Git and GitHub enable this through branching strategies, but as a beginner, you might be confused by terms like develop, fe...]]></description><link>https://blog.iresh.xyz/github-branching-strategy-explained-for-beginners</link><guid isPermaLink="true">https://blog.iresh.xyz/github-branching-strategy-explained-for-beginners</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Tue, 06 May 2025 06:38:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746517063863/f4cc2638-d55a-4cc4-88fb-4b38d32749ef.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">🚀 Introduction</h2>
<p>When you're working on a software project - especially in a team - managing your code effectively is critical. Git and GitHub enable this through branching strategies, but as a beginner, you might be confused by terms like <code>develop</code>, <code>feature</code>, or <code>hotfix</code>, or unsure which strategy fits your project best.</p>
<p>In this post, I’ll break down <strong>three popular Git branching strategies</strong> - <strong>Git Flow</strong>, <strong>Feature Branch Workflow</strong>, and <strong>Forking Workflow</strong> - explain how they work, and help you choose the right one.</p>
<hr />
<h2 id="heading-branching-strategies-overview">🌳 Branching Strategies Overview</h2>
<h3 id="heading-1-git-flow-workflow">1. <strong>Git Flow Workflow</strong></h3>
<p>A structured and full-featured strategy for managing larger projects with scheduled releases.</p>
<h4 id="heading-main-branches">🔑 Main Branches:</h4>
<ul>
<li><p><code>master</code> – Stable, production-ready code.</p>
</li>
<li><p><code>develop</code> – Integrates features; staging area before production.</p>
</li>
<li><p><code>feature/*</code> – Individual feature development branches.</p>
</li>
<li><p><code>release/*</code> – Pre-release staging and polishing.</p>
</li>
<li><p><code>hotfix/*</code> – Urgent fixes for production issues.</p>
</li>
</ul>
<h4 id="heading-typical-flow">🔁 Typical Flow:</h4>
<pre><code class="lang-bash">master &lt;—— hotfix
   ↑
release
   ↑
develop &lt;—— feature
</code></pre>
<h4 id="heading-example">🧪 Example:</h4>
<ol>
<li><p><code>git checkout -b develop master</code></p>
</li>
<li><p><code>git checkout -b feature/login develop</code></p>
</li>
<li><p>Merge feature into <code>develop</code> → create <code>release/*</code> → merge into <code>master</code> and tag → back-merge into <code>develop</code></p>
</li>
</ol>
<p>✅ Best for: Large teams, scheduled/versioned releases.<br />❌ Complex for fast-paced or CI/CD-driven environments.</p>
<hr />
<h3 id="heading-2-feature-branch-workflow">2. <strong>Feature Branch Workflow</strong></h3>
<p>This lightweight and popular strategy is often mistakenly called "GitHub Flow" - but it's officially known as <strong>Feature Branch Workflow</strong>. GitHub Flow is a variant of this, optimized for continuous delivery.</p>
<h4 id="heading-main-branch">🔑 Main Branch:</h4>
<ul>
<li><p><code>main</code> or <code>master</code> – Always production-ready</p>
</li>
<li><p><code>feature/*</code> – Short-lived branches for individual changes</p>
</li>
</ul>
<h4 id="heading-typical-flow-1">🔁 Typical Flow:</h4>
<pre><code class="lang-bash">main &lt;—— feature/* (via Pull Request)
</code></pre>
<h4 id="heading-example-1">🧪 Example:</h4>
<ol>
<li><p><code>git checkout -b feature/signup main</code></p>
</li>
<li><p>Commit and push changes</p>
</li>
<li><p>Open a PR, get it reviewed, and merge into <code>main</code></p>
</li>
</ol>
<p>✅ Best for: CI/CD, small to medium teams, rapid releases<br />❌ Lacks pre-production stages like testing or staging unless you set them up in your CI pipeline</p>
<hr />
<h3 id="heading-3-forking-workflow">3. <strong>Forking Workflow</strong></h3>
<p>Mostly used in open-source projects where contributors don't have direct write access to the main repository.</p>
<h4 id="heading-key-concept">🔑 Key Concept:</h4>
<ul>
<li><p>Contributors <strong>fork</strong> the main repository</p>
</li>
<li><p>Work is done in their <strong>personal clone</strong></p>
</li>
<li><p>Changes are submitted via <strong>Pull Request</strong> back to the original repo</p>
</li>
</ul>
<h4 id="heading-typical-flow-2">🔁 Typical Flow:</h4>
<pre><code class="lang-bash">origin/main &lt;—— Pull Request &lt;—— forked-repo/feature
</code></pre>
<h4 id="heading-example-2">🧪 Example:</h4>
<ol>
<li><p>Fork the repo on GitHub</p>
</li>
<li><p><code>git clone</code> your fork</p>
</li>
<li><p><code>git checkout -b fix/typo</code></p>
</li>
<li><p>Push and open a PR to the original repo</p>
</li>
</ol>
<p>✅ Best for: Open-source and external collaborations<br />❌ Not ideal for internal team projects due to overhead</p>
<hr />
<h2 id="heading-real-world-example-to-do-app">📘 Real-World Example: To-Do App</h2>
<p>Let’s walk through how each strategy could apply to a simple project like a To-Do App.</p>
<h3 id="heading-using-git-flow">🔸 Using Git Flow:</h3>
<ul>
<li><p>Start from <code>master</code>, create <code>develop</code></p>
</li>
<li><p>Each feature (e.g., "Dark Mode") gets a <code>feature/dark-mode</code> branch from <code>develop</code></p>
</li>
<li><p>Once ready, create <code>release/1.0.0</code> from <code>develop</code></p>
</li>
<li><p>Merge <code>release</code> into <code>master</code> and <code>develop</code>, tag the release</p>
</li>
<li><p>If a crash is found in production, create <code>hotfix/crash-fix</code> from <code>master</code></p>
</li>
</ul>
<h3 id="heading-using-feature-branch-workflow">🔹 Using Feature Branch Workflow:</h3>
<ul>
<li><p>Start from <code>main</code></p>
</li>
<li><p>Create a branch <code>feature/dark-mode</code> directly from <code>main</code></p>
</li>
<li><p>Work and open a PR</p>
</li>
<li><p>After testing, merge to <code>main</code> and deploy</p>
</li>
</ul>
<h3 id="heading-using-forking-workflow">🌐 Using Forking Workflow:</h3>
<ul>
<li><p>Contributor forks the main repo</p>
</li>
<li><p>Creates a feature branch in their fork (e.g., <code>feature/dark-mode</code>)</p>
</li>
<li><p>Pushes and opens a PR to the main repo’s <code>main</code> branch</p>
</li>
</ul>
<hr />
<h2 id="heading-summary-table">🧠 Summary Table</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Strategy</td><td>Best For</td><td>Main Branches</td><td>Pros</td><td>Cons</td></tr>
</thead>
<tbody>
<tr>
<td>Git Flow</td><td>Enterprise apps, versioned releases</td><td><code>master</code>, <code>develop</code>, <code>feature/*</code>, <code>release/*</code>, <code>hotfix/*</code></td><td>Structured, scalable</td><td>Complex setup</td></tr>
<tr>
<td>Feature Branch</td><td>Startups, CI/CD teams</td><td><code>main</code>, <code>feature/*</code></td><td>Simple, fast</td><td>No staging by default</td></tr>
<tr>
<td>Forking Workflow</td><td>Open-source projects</td><td>Forks, PRs to <code>main</code></td><td>Secure, external contributions</td><td>Slower workflow</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-text-based-diagrams">🔍 Text-Based Diagrams</h2>
<h3 id="heading-git-flow">Git Flow:</h3>
<pre><code class="lang-bash">*--------------------*-------------------&gt; master
         \             \           
          \             *------------&gt; hotfix/*
           \
            *-------------------------&gt; release/*
             \
              *--*--*--*--*-----------&gt; develop
                 \  \  \  \
                  \  \  \ *----------&gt; feature/*
                   \  \  *-----------&gt; feature/*
                    \  *-------------&gt; feature/*
</code></pre>
<h3 id="heading-feature-branch">Feature Branch:</h3>
<pre><code class="lang-bash">main
  |\
  | *--&gt; feature/login
  | *--&gt; feature/dark-mode
  | *--&gt; feature/tags
  --&gt; PR merge back to main
</code></pre>
<h3 id="heading-forking">Forking:</h3>
<pre><code class="lang-bash">original-repo/main
        ^
        |
  Pull Request
        |
  forked-repo/feature
</code></pre>
<hr />
<h2 id="heading-final-tips">✅ Final Tips</h2>
<ul>
<li><p>Choose a strategy that matches your team’s workflow and delivery model.</p>
</li>
<li><p>Always pull latest changes before creating new branches.</p>
</li>
<li><p>Use clear, consistent branch naming (<code>feature/login-page</code>, <code>hotfix/api-timeout</code>).</p>
</li>
<li><p>Keep commits focused and meaningful.</p>
</li>
<li><p>Use tags for versioning (<code>v1.0.0</code>, <code>v1.0.1</code>).</p>
</li>
</ul>
<p>With the right strategy, your team can work efficiently, reduce conflicts, and release with confidence.</p>
]]></content:encoded></item><item><title><![CDATA[Setting Up a Multi-Node Kubernetes Cluster Using Kubeadm on Ubuntu 24.04 LTS]]></title><description><![CDATA[Kubernetes is a powerful platform for managing containerized workloads, and Kubeadm is a tool for setting up a Kubernetes cluster easily. In this guide, we'll walk you through the process of setting up a multi-node Kubernetes cluster on Ubuntu 24.04 ...]]></description><link>https://blog.iresh.xyz/setting-up-a-multi-node-kubernetes-cluster-using-kubeadm-on-ubuntu-2404-lts</link><guid isPermaLink="true">https://blog.iresh.xyz/setting-up-a-multi-node-kubernetes-cluster-using-kubeadm-on-ubuntu-2404-lts</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Mon, 28 Apr 2025 19:45:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745870125133/c62b0cec-6e13-496d-bde3-9ae449737f8b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Kubernetes is a powerful platform for managing containerized workloads, and Kubeadm is a tool for setting up a Kubernetes cluster easily. In this guide, we'll walk you through the process of setting up a multi-node Kubernetes cluster on Ubuntu 24.04 LTS using Kubeadm. The setup is straightforward and includes all the necessary steps for beginners.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you begin, make sure you meet the following requirements:</p>
<ul>
<li><p>At least two Ubuntu 24.04 LTS servers with 2GB of RAM and 2 CPU cores.</p>
</li>
<li><p>Network connectivity between the servers.</p>
</li>
<li><p>Root (sudo) access to each server.</p>
</li>
</ul>
<h2 id="heading-step-1-update-the-system-and-install-dependencies">Step 1: Update the System and Install Dependencies</h2>
<p>Start by updating the system and installing the necessary dependencies on all nodes (both master and worker nodes).</p>
<pre><code class="lang-plaintext">sudo apt update &amp;&amp; sudo apt upgrade -y
sudo apt install apt-transport-https curl -y
</code></pre>
<h2 id="heading-step-2-install-and-configure-containerd">Step 2: Install and Configure Containerd</h2>
<p>Kubernetes uses containerd as the container runtime. Let's install and configure it:</p>
<pre><code class="lang-plaintext">sudo apt install containerd -y
</code></pre>
<p>Now configure containerd to use systemd as the cgroup driver:</p>
<pre><code class="lang-plaintext">sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
</code></pre>
<h2 id="heading-step-3-install-kubernetes-components">Step 3: Install Kubernetes Components</h2>
<p>Next, we'll install the Kubernetes components: <code>kubelet</code>, <code>kubeadm</code>, and <code>kubectl</code>. These are the essential tools for setting up and managing the Kubernetes cluster.</p>
<pre><code class="lang-plaintext">curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable --now kubelet
</code></pre>
<h2 id="heading-step-4-disable-swap">Step 4: Disable Swap</h2>
<p>Kubernetes requires that swap be disabled for proper node functioning. Disable it by running:</p>
<pre><code class="lang-plaintext">sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
</code></pre>
<h2 id="heading-step-5-load-necessary-kernel-modules">Step 5: Load Necessary Kernel Modules</h2>
<p>Kubernetes requires certain kernel modules for networking. Load these modules by running the following commands:</p>
<pre><code class="lang-plaintext">sudo modprobe overlay
sudo modprobe br_netfilter
</code></pre>
<h2 id="heading-step-6-set-required-sysctl-parameters">Step 6: Set Required Sysctl Parameters</h2>
<p>To ensure proper network communication, set the following sysctl parameters:</p>
<pre><code class="lang-plaintext">cat &lt;&lt;EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
</code></pre>
<p>Apply these sysctl settings:</p>
<pre><code class="lang-plaintext">sudo sysctl --system
</code></pre>
<h2 id="heading-step-7-initialize-the-kubernetes-cluster-on-the-master-node">Step 7: Initialize the Kubernetes Cluster (on the Master Node)</h2>
<p>Now that the nodes are configured, it's time to initialize the Kubernetes cluster. Run the following command only on the master node:</p>
<pre><code class="lang-plaintext">sudo kubeadm init --pod-network-cidr=10.244.0.0/16
</code></pre>
<p>This command will provide a <code>kubeadm join</code> command that you'll use later to join worker nodes to the cluster.</p>
<h2 id="heading-step-8-set-up-kubeconfig-for-the-user">Step 8: Set Up kubeconfig for the User</h2>
<p>To interact with the Kubernetes cluster using <code>kubectl</code>, set up the kubeconfig file for your user:</p>
<pre><code class="lang-plaintext">mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
</code></pre>
<h2 id="heading-step-9-install-a-network-plugin-flannel">Step 9: Install a Network Plugin (Flannel)</h2>
<p>Kubernetes requires a network plugin to enable communication between pods across different nodes. We will use Flannel for this purpose. Run the following command on the master node:</p>
<pre><code class="lang-plaintext">kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
</code></pre>
<h2 id="heading-step-10-verify-the-installation">Step 10: Verify the Installation</h2>
<p>To verify that your cluster is up and running, check the status of the nodes and pods:</p>
<pre><code class="lang-plaintext">kubectl get nodes
kubectl get pods --all-namespaces
</code></pre>
<h2 id="heading-step-11-join-worker-nodes-to-the-cluster">Step 11: Join Worker Nodes to the Cluster</h2>
<p>On the worker nodes, run the <code>kubeadm join</code> command provided by the <code>kubeadm init</code> output on the master node. It will look something like this:</p>
<pre><code class="lang-plaintext">sudo kubeadm join 172.31.19.36:6443 --token 922x9d.v0jn4c8he0s286js --discovery-token-ca-cert-hash sha256:abcd1234...
</code></pre>
<p>After running the <code>kubeadm join</code> command on the worker nodes, they will join the cluster.</p>
<h2 id="heading-step-12-verify-the-cluster">Step 12: Verify the Cluster</h2>
<p>On the master node, run the following command to ensure that all nodes have joined the cluster successfully:</p>
<pre><code class="lang-plaintext">kubectl get nodes
</code></pre>
<p>You should see the master and worker nodes listed as <code>Ready</code>.</p>
<hr />
<h3 id="heading-conclusion">Conclusion</h3>
<p>Congratulations! You have successfully set up a multi-node Kubernetes cluster using Kubeadm on Ubuntu 24.04 LTS. You can now start deploying your applications on this cluster. If you face any issues during the setup, check the logs or consult the Kubernetes documentation for more troubleshooting steps.</p>
<hr />
<h2 id="heading-understanding-kubernetes-system-pods-after-cluster-initialization">🔍 Understanding Kubernetes System Pods After Cluster Initialization</h2>
<p>After initializing your Kubernetes cluster with <code>kubeadm</code>, you can run the command:</p>
<pre><code class="lang-plaintext">kubectl get pods -n kube-system
</code></pre>
<p>This will list the core system components running in the <code>kube-system</code> namespace. Here's what each of them does:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Pod Name</strong></td><td><strong>Purpose</strong></td></tr>
</thead>
<tbody>
<tr>
<td><code>calico-kube-controllers</code></td><td>Controls the state of Calico network policies and routes. It ensures proper communication between nodes.</td></tr>
<tr>
<td><code>calico-node</code></td><td>Runs on every node and is responsible for setting up networking, routing, and enforcing network policies.</td></tr>
<tr>
<td><code>coredns</code></td><td>DNS server for service discovery in the cluster. It allows pods to resolve service names like <code>my-service.default.svc.cluster.local</code>.</td></tr>
<tr>
<td><code>etcd</code></td><td>A distributed key-value store used as the backing store for all cluster data. Critical for cluster state.</td></tr>
<tr>
<td><code>kube-apiserver</code></td><td>Exposes the Kubernetes API. It's the front-end and primary control plane component.</td></tr>
<tr>
<td><code>kube-controller-manager</code></td><td>Manages various controllers (e.g., replication, endpoint, namespace). It ensures the desired state of resources.</td></tr>
<tr>
<td><code>kube-proxy</code></td><td>Maintains network rules on nodes to allow communication to services. Handles routing traffic to appropriate pods.</td></tr>
<tr>
<td><code>kube-scheduler</code></td><td>Assigns newly created pods to nodes based on resource availability and scheduling rules.</td></tr>
</tbody>
</table>
</div>]]></content:encoded></item><item><title><![CDATA[How to Install KVM on Ubuntu: A Step-by-Step Beginner’s Guide]]></title><description><![CDATA[If you're diving into the world of virtualization on Linux, KVM (Kernel-based Virtual Machine) is one of the best technologies you can use. It’s powerful, free, built right into the Linux kernel, and acts like a Type 1 hypervisor — just like VMware E...]]></description><link>https://blog.iresh.xyz/how-to-install-kvm-on-ubuntu-a-step-by-step-beginners-guide</link><guid isPermaLink="true">https://blog.iresh.xyz/how-to-install-kvm-on-ubuntu-a-step-by-step-beginners-guide</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Mon, 28 Apr 2025 19:34:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745870099618/b4a0db62-1602-47d2-bc04-2547421c6134.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you're diving into the world of virtualization on Linux, <strong>KVM (Kernel-based Virtual Machine)</strong> is one of the best technologies you can use. It’s powerful, free, built right into the Linux kernel, and acts like a <strong>Type 1 hypervisor</strong> — just like VMware ESXi or Hyper-V.</p>
<p>In this guide, I’ll walk you through <strong>installing KVM on Ubuntu 24.04 (Noble Numbat)</strong>. Whether you're a complete beginner or need a quick refresher, follow along and you'll have a working KVM setup in no time! 🙌</p>
<hr />
<h2 id="heading-prerequisites">🛠️ Prerequisites</h2>
<p>Before you start:</p>
<ul>
<li><p>Ubuntu 24.04 installed on your system</p>
</li>
<li><p>Terminal access (Ctrl + Alt + T)</p>
</li>
<li><p>Root privileges (use <code>sudo</code>)</p>
</li>
</ul>
<hr />
<h2 id="heading-step-1-update-ubuntu">Step 1: Update Ubuntu 📦</h2>
<p>First, make sure your system packages are up to date.<br />Open the terminal and run:</p>
<pre><code class="lang-plaintext">sudo apt update
</code></pre>
<p>👉 This ensures you’re pulling the latest available packages.</p>
<hr />
<h2 id="heading-step-2-check-if-your-system-supports-virtualization">Step 2: Check if Your System Supports Virtualization ⚙️</h2>
<p><strong>1. Check CPU virtualization support:</strong></p>
<pre><code class="lang-plaintext">egrep -c '(vmx|svm)' /proc/cpuinfo
</code></pre>
<ul>
<li><p>If you get <strong>0</strong> ➔ your CPU doesn’t support virtualization (sorry 😞).</p>
</li>
<li><p>If you get <strong>1 or more</strong> ➔ you're good to go! ✅</p>
</li>
</ul>
<hr />
<p><strong>2. Check KVM support with</strong> <code>kvm-ok</code>:</p>
<p>Install <code>cpu-checker</code> if <code>kvm-ok</code> is missing:</p>
<pre><code class="lang-plaintext">sudo apt install cpu-checker
</code></pre>
<p>Then, check again:</p>
<pre><code class="lang-plaintext">sudo kvm-ok
</code></pre>
<p>You should see a message like:</p>
<blockquote>
<p>"KVM acceleration can be used"</p>
</blockquote>
<p>✅ If yes, move to the next step!</p>
<hr />
<h2 id="heading-step-3-install-kvm-and-required-packages">Step 3: Install KVM and Required Packages 📚</h2>
<p>Now install KVM along with the tools you’ll need:</p>
<pre><code class="lang-plaintext">sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils -y
</code></pre>
<p>This installs:</p>
<ul>
<li><p><strong>qemu-kvm</strong> ➔ main KVM package</p>
</li>
<li><p><strong>libvirt</strong> ➔ to manage VMs</p>
</li>
<li><p><strong>bridge-utils</strong> ➔ networking support</p>
</li>
</ul>
<hr />
<h2 id="heading-step-4-authorize-your-user-to-use-kvm">Step 4: Authorize Your User to Use KVM 👤</h2>
<p>By default, only members of the <code>libvirt</code> and <code>kvm</code> groups can manage VMs.<br />Add your user to both groups:</p>
<pre><code class="lang-plaintext">sudo adduser $USER libvirt
sudo adduser $USER kvm
</code></pre>
<p><strong>Tip:</strong></p>
<ul>
<li><p>Replace <code>$USER</code> with your username if needed.</p>
</li>
<li><p>You might need to <strong>log out and log back in</strong> for the changes to apply.</p>
</li>
</ul>
<hr />
<h2 id="heading-step-5-verify-your-installation">Step 5: Verify Your Installation 🔎</h2>
<p>Use the <code>virsh</code> tool to confirm that KVM and libvirt are working:</p>
<pre><code class="lang-plaintext">sudo virsh list --all
</code></pre>
<ul>
<li>If you get a (mostly empty) list without errors ➔ everything is working! ✅</li>
</ul>
<p>Also, check the <code>libvirtd</code> service:</p>
<pre><code class="lang-plaintext">sudo systemctl status libvirtd
</code></pre>
<p>If it’s not running, start it with:</p>
<pre><code class="lang-plaintext">sudo systemctl enable --now libvirtd
</code></pre>
<hr />
<h1 id="heading-create-your-first-virtual-machine-vm">🎯 Create Your First Virtual Machine (VM)</h1>
<p>There are two ways to create VMs: <strong>using a GUI</strong> or <strong>command line</strong>.</p>
<hr />
<h2 id="heading-method-1-using-virt-manager-gui">Method 1: Using Virt-Manager GUI 🖥️</h2>
<p>First, install Virt Manager:</p>
<pre><code class="lang-plaintext">sudo apt install virt-manager -y
</code></pre>
<p>Then start it:</p>
<pre><code class="lang-plaintext">sudo virt-manager
</code></pre>
<p>💡 <strong>Steps to create a VM:</strong></p>
<ol>
<li><p>Click the <strong>computer icon</strong> ➔ "Create a new VM".</p>
</li>
<li><p>Choose "<strong>Local install media (ISO image)</strong>".</p>
</li>
<li><p>Browse and select your ISO file (e.g., Ubuntu Server ISO).</p>
</li>
<li><p>Allocate <strong>CPU</strong> and <strong>Memory</strong>.</p>
</li>
<li><p>Create and allocate <strong>disk space</strong>.</p>
</li>
<li><p>Name your VM ➔ Finish.</p>
</li>
</ol>
<p>🚀 Your VM will boot up and you can install the OS normally!</p>
<hr />
<h2 id="heading-method-2-using-the-command-line">Method 2: Using the Command Line 🖥️💬</h2>
<p>Prefer the terminal? Use <code>virt-install</code>:</p>
<p>Example command:</p>
<pre><code class="lang-plaintext">sudo virt-install \
--name ubuntu24-vm \
--description "Ubuntu 24 VM" \
--ram 2048 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/ubuntu24-vm.qcow2,size=20 \
--cdrom /path/to/ubuntu-24.04-live-server-amd64.iso \
--graphics vnc
</code></pre>
<p>👉 Replace <code>/path/to/ubuntu-24.04-live-server-amd64.iso</code> with your actual ISO path.</p>
<p>This will:</p>
<ul>
<li><p>Create a 2GB RAM, 2 vCPU VM</p>
</li>
<li><p>Allocate a 20GB disk</p>
</li>
<li><p>Attach the Ubuntu ISO to install</p>
</li>
<li><p>Open the VM console via VNC (or view it through Virt Manager)</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[🚀 Why Overprovisioning Breaks Kubernetes Autoscaling]]></title><description><![CDATA[Autoscaling is one of the most powerful features in Kubernetes. It promises to help you respond to fluctuating demand without manual intervention - saving costs when traffic is low and scaling automatically when it's high.
But what happens when… it d...]]></description><link>https://blog.iresh.xyz/why-overprovisioning-breaks-kubernetes-autoscaling</link><guid isPermaLink="true">https://blog.iresh.xyz/why-overprovisioning-breaks-kubernetes-autoscaling</guid><category><![CDATA[autoscaling]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[keda]]></category><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Wed, 09 Apr 2025 07:02:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744182126228/539b8700-e505-4ff8-bfb5-5c7663af18b7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Autoscaling is one of the most powerful features in Kubernetes. It promises to help you respond to fluctuating demand without manual intervention - saving costs when traffic is low and scaling automatically when it's high.</p>
<p>But what happens when… <strong>it doesn't scale?</strong></p>
<p>Even when traffic increases and users experience degraded performance - the number of pods remains the same.</p>
<p>The culprit?</p>
<blockquote>
<p><strong>Overprovisioning.</strong></p>
</blockquote>
<hr />
<h2 id="heading-the-problem-no-scaling-despite-load">⚠️ The Problem: No Scaling Despite Load</h2>
<p>Imagine this: You’re running a microservice that handles frequent API calls. You run a load test and notice increasing latency and timeouts. But strangely enough, <strong>no new pods are being added by the Horizontal Pod Autoscaler (HPA)</strong>.</p>
<p>You check the metrics and see CPU usage hovering around 20%. Autoscaling is configured to trigger at 50%. So everything <em>looks fine</em>... right?</p>
<p>Not really.</p>
<p>Despite clear signs of stress, Kubernetes <strong>doesn’t scale</strong> - because <strong>the app is requesting way more resources than it actually needs.</strong></p>
<hr />
<h2 id="heading-root-cause-overprovisioning">🕵️‍♂️ Root Cause: Overprovisioning</h2>
<p>In many cases, developers and engineers allocate large CPU and memory limits "just to be safe." It’s a common habit - especially when there’s little visibility into how much an app truly needs.</p>
<p>For example:</p>
<blockquote>
<p>You give your service <code>1 CPU</code> and <code>1Gi</code> memory, but in reality, it only ever uses ~200m CPU and 300Mi memory.</p>
</blockquote>
<h3 id="heading-what-happens-next">What happens next?</h3>
<ul>
<li><p>Kubernetes thinks your pod is underutilized.</p>
</li>
<li><p>HPA sees usage at only 20% of the requested value - so it does <em>nothing</em>.</p>
</li>
<li><p>Meanwhile, the node is <strong>overcommitted</strong>, and other workloads may also get throttled.</p>
</li>
<li><p>End-users face slower response times… and nobody knows why.</p>
</li>
</ul>
<hr />
<h2 id="heading-real-world-example-anonymized">🔧 Real-World Example (Anonymized)</h2>
<p>A team was managing a stateless API service handling product metadata. It was configured with:</p>
<ul>
<li><p><code>1 core CPU request</code></p>
</li>
<li><p><code>1.5 cores CPU limit</code></p>
</li>
<li><p><code>1Gi+ memory</code></p>
</li>
</ul>
<p>During load testing, it showed 0% CPU usage in HPA metrics, despite experiencing throttling and performance degradation. Why?</p>
<p>Because:</p>
<ul>
<li><p>It was actually using around <strong>200m CPU</strong> per pod.</p>
</li>
<li><p>The high request value masked this under-utilization.</p>
</li>
<li><p>Kubernetes couldn’t allocate more resources, and HPA never scaled the workload.</p>
</li>
</ul>
<h3 id="heading-the-fix">✅ The Fix:</h3>
<ul>
<li><p>Right-sized the pod to use:</p>
<ul>
<li><p><code>256m</code> CPU request</p>
</li>
<li><p><code>512m</code> CPU limit</p>
</li>
<li><p>~<code>256Mi–768Mi</code> memory range</p>
</li>
</ul>
</li>
<li><p>HPA immediately started picking up the actual usage.</p>
</li>
<li><p><a target="_blank" href="https://blog.iresh.xyz/a-beginners-guide-to-kubernetes-event-driven-autoscaling-keda">KEDA</a> was added to scale based on <strong>requests per minute</strong>, not just CPU.</p>
</li>
</ul>
<p>💡 <strong>Result:</strong> The app handled load better, latency dropped, and resource cost dropped by nearly 60%.</p>
<hr />
<h2 id="heading-common-pitfalls-in-kubernetes-autoscaling">🔍 Common Pitfalls in Kubernetes Autoscaling</h2>
<h3 id="heading-overprovisioning-resources">❌ Overprovisioning Resources</h3>
<p>When request values are too high, autoscalers see artificially low usage and don’t act - even under pressure.</p>
<h3 id="heading-scaling-only-on-cpu">❌ Scaling Only on CPU</h3>
<p>CPU isn’t always the best indicator of load, especially for:</p>
<ul>
<li><p>I/O-bound workloads</p>
</li>
<li><p>Latency-sensitive apps</p>
</li>
<li><p>APIs with fast but frequent calls</p>
</li>
</ul>
<h3 id="heading-ignoring-node-throttling">❌ Ignoring Node Throttling</h3>
<p>Even if your pod isn't consuming much, an <strong>overcommitted node</strong> will throttle workloads to protect overall stability.</p>
<hr />
<h2 id="heading-best-practices-for-smart-autoscaling">✅ Best Practices for Smart Autoscaling</h2>
<h3 id="heading-1-right-size-your-workloads">1. <strong>Right-Size Your Workloads</strong></h3>
<p>Start small. Monitor your pods using:</p>
<pre><code class="lang-bash">kubectl top pods
</code></pre>
<p>Compare actual usage to requested values. If usage is consistently low, reduce the request and limit values.</p>
<hr />
<h3 id="heading-2-tune-hpa-carefully">2. <strong>Tune HPA Carefully</strong></h3>
<p>Use reasonable thresholds:</p>
<ul>
<li><p>Trigger at 50–60% CPU usage</p>
</li>
<li><p>Set minimum and maximum replica ranges based on traffic expectations</p>
</li>
</ul>
<hr />
<h3 id="heading-3-add-request-based-scaling-with-kedahttpsblogireshxyza-beginners-guide-to-kubernetes-event-driven-autoscaling-keda">3. <strong>Add Request-Based Scaling (with</strong> <a target="_blank" href="https://blog.iresh.xyz/a-beginners-guide-to-kubernetes-event-driven-autoscaling-keda"><strong>KEDA</strong></a><strong>)</strong></h3>
<p>HPA works well with CPU/RAM, but doesn’t understand traffic volume.</p>
<p>Use <a target="_blank" href="https://keda.sh">KEDA</a> to scale based on:</p>
<ul>
<li><p>Requests per second</p>
</li>
<li><p>Queue length</p>
</li>
<li><p>Custom Observability metrics</p>
</li>
</ul>
<hr />
<h3 id="heading-4-avoid-blind-copy-paste">4. <strong>Avoid Blind Copy-Paste</strong></h3>
<p>Don’t reuse resource configs from unrelated services. Each service behaves differently.</p>
<hr />
<h3 id="heading-5-watch-for-throttling">5. <strong>Watch for Throttling</strong></h3>
<p>If you see throttling in your observability tools, it’s time to revisit your requests and limits. Even if HPA isn’t scaling, <strong>Kubernetes might still be struggling to allocate what you asked for</strong>.</p>
<hr />
<h2 id="heading-faqs">❓ FAQs</h2>
<h3 id="heading-q-why-doesnt-hpa-scale-even-under-load">Q: Why doesn’t HPA scale even under load?</h3>
<p><strong>A:</strong> If the app is overprovisioned, CPU usage stays low <em>relative to the request</em>, so the autoscaler won’t trigger.</p>
<hr />
<h3 id="heading-q-how-do-i-know-what-cpumemory-to-request">Q: How do I know what CPU/memory to request?</h3>
<p><strong>A:</strong> Start with a conservative value (e.g., <code>200m CPU</code>, <code>256Mi memory</code>). Monitor usage under normal and peak traffic, and adjust accordingly.</p>
<hr />
<h3 id="heading-q-when-should-i-use-kedahttpsblogireshxyza-beginners-guide-to-kubernetes-event-driven-autoscaling-keda">Q: When should I use <a target="_blank" href="https://blog.iresh.xyz/a-beginners-guide-to-kubernetes-event-driven-autoscaling-keda">KEDA</a>?</h3>
<p><strong>A:</strong> When CPU isn’t a reliable scaling signal. For example, use <a target="_blank" href="https://blog.iresh.xyz/a-beginners-guide-to-kubernetes-event-driven-autoscaling-keda">KEDA</a> to scale on:</p>
<ul>
<li><p>HTTP request rate</p>
</li>
<li><p>Queue depth</p>
</li>
<li><p>Event counts</p>
</li>
<li><p>Custom metrics</p>
</li>
</ul>
<hr />
<h3 id="heading-q-can-overprovisioning-affect-other-apps">Q: Can overprovisioning affect other apps?</h3>
<p><strong>A:</strong> Yes. Especially in shared node pools, it can cause throttling across unrelated services and reduce overall node efficiency.</p>
<hr />
<h2 id="heading-final-takeaway">📌 Final Takeaway</h2>
<blockquote>
<p>🧠 <strong>Overprovisioning doesn’t protect your app - it hides the real load and breaks autoscaling.</strong></p>
</blockquote>
<p>Instead, embrace:</p>
<ul>
<li><p><strong>Right-sizing</strong></p>
</li>
<li><p><strong>Smart metric selection</strong></p>
</li>
<li><p><strong>Intentional scaling strategies</strong></p>
</li>
</ul>
<p>By tuning your workloads based on reality - not assumptions - you can achieve <strong>better performance, more reliable scaling, and major cost savings.</strong></p>
]]></content:encoded></item><item><title><![CDATA[A Beginner's Guide to Kubernetes Event-Driven Autoscaling (KEDA)]]></title><description><![CDATA[Introduction
Kubernetes has revolutionized the way we deploy and manage containerized applications. However, efficiently scaling workloads based on demand remains a challenge. While Kubernetes’ native Horizontal Pod Autoscaler (HPA) scales applicatio...]]></description><link>https://blog.iresh.xyz/a-beginners-guide-to-kubernetes-event-driven-autoscaling-keda</link><guid isPermaLink="true">https://blog.iresh.xyz/a-beginners-guide-to-kubernetes-event-driven-autoscaling-keda</guid><category><![CDATA[keda]]></category><category><![CDATA[scaling]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Thu, 03 Apr 2025 06:03:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743660110738/d3f5b6cb-8971-4378-b380-0080a6fd2dc5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Kubernetes has revolutionized the way we deploy and manage containerized applications. However, efficiently scaling workloads based on demand remains a challenge. While Kubernetes’ native Horizontal Pod Autoscaler (HPA) scales applications based on CPU and memory usage, it lacks support for external event-based triggers. This is where <strong>KEDA (Kubernetes Event-Driven Autoscaler)</strong> comes in.</p>
<p>KEDA extends Kubernetes' autoscaling capabilities by enabling <strong>event-driven scaling</strong> based on external sources like message queues, databases, cloud events, and custom metrics. This guide will help beginners understand KEDA and how to integrate it into their Kubernetes environments.</p>
<hr />
<h2 id="heading-what-is-keda">What is KEDA?</h2>
<p>KEDA is an open-source project under the Cloud Native Computing Foundation (CNCF) that provides event-driven autoscaling for Kubernetes workloads. It works alongside Kubernetes’ HPA, allowing workloads to scale based on <strong>real-time external events</strong> rather than just CPU and memory metrics.</p>
<h3 id="heading-key-features-of-keda">Key Features of KEDA:</h3>
<ul>
<li><p><strong>Event-Driven Scaling</strong>: Scales applications based on external event sources such as Kafka, RabbitMQ, AWS SQS, PostgreSQL, and Azure Event Hubs.</p>
</li>
<li><p><strong>Efficient Resource Utilization</strong>: Pods remain at zero when idle, reducing unnecessary resource consumption.</p>
</li>
<li><p><strong>Seamless HPA Integration</strong>: Works with Kubernetes' native HPA to ensure efficient autoscaling.</p>
</li>
<li><p><strong>Flexible Scaling Policies</strong>: Define how and when your applications should scale using custom triggers.</p>
</li>
</ul>
<hr />
<h2 id="heading-why-use-keda">Why Use KEDA?</h2>
<p>KEDA is particularly useful in scenarios where workload demand fluctuates based on external events rather than system resource usage. Here are a few common use cases:</p>
<ol>
<li><p><strong>Queue-Based Processing</strong>: Scale applications dynamically based on the number of messages in a queue (e.g., RabbitMQ, Azure Queue Storage, AWS SQS).</p>
</li>
<li><p><strong>Database-Driven Scaling</strong>: Scale services when new records are inserted into a database.</p>
</li>
<li><p><strong>IoT and Streaming Applications</strong>: Automatically scale applications based on incoming IoT data or Kafka events.</p>
</li>
<li><p><strong>Event-Driven Serverless Applications</strong>: Run workloads only when events occur, reducing infrastructure costs.</p>
</li>
</ol>
<h3 id="heading-advantages-of-keda-over-cpumemory-based-hpa-and-cluster-autoscaler">Advantages of KEDA Over CPU/Memory-Based HPA and Cluster Autoscaler</h3>
<p>KEDA provides several advantages compared to traditional CPU and memory-based Horizontal Pod Autoscaler (HPA) and Cluster Autoscaler (CA):</p>
<ol>
<li><p><strong>Event-Driven Scaling Instead of Just CPU/Memory</strong></p>
<ul>
<li><p>HPA only scales based on <strong>CPU and memory usage</strong> (with limited support for custom metrics).</p>
</li>
<li><p>KEDA allows scaling based on <strong>external events</strong> such as queue length in Kafka, database row count, HTTP request rate, or even cloud events.</p>
</li>
</ul>
</li>
<li><p><strong>Fine-Grained Control Over Scaling</strong></p>
<ul>
<li><p>HPA and CA react only when resource utilization crosses thresholds.</p>
</li>
<li><p>KEDA allows <strong>custom triggers</strong> (e.g., "Scale up when Kafka queue has more than 100 messages").</p>
</li>
</ul>
</li>
<li><p><strong>Cost Efficiency</strong></p>
<ul>
<li><p>With HPA, pods remain active based on CPU/memory, which may lead to unnecessary costs.</p>
</li>
<li><p>KEDA ensures <strong>pods run only when needed</strong>, reducing costs by automatically scaling down to zero when there are no events.</p>
</li>
</ul>
</li>
<li><p><strong>Faster Response to Workload Spikes</strong></p>
<ul>
<li><p>HPA and CA rely on metric scraping, which can delay autoscaling responses.</p>
</li>
<li><p>KEDA reacts to <strong>real-time events</strong>, ensuring faster pod provisioning and scaling.</p>
</li>
</ul>
</li>
<li><p><strong>Works Alongside HPA and CA</strong></p>
<ul>
<li><p>You can still use <strong>HPA for CPU/memory-based autoscaling</strong> alongside KEDA for event-driven scaling.</p>
</li>
<li><p><strong>Cluster Autoscaler (CA)</strong> is still needed to scale up nodes when pods need more capacity.</p>
</li>
</ul>
</li>
<li><p><strong>Ideal for Asynchronous and Batch Workloads</strong></p>
<ul>
<li><p>If your application processes messages from a queue (e.g., <strong>RabbitMQ, Kafka, Azure Event Hub</strong>), KEDA is a perfect fit.</p>
</li>
<li><p>For <strong>serverless applications</strong>, it provides event-driven scaling without overprovisioning resources.</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-installing-keda">Installing KEDA</h2>
<p>KEDA can be installed using Helm, which simplifies the deployment process.</p>
<h3 id="heading-step-1-add-the-keda-helm-repository">Step 1: Add the KEDA Helm Repository</h3>
<pre><code class="lang-sh">helm repo add kedacore https://kedacore.github.io/charts
helm repo update
</code></pre>
<h3 id="heading-step-2-install-keda">Step 2: Install KEDA</h3>
<pre><code class="lang-sh">helm install keda kedacore/keda --namespace keda --create-namespace
</code></pre>
<p>To verify the installation, check if the KEDA pods are running:</p>
<pre><code class="lang-sh">kubectl get pods -n keda
</code></pre>
<hr />
<h2 id="heading-configuring-keda-for-autoscaling">Configuring KEDA for Autoscaling</h2>
<h3 id="heading-step-1-define-a-triggerauthentication">Step 1: Define a <strong>TriggerAuthentication</strong></h3>
<p>If your external source requires authentication, you need to define a <code>TriggerAuthentication</code> resource.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">keda.sh/v1alpha1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">TriggerAuthentication</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">my-trigger-auth</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">secretTargetRef:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">parameter:</span> <span class="hljs-string">connectionString</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">my-secret</span>
      <span class="hljs-attr">key:</span> <span class="hljs-string">connectionString</span>
</code></pre>
<h3 id="heading-step-2-create-a-scaleobject">Step 2: Create a <strong>ScaleObject</strong></h3>
<p>A <code>ScaleObject</code> defines the scaling behavior for your workload.</p>
<p>Example: Scaling a Deployment based on a RabbitMQ queue length</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">keda.sh/v1alpha1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ScaleObject</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">rabbitmq-scaler</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">scaleTargetRef:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">my-app</span>
  <span class="hljs-attr">minReplicaCount:</span> <span class="hljs-number">1</span>
  <span class="hljs-attr">maxReplicaCount:</span> <span class="hljs-number">10</span>
  <span class="hljs-attr">triggers:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">type:</span> <span class="hljs-string">rabbitmq</span>
      <span class="hljs-attr">metadata:</span>
        <span class="hljs-attr">queueName:</span> <span class="hljs-string">my-queue</span>
        <span class="hljs-attr">mode:</span> <span class="hljs-string">QueueLength</span>
        <span class="hljs-attr">value:</span> <span class="hljs-string">"5"</span>
      <span class="hljs-attr">authenticationRef:</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">my-trigger-auth</span>
</code></pre>
<p>This configuration scales the <code>my-app</code> deployment based on the number of messages in the RabbitMQ queue.</p>
<hr />
<h2 id="heading-monitoring-keda">Monitoring KEDA</h2>
<p>To check the status of KEDA’s scaling operations:</p>
<pre><code class="lang-sh">kubectl get scaledobjects
kubectl get hpa
</code></pre>
<p>To view logs:</p>
<pre><code class="lang-sh">kubectl logs -f deployment/keda-operator -n keda
</code></pre>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>KEDA brings <strong>event-driven scaling</strong> to Kubernetes, making it ideal for workloads that depend on external events. By integrating with various event sources, it ensures that applications scale efficiently and cost-effectively. Whether you’re managing <strong>queue-based jobs</strong>, <strong>database-triggered workloads</strong>, or <strong>streaming applications</strong>, KEDA provides a powerful and flexible solution for scaling in response to real-world demands.</p>
<p>Ready to get started? Install KEDA in your cluster and experiment with different event sources to see how it can optimize your application scaling!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding the Scrum Process: A Beginner's Guide]]></title><description><![CDATA[Scrum is an Agile framework used to develop and deliver products iteratively and incrementally. It helps teams work collaboratively and respond to change effectively. This guide provides an overview of the Scrum process and its key components.

1. Sc...]]></description><link>https://blog.iresh.xyz/understanding-the-scrum-process-a-beginners-guide</link><guid isPermaLink="true">https://blog.iresh.xyz/understanding-the-scrum-process-a-beginners-guide</guid><category><![CDATA[Agile Best Practices]]></category><category><![CDATA[Scrum]]></category><category><![CDATA[project management]]></category><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Tue, 01 Apr 2025 16:47:35 GMT</pubDate><content:encoded><![CDATA[<p>Scrum is an Agile framework used to develop and deliver products iteratively and incrementally. It helps teams work collaboratively and respond to change effectively. This guide provides an overview of the Scrum process and its key components.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743525919192/1e075666-87e6-4cf3-9d99-3c411e00d1ea.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-1-scrum-framework-overview">1. Scrum Framework Overview</h2>
<p>Scrum follows an iterative approach, breaking down work into fixed time periods called <strong>Sprints</strong>. Each Sprint results in a potentially shippable product increment. The process involves specific roles, events, and artifacts.</p>
<h3 id="heading-key-roles-in-scrum">Key Roles in Scrum:</h3>
<ul>
<li><p><strong>Product Owner</strong>: Defines product goals, prioritizes backlog items, and ensures value delivery.</p>
</li>
<li><p><strong>Scrum Master</strong>: Facilitates Scrum processes, removes impediments, and ensures adherence to Agile principles.</p>
</li>
<li><p><strong>Development Team</strong>: Cross-functional team responsible for delivering increments.</p>
</li>
</ul>
<hr />
<h2 id="heading-2-scrum-process-flow">2. Scrum Process Flow</h2>
<h3 id="heading-21-product-backlog">2.1 Product Backlog</h3>
<p>The <strong>Product Backlog</strong> is a prioritized list of features, improvements, and fixes required for the product. The Product Owner maintains and refines this backlog continuously.</p>
<h3 id="heading-22-backlog-refinement-backlog-grooming">2.2 Backlog Refinement (Backlog Grooming)</h3>
<p>Backlog Refinement (also known as Backlog Grooming) is an ongoing activity where the team discusses and clarifies backlog items, breaks them into smaller tasks, and estimates their effort.</p>
<h3 id="heading-23-sprint-planning">2.3 Sprint Planning</h3>
<p>Sprint Planning is the meeting where the team selects backlog items for the upcoming Sprint. The key outputs of Sprint Planning include:</p>
<ul>
<li><p><strong>Sprint Goal</strong>: Defines the purpose of the Sprint.</p>
</li>
<li><p><strong>Sprint Backlog</strong>: A subset of Product Backlog items selected for the Sprint.</p>
</li>
<li><p><strong>Task Breakdown</strong>: Identifying the necessary tasks to complete selected items.</p>
</li>
</ul>
<h3 id="heading-24-sprint-execution">2.4 Sprint Execution</h3>
<p>The <strong>Sprint</strong> is a time-boxed iteration (typically 1-4 weeks) where the team works on Sprint Backlog items. The team holds <strong>Daily Standup (Daily Scrum) Meetings</strong> to sync progress and discuss roadblocks.</p>
<h3 id="heading-25-increment">2.5 Increment</h3>
<p>By the end of the Sprint, the team delivers a <strong>Potentially Shippable Product Increment</strong> that meets the Definition of Done (DoD).</p>
<h3 id="heading-26-sprint-review">2.6 Sprint Review</h3>
<p>The <strong>Sprint Review</strong> is held at the end of the Sprint, where the team demonstrates the completed work to stakeholders and gathers feedback.</p>
<h3 id="heading-27-sprint-retrospective">2.7 Sprint Retrospective</h3>
<p>The <strong>Sprint Retrospective</strong> follows the Sprint Review and is aimed at process improvement. The team discusses what went well, what didn’t, and how they can improve future Sprints.</p>
<hr />
<h2 id="heading-3-summary-of-scrum-process-steps">3. Summary of Scrum Process Steps</h2>
<ol>
<li><p><strong>Product Backlog Creation</strong>: Product Owner maintains and prioritizes backlog items.</p>
</li>
<li><p><strong>Backlog Refinement</strong>: Team refines and estimates backlog items.</p>
</li>
<li><p><strong>Sprint Planning</strong>: Team selects work for the Sprint and sets a goal.</p>
</li>
<li><p><strong>Sprint Execution</strong>: Development occurs, guided by Daily Standups.</p>
</li>
<li><p><strong>Increment Creation</strong>: A potentially shippable product increment is produced.</p>
</li>
<li><p><strong>Sprint Review</strong>: Team showcases work and receives feedback.</p>
</li>
<li><p><strong>Sprint Retrospective</strong>: The team reflects and improves the process.</p>
</li>
<li><p><strong>Repeat</strong>: The process continues in cycles until the product is completed.</p>
</li>
</ol>
<p>Scrum ensures adaptability, continuous improvement, and consistent product delivery. By following these steps, teams can efficiently manage their work and deliver high-value products in an Agile environment.</p>
]]></content:encoded></item><item><title><![CDATA[Terraform Access for Azure]]></title><description><![CDATA[A cheat sheet for configuring authentication and access control in Azure for Terraform users.
1️⃣ Azure Authentication Methods
Before configuring Terraform, understand the authentication options in Azure:
🔹 Managed Identity
✅ Best For:

Azure resour...]]></description><link>https://blog.iresh.xyz/terraform-access-for-azure</link><guid isPermaLink="true">https://blog.iresh.xyz/terraform-access-for-azure</guid><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Tue, 01 Apr 2025 16:41:54 GMT</pubDate><content:encoded><![CDATA[<p><em>A cheat sheet for configuring authentication and access control in Azure for Terraform users.</em></p>
<h2 id="heading-1-azure-authentication-methods"><strong>1️⃣ Azure Authentication Methods</strong></h2>
<p>Before configuring Terraform, understand the authentication options in Azure:</p>
<h3 id="heading-managed-identity"><strong>🔹 Managed Identity</strong></h3>
<p>✅ <strong>Best For:</strong></p>
<ul>
<li><p>Azure resources (VMs, Functions, AKS, etc.) needing access to other Azure services.</p>
</li>
<li><p>Secretless authentication within Azure.</p>
</li>
</ul>
<p>✅ <strong>Types:</strong></p>
<ul>
<li><p><strong>System-assigned</strong> → Tied to a single resource.</p>
</li>
<li><p><strong>User-assigned</strong> → Reusable across multiple resources.</p>
</li>
</ul>
<hr />
<h3 id="heading-service-principal"><strong>🔹 Service Principal</strong></h3>
<p>✅ <strong>Best For:</strong></p>
<ul>
<li><p>Automation tools like Terraform, CI/CD (GitHub Actions, Azure DevOps).</p>
</li>
<li><p>Programmatic access to Azure resources.</p>
</li>
</ul>
<p>✅ <strong>Authentication Methods:</strong></p>
<ul>
<li><p><strong>Client Secret (Password-based) 🔑</strong> → Easy but less secure.</p>
</li>
<li><p><strong>Certificate-based</strong> → More secure than secrets.</p>
</li>
<li><p><strong>Federated Identity (OIDC) 🎭</strong> → No secret required (best for GitHub Actions &amp; Kubernetes).</p>
</li>
</ul>
<hr />
<h2 id="heading-2-prerequisites"><strong>2️⃣ Prerequisites</strong></h2>
<p>Before proceeding, ensure you have:<br />✅ An <strong>Azure Subscription</strong><br />✅ <strong>Azure CLI</strong> installed (<code>az version</code> to check)<br />✅ <strong>Terraform</strong> installed (<code>terraform version</code> to check`)</p>
<hr />
<h2 id="heading-3-authenticate-with-azure-cli"><strong>3️⃣ Authenticate with Azure CLI</strong></h2>
<p>Run the following command to log in to Azure:</p>
<pre><code class="lang-plaintext">az login
</code></pre>
<p>If you're using a cloud shell, authentication happens automatically.</p>
<hr />
<h2 id="heading-4-create-a-service-principal-for-terraform"><strong>4️⃣ Create a Service Principal for Terraform</strong></h2>
<p>To enable Terraform to authenticate securely, create a Service Principal:</p>
<pre><code class="lang-plaintext">az ad sp create-for-rbac --name "terraform-sp" --role="Contributor" --scopes="/subscriptions/YOUR_SUBSCRIPTION_ID"
</code></pre>
<p>This returns JSON with important credentials:</p>
<pre><code class="lang-plaintext">{
  "appId": "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
  "displayName": "terraform-sp",
  "password": "xxxxxxxxxxxx",
  "tenant": "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
}
</code></pre>
<p>Save these values securely.</p>
<hr />
<h2 id="heading-5-configure-terraform-provider-with-service-principal"><strong>5️⃣ Configure Terraform Provider with Service Principal</strong></h2>
<p>Update your <code>provider</code> block in Terraform to use the service principal credentials:</p>
<pre><code class="lang-plaintext">provider "azurerm" {
  features {}
  subscription_id = "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
  tenant_id       = "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
  client_id       = "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
  client_secret   = "xxxxxxxxxxxx"
}
</code></pre>
<p>This ensures Terraform authenticates using the service principal directly.</p>
<hr />
<h2 id="heading-6-verify-access-with-terraform"><strong>6️⃣ Verify Access with Terraform</strong></h2>
<p>To verify if the authentication is properly set up, run:</p>
<pre><code class="lang-plaintext">terraform plan
</code></pre>
<p>If authentication is configured correctly, Terraform will display the planned actions for your infrastructure. If there are issues with authentication, Terraform will return an error message.</p>
<hr />
<h2 id="heading-7-next-steps"><strong>7️⃣ Next Steps</strong></h2>
<ul>
<li><p><strong>Use this authentication</strong> to deploy Azure resources with Terraform.</p>
</li>
<li><p><strong>Secure your credentials</strong> using an Azure Key Vault instead of storing them in Terraform files.</p>
</li>
<li><p><strong>Continue with infrastructure setup</strong> (next blog will cover creating an Azure resource).</p>
</li>
</ul>
<hr />
<p>This keeps it <strong>short, structured, and easy to follow</strong>. 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Service Principal vs. Managed Identity in Azure: A Quick Guide]]></title><description><![CDATA[When working with Azure, managing authentication and access to resources securely is crucial. Two common approaches for enabling applications and services to authenticate without using user credentials are Service Principals and Managed Identities. L...]]></description><link>https://blog.iresh.xyz/service-principal-vs-managed-identity-in-azure-a-quick-guide</link><guid isPermaLink="true">https://blog.iresh.xyz/service-principal-vs-managed-identity-in-azure-a-quick-guide</guid><category><![CDATA[Azure]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Security]]></category><category><![CDATA[IAM]]></category><dc:creator><![CDATA[Iresh Ekanayaka]]></dc:creator><pubDate>Thu, 27 Mar 2025 04:26:37 GMT</pubDate><content:encoded><![CDATA[<p>When working with Azure, managing authentication and access to resources securely is crucial. Two common approaches for enabling applications and services to authenticate without using user credentials are <strong>Service Principals</strong> and <strong>Managed Identities</strong>. Let’s break down their differences and use cases.</p>
<h2 id="heading-what-is-a-service-principal">🔹 What is a Service Principal?</h2>
<p>A <strong>Service Principal</strong> is an identity created in <strong>Azure Active Directory (Azure AD)</strong> to authenticate applications or automation processes. It enables fine-grained access control by assigning specific roles and permissions to a non-human identity.</p>
<h3 id="heading-how-to-create-a-service-principal-cli-method">How to Create a Service Principal (CLI Method):</h3>
<pre><code class="lang-plaintext">az ad sp create-for-rbac --name "my-app" --role "Contributor" --scopes "/subscriptions/{subscription-id}"
</code></pre>
<p>After running the above command, you will receive output containing essential credentials:</p>
<pre><code class="lang-plaintext">{
  "appId": "&lt;client_id&gt;",
  "password": "&lt;client_secret&gt;",
  "tenant": "&lt;tenant_id&gt;"
}
</code></pre>
<ul>
<li><p><strong>appId</strong> → <code>client_id</code></p>
</li>
<li><p><strong>password</strong> → <code>client_secret</code></p>
</li>
<li><p><strong>tenant</strong> → <code>tenant_id</code></p>
</li>
</ul>
<h3 id="heading-how-to-create-a-service-principal-portal-method">How to Create a Service Principal (Portal Method):</h3>
<ol>
<li><p>Navigate to <strong>Azure Portal</strong> → <strong>Azure Active Directory</strong>.</p>
</li>
<li><p>Select <strong>App registrations</strong> → <strong>New registration</strong>.</p>
</li>
<li><p>Provide a name, select the supported account types, and register the application.</p>
</li>
<li><p>Go to <strong>Certificates &amp; secrets</strong> to generate a client secret.</p>
</li>
<li><p>Assign necessary <strong>RBAC roles</strong> under <strong>Azure subscriptions</strong>.</p>
</li>
</ol>
<h3 id="heading-key-points">Key Points:</h3>
<p>✅ Requires manual management of secrets or certificates.<br />✅ Can be used for automation, scripts, or CI/CD pipelines.<br />✅ Supports role-based access control (RBAC).<br />✅ Needs explicit lifecycle management (creation, rotation, deletion).</p>
<h2 id="heading-what-is-a-managed-identity">🔹 What is a Managed Identity?</h2>
<p>A <strong>Managed Identity</strong> is an Azure feature that eliminates the need for managing credentials. Azure automatically handles authentication when resources (like Virtual Machines, Functions, and App Services) need access to other Azure services.</p>
<h3 id="heading-types-of-managed-identities">Types of Managed Identities:</h3>
<ol>
<li><p><strong>System-assigned</strong> – Tied to a single Azure resource and deleted when the resource is deleted.</p>
</li>
<li><p><strong>User-assigned</strong> – Created independently and can be assigned to multiple resources.</p>
</li>
</ol>
<h3 id="heading-how-to-enable-a-system-assigned-managed-identity-cli-method">How to Enable a System-Assigned Managed Identity (CLI Method):</h3>
<pre><code class="lang-plaintext">az vm identity assign --resource-group myResourceGroup --name myVM
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743078952922/e1b9bcae-0ac2-4112-b5a5-bd261929cf33.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-how-to-enable-a-managed-identity-portal-method">How to Enable a Managed Identity (Portal Method):</h3>
<ol>
<li><p>Navigate to <strong>Azure Portal</strong> → <strong>Your Resource (VM, App Service, etc.)</strong>.</p>
</li>
<li><p>Go to <strong>Identity</strong> under the settings.</p>
</li>
<li><p>Enable <strong>System-assigned</strong> or <strong>User-assigned</strong> identity.</p>
</li>
<li><p>Assign necessary <strong>RBAC roles</strong> under <strong>Azure subscriptions</strong>.</p>
</li>
</ol>
<h3 id="heading-key-points-1">Key Points:</h3>
<p>✅ No need to manage credentials manually.<br />✅ Seamless integration with Azure services.<br />✅ Automatically rotates credentials for security.<br />✅ System-assigned identities are tied to a specific resource, while user-assigned identities can be shared.</p>
<h2 id="heading-when-to-use-which">🔹 When to Use Which?</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Use Case</td><td>Service Principal</td><td>Managed Identity</td></tr>
</thead>
<tbody>
<tr>
<td>CI/CD Pipelines</td><td>✅</td><td>❌</td></tr>
<tr>
<td>Cross-Cloud Authentication</td><td>✅</td><td>❌</td></tr>
<tr>
<td>VM to Azure Storage Authentication</td><td>❌</td><td>✅</td></tr>
<tr>
<td>Long-Term Secrets Management</td><td>✅</td><td>❌</td></tr>
<tr>
<td>Automatic Credential Rotation</td><td>❌</td><td>✅</td></tr>
</tbody>
</table>
</div><h2 id="heading-final-thoughts">🔹 Final Thoughts</h2>
<p>Both Service Principals and Managed Identities serve specific purposes. If you need a reusable identity for automation, <strong>Service Principals</strong> are the way to go. If you want a secure and hassle-free authentication method for Azure resources, <strong>Managed Identities</strong> are the best choice.</p>
<p>Which one do you use the most? Let me know in the comments! 🚀</p>
<hr />
]]></content:encoded></item></channel></rss>